joshbuddy-usher 0.4.7 → 0.4.8

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ begin
9
9
  s.homepage = "http://github.com/joshbuddy/usher"
10
10
  s.authors = ["Joshua Hull"]
11
11
  s.files = FileList["[A-Z]*", "{lib,spec,rails}/**/*"]
12
- s.add_dependency 'joshbuddy-fuzzy_hash', '>=0.0.3'
12
+ s.add_dependency 'fuzzyhash', '>=0.0.3'
13
13
  end
14
14
  rescue LoadError
15
15
  puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
@@ -34,3 +34,38 @@ Spec::Rake::SpecTask.new('spec_with_rcov') do |t|
34
34
  t.rcov = true
35
35
  t.rcov_opts = ['--exclude', 'spec']
36
36
  end
37
+
38
+ require 'rake/rdoctask'
39
+ desc "Generate documentation"
40
+ Rake::RDocTask.new do |rd|
41
+ rd.main = "README.rdoc"
42
+ rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
43
+ rd.rdoc_dir = 'rdoc'
44
+ end
45
+
46
+ # These are new tasks
47
+ begin
48
+ require 'rake/contrib/sshpublisher'
49
+ namespace :rubyforge do
50
+
51
+ desc "Release gem and RDoc documentation to RubyForge"
52
+ task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
53
+
54
+ namespace :release do
55
+ desc "Publish RDoc to RubyForge."
56
+ task :docs => [:rdoc] do
57
+ config = YAML.load(
58
+ File.read(File.expand_path('~/.rubyforge/user-config.yml'))
59
+ )
60
+
61
+ host = "#{config['username']}@rubyforge.org"
62
+ remote_dir = "/var/www/gforge-projects/joshbuddy-usher/"
63
+ local_dir = 'rdoc'
64
+
65
+ Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
66
+ end
67
+ end
68
+ end
69
+ rescue LoadError
70
+ puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
71
+ end
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :minor: 4
3
- :patch: 7
3
+ :patch: 8
4
4
  :major: 0
