From 1c1188ca05e7ce7937b06123579459188c17fb18 Mon Sep 17 00:00:00 2001 From: Tal Atlas Date: Fri, 28 Jan 2011 21:16:08 -0500 Subject: [PATCH 1/2] basic functionality working --- lib/url.rb | 3 +- lib/url/classer.rb | 77 ++++++++++++++++++++++++++++++++++++++++++++ spec/classer_spec.rb | 50 ++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 lib/url/classer.rb create mode 100644 spec/classer_spec.rb diff --git a/lib/url.rb b/lib/url.rb index dc9a428..a36402c 100644 --- a/lib/url.rb +++ b/lib/url.rb @@ -6,6 +6,7 @@ files = Dir.glob(File.join(File.dirname(__FILE__),'url','*.rb')) +files.delete_if {|f| f =~ /url\/(classer)\.rb/} files.each { |f| require f } # Main class for managing urls @@ -157,7 +158,7 @@ def delete(*args) end def inspect - "#" + "#<#{self.class} #{to_s}>" end def dup diff --git a/lib/url/classer.rb b/lib/url/classer.rb new file mode 100644 index 0000000..65efb33 --- /dev/null +++ b/lib/url/classer.rb @@ -0,0 +1,77 @@ +module URL::Classer + module ClassMethods + def allowed_params + @allowed_params ||= [] + end + private + def allow_changed *args + def_delegators :@url, :subdomains if args.include?(:subdomain) + def_delegators :@url, :subdomain if args.include?(:subdomains) + def_delegators :@url, :[], :[]= if args.include?(:params) + def_delegators :@url, *args + end + + def allow_params *args + args.each do |arg| + arg = arg.to_sym + self.allowed_params << arg + define_method arg do + @url.params[arg] + end + + define_method "#{arg}=" do |val| + @url.params[arg] = val + end + end + end + + end + + module InstanceMethods + def initialize(opts={}) + @url = self.class.const_get(:URL).dup + + opts.delete_if do |k,v| + !self.class.allowed_params.include?(k.to_sym) + end + + @url.params.merge!(opts) + end + + def to_s + @url.to_s + end + + def dup + n_url = @url.dup + n = super + n.instance_variable_set(:@url, n_url) + n + end + + end + + def self.included(receiver) + receiver.extend Forwardable + receiver.send :def_delegators, :@url, :get, :post, :delete, :inspect + + receiver.extend ClassMethods + receiver.send :include, InstanceMethods + end +end + +def URL url + klass = Class.new + + if url.is_a?(URL) + url = url.dup + else + url = URL.new(url) + end + + klass.const_set(:URL, url) + + klass.send(:include, URL::Classer) + + klass +end diff --git a/spec/classer_spec.rb b/spec/classer_spec.rb new file mode 100644 index 0000000..7e7b5e0 --- /dev/null +++ b/spec/classer_spec.rb @@ -0,0 +1,50 @@ +require File.expand_path(File.dirname(__FILE__) + '/spec_helper') +require 'url/classer' + +describe "URL()" do + + before(:all) do + class FacebookURL < URL('http://www.facebook.com') + allow_changed :subdomain + allow_params :foo + end + end + + it "should create a class" do + url = 'http://www.facebook.com' + u = URL.new(url) + URL(u).should be_a(Class) + + URL.should_receive(:new,url).once + URL(url).should be_a(Class) + end + + context '.new' do + subject {FacebookURL.new} + + it "shoud work like whatever" do + subject.subdomain << 'us' + subject.to_s.should =~ /^http:\/\/www\.us\.facebook.com\/?$/ + + u = FacebookURL.new + u.to_s.should =~ /^http:\/\/www\.facebook.com\/?$/ + end + + it "should dup" do + subject.subdomain << 'us' + d = subject.dup + d.subdomain.should == ['www','us'] + + d.subdomain << '1' + d.subdomain.should == ['www','us','1'] + subject.subdomain.should == ['www','us'] + end + + it "should allow params" do + subject.foo = 1 + subject.foo.should == 1 + subject.to_s.should =~ /foo=1/ + end + end + +end From 588d55cdf57f4fcb8ea7f96a5dca2faf2686c800 Mon Sep 17 00:00:00 2001 From: Tal Atlas Date: Mon, 31 Jan 2011 12:04:52 -0500 Subject: [PATCH 2/2] advanced functionality and some docs --- README.rdoc | 15 +++++++++++++ lib/url/classer.rb | 50 +++++++++++++++++++++++++++++++++++--------- spec/classer_spec.rb | 32 +++++++++++++++++++++------- 3 files changed, 79 insertions(+), 18 deletions(-) diff --git a/README.rdoc b/README.rdoc index 59ac915..9e908c2 100644 --- a/README.rdoc +++ b/README.rdoc @@ -52,6 +52,21 @@ You can make GET, POST, or DELETE requests without doing any special formatting. url.params.delete(:message) url.delete +=== Make Custom Objects + +Make objects designed around specific urls + + class FacebookURL < URL('http://www.facebook.com/__test_me__/foo/__test_again__') + allow_changed :subdomain + allow_params :foo, :bar + end + +This will create a FacebookURL object where you can only change the subdomain, the params foo and bar, and the parts of the paths tagged +test_me and test_again. This object has the getters and setters: subdomain, foo, bar, test_me, and test_again. You can then call .to_s, +.get, .post, or .delete. + +The object has an instance variable defined as @url which is a url object you can manipulate. + == TODO * Fast Dup method * More Documentation diff --git a/lib/url/classer.rb b/lib/url/classer.rb index 65efb33..b87601b 100644 --- a/lib/url/classer.rb +++ b/lib/url/classer.rb @@ -1,10 +1,13 @@ module URL::Classer + VAR_MATCHER = /__([A-Za-z]?[A-Za-z_]*[A-Za-z])__/ + module ClassMethods def allowed_params @allowed_params ||= [] end private def allow_changed *args + args.flatten! def_delegators :@url, :subdomains if args.include?(:subdomain) def_delegators :@url, :subdomain if args.include?(:subdomains) def_delegators :@url, :[], :[]= if args.include?(:params) @@ -12,7 +15,7 @@ def allow_changed *args end def allow_params *args - args.each do |arg| + args.flatten.each do |arg| arg = arg.to_sym self.allowed_params << arg define_method arg do @@ -25,17 +28,38 @@ def allow_params *args end end + def overrideable_path_val v + v = v.to_s.downcase + define_method v do + @var_map[v] + end + + define_method "#{v}=" do |val| + @var_map[v] = val + + p = self.class.const_get(:URL).path.dup + + @var_map.each do |key,value| + p.gsub!("__#{key}__", value.to_s) + end + + @url.path = p + + val + end + end + end module InstanceMethods def initialize(opts={}) @url = self.class.const_get(:URL).dup - opts.delete_if do |k,v| - !self.class.allowed_params.include?(k.to_sym) - end + @var_map = {} - @url.params.merge!(opts) + opts.each do |op,v| + send("#{op}=",v) + end end def to_s @@ -61,17 +85,23 @@ def self.included(receiver) end def URL url - klass = Class.new - if url.is_a?(URL) url = url.dup else - url = URL.new(url) + url = ::URL.new(url) end - klass.const_set(:URL, url) + klass = Class.new do + include URL::Classer + + vars = url.path.scan(URL::Classer::VAR_MATCHER).flatten + + vars.each do |var| + overrideable_path_val(var) + end + end - klass.send(:include, URL::Classer) + klass.const_set(:URL, url.freeze) klass end diff --git a/spec/classer_spec.rb b/spec/classer_spec.rb index 7e7b5e0..48e3034 100644 --- a/spec/classer_spec.rb +++ b/spec/classer_spec.rb @@ -4,19 +4,18 @@ describe "URL()" do before(:all) do - class FacebookURL < URL('http://www.facebook.com') + class FacebookURL < URL('http://www.facebook.com/__test_me__/foo/__test_again__') allow_changed :subdomain - allow_params :foo + allow_params :foo, :bar end end it "should create a class" do url = 'http://www.facebook.com' - u = URL.new(url) - URL(u).should be_a(Class) + lambda {class FacebookURL2 < URL(url); end}.should_not raise_error - URL.should_receive(:new,url).once - URL(url).should be_a(Class) + FacebookURL2.new.to_s.should == 'http://www.facebook.com/' + FacebookURL2.new.should be_a(URL::Classer) end context '.new' do @@ -24,10 +23,10 @@ class FacebookURL < URL('http://www.facebook.com') it "shoud work like whatever" do subject.subdomain << 'us' - subject.to_s.should =~ /^http:\/\/www\.us\.facebook.com\/?$/ + subject.to_s.should =~ /^http:\/\/www\.us\.facebook.com/ u = FacebookURL.new - u.to_s.should =~ /^http:\/\/www\.facebook.com\/?$/ + u.to_s.should =~ /^http:\/\/www\.facebook.com/ end it "should dup" do @@ -45,6 +44,23 @@ class FacebookURL < URL('http://www.facebook.com') subject.foo.should == 1 subject.to_s.should =~ /foo=1/ end + + it "should set vars" do + subject.test_me = 'foobar' + subject.test_me.should == 'foobar' + + subject.test_again = 'abc' + subject.to_s.should == "http://www.facebook.com/foobar/foo/abc" + + subject.test_again = 'aaa' + subject.to_s.should == "http://www.facebook.com/foobar/foo/aaa" + end + + it "should set vars in create" do + u = FacebookURL.new(:test_me => 'foobar', :test_again => 'abc') + + u.to_s.should == "http://www.facebook.com/foobar/foo/abc" + end end end