@@ -1,22 +1,61 @@
1
+ require 'rack'
2
+
3
+ unless Rack::Utils.respond_to?(:uri_escape)
4
+ module Rack
5
+
6
+ module Utils
7
+
8
+ def uri_escape(s)
9
+ s.to_s.gsub(/([^:\/?\[\]\-_~\.!\$&'\(\)\*\+,;=@a-zA-Z0-9]+)/n) {
10
+ '%'<<$1.unpack('H2'*$1.size).join('%').upcase
11
+ }.tr(' ', '+')
12
+ end
13
+ module_function :uri_escape
14
+
15
+ def uri_unescape(s)
16
+ gsub(/((?:%[0-9a-fA-F]{2})+)/n){
17
+ [$1.delete('%')].pack('H*')
18
+ }
19
+ end
20
+ module_function :uri_unescape
21
+
22
+ end
23
+ end
24
+ end
25
+
1
26
  class Usher
2
27
  class Generators
3
28
 
4
29
  class URL
5
-
30
+
6
31
  def initialize(usher)
7
32
  @usher = usher
8
33
  end
9
-
10
- # Generates a completed URL based on a +route+ or set of optional +params+
11
- #
12
- # set = Usher.new
13
- # route = set.add_named_route(:test_route, '/:controller/:action')
14
- # set.generate_url(nil, {:controller => 'c', :action => 'a'}) == '/c/a' => true
15
- # set.generate_url(:test_route, {:controller => 'c', :action => 'a'}) == '/c/a' => true
16
- # set.generate_url(route.primary_path, {:controller => 'c', :action => 'a'}) == '/c/a' => true
17
- def generate(routing_lookup, params = nil, options = nil)
18
- delimiter = options && options.key?(:delimiter) ? options.delete(:delimiter) : @usher.delimiters.first
19
34
 
35
+ def generate_full(routing_lookup, request, params = nil)
36
+ path = path_for_routing_lookup(routing_lookup, params)
37
+ result = generate_start(path, request)
38
+ result << generate_path(path, params)
39
+ end
40
+
41
+ def generate(routing_lookup, params = nil)
42
+ generate_path(path_for_routing_lookup(routing_lookup, params), params)
43
+ end
44
+
45
+ def generate_start(path, request)
46
+ result = (path.route.generate_with && path.route.generate_with.scheme || request.scheme).dup
47
+ result << '://'
48
+ result << (path.route.generate_with && path.route.generate_with.host) ? path.route.generate_with.host : request.host
49
+ port = path.route.generate_with && path.route.generate_with.port || request.port
50
+ if result[4] == ?s
51
+ result << ':' << port.to_s if port != 443
52
+ else
53
+ result << ':' << port.to_s if port != 80
54
+ end
55
+ result
56
+ end
57
+
58
+ def path_for_routing_lookup(routing_lookup, params)
20
59
  path = case routing_lookup
21
60
  when Symbol
22
61
  route = @usher.named_routes[routing_lookup]
@@ -28,13 +67,23 @@ class Usher
28
67
  when Route::Path
29
68
  routing_lookup
30
69
  end
31
-
70
+ end
71
+
72
+ # Generates a completed URL based on a +route+ or set of optional +params+
73
+ #
74
+ # set = Usher.new
75
+ # route = set.add_named_route(:test_route, '/:controller/:action')
76
+ # set.generate_url(nil, {:controller => 'c', :action => 'a'}) == '/c/a' => true
77
+ # set.generate_url(:test_route, {:controller => 'c', :action => 'a'}) == '/c/a' => true
78
+ # set.generate_url(route.primary_path, {:controller => 'c', :action => 'a'}) == '/c/a' => true
79
+ def generate_path(path, params = nil)
32
80
  raise UnrecognizedException.new unless path
33
81
 
34
82
  params = Array(params) if params.is_a?(String)
35
83
  if params.is_a?(Array)
84
+ given_size = params.size
36
85
  extra_params = params.last.is_a?(Hash) ? params.pop : nil
37
- params = Hash[*path.dynamic_parts.inject([]){|a, dynamic_part| a.concat([dynamic_part.name, params.shift || raise(MissingParameterException.new)]); a}]
86
+ params = Hash[*path.dynamic_parts.inject([]){|a, dynamic_part| a.concat([dynamic_part.name, params.shift || raise(MissingParameterException.new("got #{given_size}, expected #{path.dynamic_parts.size} parameters"))]); a}]
38
87
  params.merge!(extra_params) if extra_params
39
88
  end
40
89
 
@@ -49,7 +98,7 @@ class Usher
49
98
  current_value = current_value.to_s unless current_value.is_a?(String)
50
99
  part.valid!(current_value)
51
100
  result << current_value
52
- result << delimiter if index != value.size - 1
101
+ result << '/' if index != value.size - 1
53
102
  end
54
103
  when :':'
55
104
  value = value.to_s unless value.is_a?(String)
@@ -60,7 +109,7 @@ class Usher
60
109
  result << part
61
110
  end
62
111
  end
63
- result = URI.escape(result)
112
+ result = Rack::Utils.uri_escape(result)
64
113
 
65
114
  if params && !params.empty?
66
115
  has_query = result[??]
@@ -68,10 +117,10 @@ class Usher
68
117
  case v
69
118
  when Array
70
119
  v.each do |v_part|
71
- result << (has_query ? '&' : has_query = true && '?') << CGI.escape("#{k.to_s}[]") << '=' << CGI.escape(v_part.to_s)
120
+ result << (has_query ? '&' : has_query = true && '?') << Rack::Utils.escape("#{k.to_s}[]") << '=' << Rack::Utils.escape(v_part.to_s)
72
121
  end
73
122
  else
74
- result << (has_query ? '&' : has_query = true && '?') << CGI.escape(k.to_s) << '=' << CGI.escape(v.to_s)
123
+ result << (has_query ? '&' : has_query = true && '?') << Rack::Utils.escape(k.to_s) << '=' << Rack::Utils.escape(v.to_s)
75
124
  end
76
125
  end
77
126
  end
@@ -1,7 +1,3 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
- require 'rack_interface/route'
4
-
5
1
  class Usher
6
2
  module Interface
7
3
  class EmailInterface
@@ -1,5 +1,3 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
1
  require 'merb-core'
4
2
  require 'merb-core/dispatch/router/behavior'
5
3
 
@@ -1,18 +1,13 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
- require 'rack_interface/route'
1
+ require 'rack'
4
2
 
5
3
  class Usher
6
4
  module Interface
7
5
  class RackInterface
8
6
 
9
- RequestMethods = [:method, :host, :port, :scheme]
10
- Request = Struct.new(:path, *RequestMethods)
11
-
12
7
  attr_accessor :routes
13
8
 
14
9
  def initialize(&blk)
15
- @routes = Usher.new(:request_methods => RequestMethods)
10
+ @routes = Usher.new(:request_methods => [:method, :host, :port, :scheme])
16
11
  @generator = Usher::Generators::URL.new(@routes)
17
12
  instance_eval(&blk) if blk
18
13
  end
@@ -26,7 +21,7 @@ class Usher
26
21
  end
27
22
 
28
23
  def call(env)
29
- response = @routes.recognize(Request.new(env['REQUEST_URI'], env['REQUEST_METHOD'].downcase, env['HTTP_HOST'], env['SERVER_PORT'].to_i, env['rack.url_scheme']))
24
+ response = @routes.recognize(Rack::Request.new(env))
30
25
  params = {}
31
26
  response.params.each{ |hk| params[hk.first] = hk.last}
32
27
  env['usher.params'] = params
@@ -1,6 +1,4 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
- require 'rails2_2_interface/mapper'
1
+ require File.join(File.dirname(__FILE__), 'rails2_2_interface', 'mapper')
4
2
 
5
3
  class Usher
6
4
  module Interface
@@ -1,5 +1,3 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
1
  class Usher
4
2
  module Interface
5
3
  class Rails2_3Interface
@@ -1,12 +1,10 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
1
  class Usher
4
2
  module Interface
5
- autoload :Rails2_2Interface, 'interface/rails2_2_interface'
6
- autoload :Rails2_3Interface, 'interface/rails2_3_interface'
7
- autoload :MerbInterface, 'interface/merb_interface'
8
- autoload :RackInterface, 'interface/rack_interface'
9
- autoload :EmailInterface, 'interface/email_interface'
3
+ autoload :Rails2_2Interface, File.join(File.dirname(__FILE__), 'interface', 'rails2_2_interface')
4
+ autoload :Rails2_3Interface, File.join(File.dirname(__FILE__), 'interface', 'rails2_3_interface')
5
+ autoload :MerbInterface, File.join(File.dirname(__FILE__), 'interface', 'merb_interface')
6
+ autoload :RackInterface, File.join(File.dirname(__FILE__), 'interface', 'rack_interface')
7
+ autoload :EmailInterface, File.join(File.dirname(__FILE__), 'interface', 'email_interface')
10
8
 
11
9
  def self.for(type, &blk)
12
10
  case type
data/lib/usher/node.rb CHANGED
@@ -1,5 +1,3 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
1
  require 'fuzzy_hash'
4
2
 
5
3
  class Usher
@@ -51,7 +49,7 @@ class Usher
51
49
  route.paths.each do |path|
52
50
  parts = path.parts.dup
53
51
  request_methods.each do |type|
54
- parts.push(Route::RequestMethod.new(type, route.conditions[type])) if route.conditions.key?(type)
52
+ parts.push(Route::RequestMethod.new(type, route.conditions[type])) if route.conditions && route.conditions.key?(type)
55
53
  end
56
54
 
57
55
  current_node = self
data/lib/usher/route.rb CHANGED
@@ -1,20 +1,21 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
- require 'route/path'
4
- require 'route/variable'
5
- require 'route/request_method'
1
+ require File.join(File.dirname(__FILE__), 'route', 'path')
2
+ require File.join(File.dirname(__FILE__), 'route', 'variable')
3
+ require File.join(File.dirname(__FILE__), 'route', 'request_method')
6
4
 
7
5
  class Usher
8
6
  class Route
9
- attr_reader :paths, :original_path, :requirements, :conditions, :destination, :named
7
+ attr_reader :paths, :original_path, :requirements, :conditions, :destination, :named, :generate_with
8
+
9
+ GenerateWith = Struct.new(:scheme, :port, :host)
10
10
 
11
- def initialize(original_path, router, conditions, requirements, default_values) # :nodoc:
11
+ def initialize(original_path, router, conditions, requirements, default_values, generate_with) # :nodoc:
12
12
  @original_path = original_path
13
13
  @router = router
14
14
  @requirements = requirements
15
15
  @conditions = conditions
16
16
  @default_values = default_values
17
17
  @paths = @router.splitter.split(@original_path, @requirements, @default_values).collect {|path| Path.new(self, path)}
18
+ @generate_with = GenerateWith.new(generate_with[:scheme], generate_with[:port], generate_with[:host]) if generate_with
18
19
  end
19
20
 
20
21
  def grapher
data/lib/usher.rb CHANGED
@@ -1,16 +1,14 @@
1
- $:.unshift File.dirname(__FILE__)
2
-
3
- require 'cgi'
4
- require 'uri'
5
- require 'usher/node'
6
- require 'usher/route'
7
- require 'usher/grapher'
8
- require 'usher/interface'
9
- require 'usher/splitter'
10
- require 'usher/exceptions'
11
- require 'usher/generate'
1
+ require File.join(File.dirname(__FILE__), 'usher', 'node')
2
+ require File.join(File.dirname(__FILE__), 'usher', 'route')
3
+ require File.join(File.dirname(__FILE__), 'usher', 'grapher')
4
+ require File.join(File.dirname(__FILE__), 'usher', 'interface')
5
+ require File.join(File.dirname(__FILE__), 'usher', 'splitter')
6
+ require File.join(File.dirname(__FILE__), 'usher', 'exceptions')
12
7
 
13
8
  class Usher
9
+
10
+ autoload :Generators, File.join(File.dirname(__FILE__), 'usher', 'generate')
11
+
14
12
  attr_reader :tree, :named_routes, :route_count, :routes, :splitter, :delimiters
15
13
 
16
14
  SymbolArraySorter = proc {|a,b| a.hash <=> b.hash} #:nodoc:
@@ -142,18 +140,19 @@ class Usher
142
140
  # * +conditions+ - Accepts any of the +request_methods+ specificied in the construction of Usher. This can be either a <tt>string</tt> or a regular expression.
143
141
  # * Any other key is interpreted as a requirement for the variable of its name.
144
142
  def add_route(path, options = nil)
145
- conditions = options && options.delete(:conditions) || {}
146
- requirements = options && options.delete(:requirements) || {}
147
- default_values = options && options.delete(:default_values) || {}
143
+ conditions = options && options.delete(:conditions) || nil
144
+ requirements = options && options.delete(:requirements) || nil
145
+ default_values = options && options.delete(:default_values) || nil
146
+ generate_with = options && options.delete(:generate_with) || nil
148
147
  if options
149
148
  options.delete_if do |k, v|
150
149
  if v.is_a?(Regexp) || v.is_a?(Proc)
151
- requirements[k] = v
150
+ (requirements ||= {})[k] = v
152
151
  true
153
152
  end
154
153
  end
155
154
  end
156
- route = Route.new(path, self, conditions, requirements, default_values)
155
+ route = Route.new(path, self, conditions, requirements, default_values, generate_with)
157
156
  route.to(options) if options && !options.empty?
158
157
 
159
158
  @tree.add(route)
@@ -1,5 +1,5 @@
1
1
  require 'lib/usher'
2
-
2
+ require 'rack'
3
3
 
4
4
  describe "Usher URL generation" do
5
5
 
@@ -87,6 +87,11 @@ describe "Usher URL generation" do
87
87
  @url_generator.generate(:name, ['controller', 'action', 'html']).should == '/controller/action.html'
88
88
  end
89
89
 
90
+ it "should generate a route with a specific host" do
91
+ caf = @route_set.add_named_route(:name, '/:controller/:action.:format', :generate_with => {:host => 'www.slashdot.org', :port => 80})
92
+ @url_generator.generate_full(:name, Rack::Request.new(Rack::MockRequest.env_for("http://localhost:8080")), ['controller', 'action', 'html']).should == 'http://www.slashdot.org/controller/action.html'
93
+ end
94
+
90
95
  it "should require all the parameters (hash) to generate a route" do
91
96
  proc {@url_generator.generate(@route_set.add_route('/:controller/:action'), {:controller => 'controller'})}.should raise_error Usher::MissingParameterException
92
97
  end
@@ -1,22 +1,8 @@
1
1
  require 'lib/usher'
2
2
 
3
- route_set = Usher::Interface.for(:rack)
4
-
5
- def build_request_mock(path, method, params)
6
- request = mock "Request"
7
- request.should_receive(:path).any_number_of_times.and_return(path)
8
- request.should_receive(:method).any_number_of_times.and_return(method)
9
- params = params.with_indifferent_access
10
- request.should_receive(:path_parameters=).any_number_of_times.with(params)
11
- request.should_receive(:path_parameters).any_number_of_times.and_return(params)
12
- request
13
- end
3
+ require 'rack'
14
4
 
15
- def build_app_mock(params)
16
- request = mock "App"
17
- request.should_receive(:call).any_number_of_times.with(params)
18
- request
19
- end
5
+ route_set = Usher::Interface.for(:rack)
20
6
 
21
7
  describe "Usher (for rack) route dispatching" do
22
8
 
@@ -25,9 +11,19 @@ describe "Usher (for rack) route dispatching" do
25
11
  end
26
12
 
27
13
  it "should dispatch a simple request" do
28
- env = {'REQUEST_URI' => '/sample', 'REQUEST_METHOD' => 'get', 'usher.params' => {}}
29
- route_set.add('/sample').to(build_app_mock(env.dup))
30
- route_set.call(env)
14
+ app = mock 'app'
15
+ app.should_receive(:call).once.with {|v| v['usher.params'].should == {} }
16
+ route_set.add('/sample').to(app)
17
+ route_set.call(Rack::MockRequest.env_for("/sample", :method => 'GET'))
18
+ end
19
+
20
+ it "should dispatch a POST request" do
21
+ bad_app = mock 'bad_app'
22
+ app = mock 'app'
23
+ app.should_receive(:call).once.with {|v| v['usher.params'].should == {} }
24
+ route_set.add('/sample').to(bad_app)
25
+ route_set.add('/sample', :requirements => {:request_method => 'POST'}).to(app)
26
+ route_set.call(Rack::MockRequest.env_for("/sample", :request_method => 'POST'))
31
27
  end
32
28
 
33
- end
29
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: joshbuddy-usher
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.7
4
+ version: 0.4.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Hull
@@ -9,11 +9,11 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-12 00:00:00 -07:00
12
+ date: 2009-06-16 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
- name: joshbuddy-fuzzy_hash
16
+ name: fuzzyhash
17
17
  type: :runtime
18
18
  version_requirement:
19
19
  version_requirements: !ruby/object:Gem::Requirement
@@ -73,7 +73,7 @@ files:
73
73
  - spec/private/request_method_spec.rb
74
74
  - spec/private/split_spec.rb
75
75
  - spec/spec.opts
76
- has_rdoc: true
76
+ has_rdoc: false
77
77
  homepage: http://github.com/joshbuddy/usher
78
78
  post_install_message:
79
79
  rdoc_options:
@@ -97,7 +97,7 @@ requirements: []
97
97
  rubyforge_project:
98
98
  rubygems_version: 1.2.0
99
99
  signing_key:
100
- specification_version: 2
100
+ specification_version: 3
101
101
  summary: A general purpose routing library
102
102
  test_files:
103
103
  - spec/private/email/recognize_spec.rb