http_router 0.3.17 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile CHANGED
@@ -8,5 +8,6 @@ group :development do
8
8
  gem 'rake'
9
9
  gem 'sinatra'
10
10
  gem 'rbench'
11
+ gem 'code_stats'
11
12
  gem 'tumbler', ">= 0.0.11"
12
13
  end
@@ -53,14 +53,10 @@ class HttpRouter
53
53
  new_node
54
54
  end
55
55
  @linear.sort!{|a, b|
56
- if a.first.respond_to?(:priority) and b.first.respond_to?(:priority)
57
- b.first.priority <=> a.first.priority
58
- elsif a.first.respond_to?(:priority)
59
- -1
60
- elsif b.first.respond_to?(:priority)
61
- 1
62
- else
63
- 0
56
+ if a.first.respond_to?(:priority) and b.first.respond_to?(:priority) ; b.first.priority <=> a.first.priority
57
+ elsif a.first.respond_to?(:priority) ; -1
58
+ elsif b.first.respond_to?(:priority) ; 1
59
+ else ; 0
64
60
  end
65
61
  }
66
62
  n
@@ -151,103 +147,108 @@ class HttpRouter
151
147
  val
152
148
  end
153
149
 
154
- def find_on_parts(request, parts, params)
150
+ def find_on_parts(request, parts, params = [], routes = [])
155
151
  if parts and !parts.empty?
156
- if potential = potential_match(request, parts, params)
157
- return potential
158
- end
152
+ if parts.size == 1 and parts.first == ''
153
+ potential, match_parts, match_params = catch(:match) { find_on_parts(request, nil, params) }
154
+ process_match(potential, nil, match_params, routes) if potential and potential.value and (router.ignore_trailing_slash? or potential.value.route.trailing_slash_ignore?)
155
+ end
159
156
  if @linear && !@linear.empty?
160
- response = nil
161
- dupped_parts = nil
162
- dupped_params = nil
157
+ response, dupped_parts, dupped_params = nil, nil, nil
163
158
  next_node = @linear.find do |(tester, node)|
164
159
  if tester.respond_to?(:matches?) and match = tester.matches?(parts)
165
- dupped_parts = parts.dup
166
- dupped_params = params.dup
160
+ dupped_parts, dupped_params = parts.dup, params.dup
167
161
  dupped_params << escape_val(tester.consume(match, dupped_parts))
168
- parts.replace(dupped_parts) if response = node.find_on_parts(request, dupped_parts, dupped_params)
162
+ node.find_on_parts(request, dupped_parts, dupped_params, routes)
169
163
  elsif tester.respond_to?(:match) and match = tester.match(parts.whole_path) and match.begin(0) == 0
170
- dupped_parts = router.split(parts.whole_path[match[0].size, parts.whole_path.size])
171
- dupped_params = params.dup
172
- parts.replace(dupped_parts) if response = node.find_on_parts(request, dupped_parts, dupped_params)
164
+ dupped_parts, dupped_params = router.split(parts.whole_path[match[0].size, parts.whole_path.size]), params.dup
165
+ node.find_on_parts(request, dupped_parts, dupped_params, routes)
173
166
  else
174
167
  nil
175
168
  end
176
169
  end
177
- if response
178
- params.replace(dupped_params)
179
- return response
180
- end
181
170
  end
182
171
  if match = @lookup && @lookup[parts.first]
183
- part = parts.shift
184
- if match = match.find_on_parts(request, parts, params)
185
- return match
186
- else
187
- parts.unshift(part)
188
- end
172
+ match.find_on_parts(request, parts[1, parts.size - 1], params, routes)
189
173
  end
190
174
  if @catchall
191
- params << escape_val(@catchall.variable.consume(nil, parts))
192
- return @catchall.find_on_parts(request, parts, params)
175
+ dupped_parts, dupped_params = parts.dup, params.dup
176
+ dupped_params << escape_val(@catchall.variable.consume(nil, dupped_parts))
177
+ @catchall.find_on_parts(request, dupped_parts, dupped_params, routes)
193
178
  end
194
179
  end
195
- request_node and request_node.find_on_request_methods(request) or resolve_node(request)
180
+ if request_node
181
+ request_node.find_on_request_methods(request, parts, params, routes)
182
+ elsif arbitrary_node
183
+ arbitrary_node.find_on_arbitrary(request, parts, params, routes)
184
+ elsif @value
185
+ process_match(self, parts, params, routes)
186
+ else
187
+ nil
188
+ end
196
189
  end
197
190
 
198
- def create_linear
199
- @linear ||= []
191
+ def process_match(node, parts, params, routes)
192
+ if node.value.route.partially_match?
193
+ routes.push << [node, parts, params]
194
+ node
195
+ else
196
+ throw :match, [node, parts, params]
197
+ end
200
198
  end
201
199
 
202
- def create_lookup
203
- @lookup ||= {}
204
- end
205
-
206
200
  protected
207
- def resolve_node(request)
208
- if arbitrary_node
209
- arbitrary_node.find_on_arbitrary(request)
210
- elsif @value
211
- self
212
- else
213
- nil
214
- end
201
+ def create_linear
202
+ @linear ||= []
215
203
  end
216
-
217
- def potential_match(request, parts, params)
218
- parts.size == 1 and parts.first == '' and potential = find_on_parts(request, nil, params) and (router.ignore_trailing_slash? or (potential.value and potential.value.route.trailing_slash_ignore?)) and parts.shift ? potential : nil
204
+
205
+ def create_lookup
206
+ @lookup ||= {}
219
207
  end
220
208
  end
221
209
 
222
210
  class ArbitraryNode < Node
223
- def find_on_arbitrary(request)
224
- next_node = @linear && !@linear.empty? && @linear.find { |(procs, node)| procs.all?{|p| p.call(request)} }
225
- next_node && next_node.last || @catchall
211
+ def find_on_arbitrary(request, parts, params, routes)
212
+ next_node = @linear && !@linear.empty? && @linear.find { |(procs, node)|
213
+ params_hash = node.value.hashify_params(params)
214
+ procs.all?{|p| p.call(request, params_hash, node.value.route.dest)}
215
+ }
216
+ if next_node
217
+ process_match(next_node.last, parts, params, routes)
218
+ elsif @catchall
219
+ process_match(@catchall, parts, params, routes)
220
+ end
226
221
  end
227
222
  end
228
223
 
229
224
  class RequestNode < Node
230
225
  RequestMethods = [:request_method, :host, :port, :scheme, :user_agent, :ip, :fullpath, :query_string].freeze
231
226
  attr_accessor :request_method
232
- def find_on_request_methods(request)
227
+ def find_on_request_methods(request, parts, params, routes)
233
228
  next_node = if @request_method
234
229
  request_value = request.send(request_method)
235
- linear_node(request, request_value) or lookup_node(request, request_value) or catchall_node(request)
230
+ linear_node(request, parts, params, request_value, routes) or
231
+ lookup_node(request, parts, params, request_value, routes) or
232
+ catchall_node(request, parts, params, request_value, routes)
233
+ end
234
+ if next_node
235
+ process_match(next_node, parts, params, routes)
236
+ else
237
+ find_on_parts(request, parts, params, routes)
236
238
  end
237
- next_node or resolve_node(request)
238
239
  end
239
240
  private
240
- def linear_node(request, request_value)
241
+ def linear_node(request, parts, params, request_value, routes)
241
242
  if @linear && !@linear.empty?
242
243
  node = @linear.find { |(regexp, node)| regexp === request_value }
243
- node.last.find_on_request_methods(request) if node
244
+ node.last.find_on_request_methods(request, parts, params, routes) if node
244
245
  end
245
246
  end
246
- def lookup_node(request, request_value)
247
- @lookup[request_value].find_on_request_methods(request) if @lookup and @lookup[request_value]
247
+ def lookup_node(request, parts, params, request_value, routes)
248
+ @lookup[request_value].find_on_request_methods(request, parts, params, routes) if @lookup and @lookup[request_value]
248
249
  end
249
- def catchall_node(request)
250
- @catchall.find_on_request_methods(request) if @catchall
250
+ def catchall_node(request, parts, params, request_value, routes)
251
+ @catchall.find_on_request_methods(request, parts, params, routes) if @catchall
251
252
  end
252
253
  end
253
254
 
@@ -1,11 +1,14 @@
1
1
  class HttpRouter
2
2
  class Parts < Array
3
+ SLASH = '/'.freeze
4
+ SLASH_RX = Regexp.new(SLASH)
5
+
3
6
  def initialize(path)
4
- super((path[0] == ?/ ? path[1, path.size] : path).split('/'))
7
+ super((path[0] == ?/ ? path[1, path.size] : path).split(SLASH_RX))
5
8
  end
6
9
 
7
10
  def whole_path
8
- @whole_path ||= join('/')
11
+ @whole_path ||= join(SLASH)
9
12
  end
10
13
 
11
14
  def shift
@@ -1,6 +1,6 @@
1
1
  class HttpRouter
2
2
  class Path
3
- attr_reader :parts, :route, :splitting_indexes
3
+ attr_reader :parts, :route, :splitting_indexes, :path
4
4
  def initialize(route, path, parts, splitting_indexes)
5
5
  @route, @path, @parts, @splitting_indexes = route, path, parts, splitting_indexes
6
6
 
@@ -25,6 +25,10 @@ class HttpRouter
25
25
  "
26
26
  end
27
27
 
28
+ def hashify_params(params)
29
+ variable_names.zip(params).inject({}) { |h, (k,v)| h[k] = v; h }
30
+ end
31
+
28
32
  def ===(other_path)
29
33
  return false if @parts.size != other_path.parts.size
30
34
  @parts.each_with_index {|p,i|
@@ -56,15 +60,19 @@ class HttpRouter
56
60
  params.each do |k,v|
57
61
  case v
58
62
  when Array
59
- v.each { |v_part| uri << '&' << Rack::Utils.escape(k.to_s) << '%5B%5D=' << Rack::Utils.escape(v_part.to_s) }
63
+ v.each { |v_part| uri << '&' << ::Rack::Utils.escape(k.to_s) << '%5B%5D=' << ::Rack::Utils.escape(v_part.to_s) }
60
64
  else
61
- uri << '&' << Rack::Utils.escape(k.to_s) << '=' << Rack::Utils.escape(v.to_s)
65
+ uri << '&' << ::Rack::Utils.escape(k.to_s) << '=' << ::Rack::Utils.escape(v.to_s)
62
66
  end
63
67
  end
64
68
  uri[uri_size] = ??
65
69
  end
66
70
  end
67
71
 
72
+ def static?
73
+ variables.empty?
74
+ end
75
+
68
76
  def variables
69
77
  unless @variables
70
78
  @variables = @parts.select{|p| p.is_a?(Variable)}
@@ -1,6 +1,6 @@
1
1
  # Replacement for {Rack::Builder} which using HttpRouter to map requests instead of a simple Hash.
2
2
  # As well, add convenience methods for the request methods.
3
- class Rack::Builder
3
+ class HttpRouter::Rack::Builder < ::Rack::Builder
4
4
  def initialize(&block)
5
5
  super
6
6
  end
@@ -1,4 +1,4 @@
1
- class Rack::URLMap
1
+ class HttpRouter::Rack::URLMap < ::Rack::URLMap
2
2
  def initialize(map = {})
3
3
  @router = HttpRouter.new
4
4
  map.each { |path, app| (path =~ /^(https?):\/\/(.*?)(\/.*)/ ? @router.add($3).host($2).scheme($1) : @router.add(path)).partial.to(app) }
@@ -0,0 +1,18 @@
1
+ class HttpRouter
2
+ module Rack
3
+ autoload :URLMap, 'http_router/rack/url_map'
4
+ autoload :Builder, 'http_router/rack/buidler'
5
+
6
+ # Monkey-patches Rack::Builder to use HttpRouter.
7
+ # See examples/rack_mapper.rb
8
+ def self.override_rack_builder!
9
+ ::Rack.class_eval("OriginalBuilder = Builder; HttpRouterBuilder = HttpRouter::Rack::Builder; remove_const :Builder; Builder = HttpRouterBuilder")
10
+ end
11
+
12
+ # Monkey-patches Rack::URLMap to use HttpRouter.
13
+ # See examples/rack_mapper.rb
14
+ def self.override_rack_urlmap!
15
+ ::Rack.class_eval("OriginalURLMap = URLMap; HttpRouterURLMap = HttpRouter::Rack::URLMap; remove_const :URLMap; URLMap = HttpRouterURLMap")
16
+ end
17
+ end
18
+ end
@@ -21,8 +21,8 @@ class HttpRouter
21
21
  def initialize(path, params, matched_path, remaining_path = nil)
22
22
  raise if matched_path.nil?
23
23
  super
24
- path.splitting_indexes and path.splitting_indexes.each{|i| params[i] = params[i].split('/')}
25
- @params_as_hash = path.variable_names.zip(params).inject({}) {|h, (k,v)| h[k] = v; h }
24
+ path.splitting_indexes and path.splitting_indexes.each{|i| params[i] = params[i].split(HttpRouter::Parts::SLASH_RX)}
25
+ @params_as_hash = path.hashify_params(params)
26
26
  end
27
27
 
28
28
  def matched?
@@ -10,10 +10,23 @@ class HttpRouter
10
10
  end
11
11
 
12
12
  def find(request)
13
- params = []
14
- parts = get_parts(request)
15
- node = find_on_parts(request, parts, params)
16
- process_response(node, parts, params, request)
13
+ routes = []
14
+ node, parts, params = catch(:match) { find_on_parts(request, get_parts(request), [], routes) }
15
+ if !routes.empty?
16
+ routes.map { |node, parts, params| process_response(node, parts, params, request) }
17
+ elsif node
18
+ process_response(node, parts, params, request)
19
+ elsif !router.request_methods_specified.empty?
20
+ alternate_methods = (router.request_methods_specified - [request.request_method]).select do |alternate_method|
21
+ test_request = request.dup
22
+ test_request.env['REQUEST_METHOD'] = alternate_method
23
+ routes = []
24
+ catch(:match) { find_on_parts(test_request, get_parts(request), [], routes) } || !routes.empty?
25
+ end
26
+ alternate_methods.empty? ? nil : Response.unmatched(405, {"Allow" => alternate_methods.join(", ")})
27
+ else
28
+ nil
29
+ end
17
30
  end
18
31
 
19
32
  def get_parts(request)
@@ -24,25 +37,11 @@ class HttpRouter
24
37
 
25
38
  private
26
39
  def process_response(node, parts, params, request)
27
- if node && node.value
28
- if parts.empty?
29
- Response.matched(node.value, params, request.path_info)
30
- elsif node.value.route.partially_match?
31
- rest = '/' << parts.join('/')
32
- Response.matched(node.value, params, request.path_info[0, request.path_info.size - rest.size], rest)
33
- else
34
- nil
35
- end
36
- elsif !router.request_methods_specified.empty?
37
- alternate_methods = (router.request_methods_specified - [request.request_method]).select do |alternate_method|
38
- test_request = request.dup
39
- test_request.env['REQUEST_METHOD'] = alternate_method
40
- node = find_on_parts(test_request, get_parts(request), [])
41
- node && node.value
42
- end
43
- alternate_methods.empty? ? nil : Response.unmatched(405, {"Allow" => alternate_methods.join(", ")})
44
- else
45
- nil
40
+ if parts.nil? || parts.empty?
41
+ Response.matched(node.value, params, request.path_info)
42
+ elsif node.value.route.partially_match?
43
+ rest = '/' << parts.join('/')
44
+ Response.matched(node.value, params, request.path_info[0, request.path_info.size - rest.size], rest)
46
45
  end
47
46
  end
48
47
  end
@@ -167,10 +167,10 @@ class HttpRouter
167
167
 
168
168
  # Convenient regexp matching on an entire path. Returns +self+
169
169
  def match_path(matcher)
170
- arbitrary{|env| match = matcher.match(env.path_info); !match.nil? and match.begin(0) == 0 and match[0].size == env.path_info.size}
170
+ arbitrary{|env, params, dest| match = matcher.match(env.path_info); !match.nil? and match.begin(0) == 0 and match[0].size == env.path_info.size}
171
171
  end
172
172
 
173
- # Adds an arbitrary proc matcher to a Route. Receives either a block, or a proc. The proc will receive a Rack::Request object and must return true for the Route to be matched. Returns +self+.
173
+ # Adds an arbitrary proc matcher to a Route. Receives either a block, or a proc. The proc will receive a Rack::Request object, a Hash of the params, and the destination for this route. The proc must return true if the Route is matched. Returns +self+.
174
174
  def arbitrary(proc = nil, &block)
175
175
  guard_compiled
176
176
  @arbitrary << (proc || block)
@@ -240,22 +240,17 @@ class HttpRouter
240
240
  # Generates a URL for this route. See HttpRouter#url for how the arguments for this are structured.
241
241
  def url(*args)
242
242
  options = args.last.is_a?(Hash) ? args.pop : nil
243
- options ||= {} if default_values
244
- options = default_values.merge(options) if default_values && options
243
+ options = options.nil? ? default_values.dup : default_values.merge(options) if default_values
244
+ options.delete_if{ |k,v| v.nil? } if options
245
245
  path = if args.empty?
246
246
  matching_path(options)
247
247
  else
248
248
  matching_path(args, options)
249
249
  end
250
250
  raise UngeneratableRouteException unless path
251
-
252
- mount_point = nil
253
- if !router.url_mount.nil?
254
- mount_point = router.url_mount.url(options)
255
- end
256
-
251
+ mount_point = router.url_mount && router.url_mount.url(options)
257
252
  result = path.url(args, options)
258
- mount_point.nil? ? result : File.join(mount_point, result)
253
+ mount_point ? File.join(mount_point, result) : result
259
254
  end
260
255
 
261
256
  def significant_variable_names
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  class HttpRouter #:nodoc
3
- VERSION = '0.3.17'
3
+ VERSION = '0.4.0'
4
4
  end
data/lib/http_router.rb CHANGED
@@ -11,6 +11,7 @@ require 'http_router/path'
11
11
  require 'http_router/optional_compiler'
12
12
  require 'http_router/parts'
13
13
  require 'http_router/version'
14
+ require 'http_router/rack'
14
15
 
15
16
  class HttpRouter
16
17
  # Raised when a Route is not able to be generated.
@@ -33,18 +34,6 @@ class HttpRouter
33
34
  attr_reader :named_routes, :routes, :root, :request_methods_specified
34
35
  attr_accessor :url_mount
35
36
 
36
- # Monkey-patches Rack::Builder to use HttpRouter.
37
- # See examples/rack_mapper.rb
38
- def self.override_rack_mapper!
39
- require File.join('ext', 'rack', 'rack_mapper')
40
- end
41
-
42
- # Monkey-patches Rack::Builder to use HttpRouter.
43
- # See examples/rack_mapper.rb
44
- def self.override_rack_urlmap!
45
- require File.join('ext', 'rack', 'rack_urlmap')
46
- end
47
-
48
37
  # Creates a new HttpRouter.
49
38
  # Can be called with either <tt>HttpRouter.new(proc{|env| ... }, { .. options .. })</tt> or with the first argument omitted.
50
39
  # If there is a proc first, then it's used as the default app in the case of a non-match.
@@ -56,7 +45,7 @@ class HttpRouter
56
45
  def initialize(*args, &block)
57
46
  default_app, options = args.first.is_a?(Hash) ? [nil, args.first] : [args.first, args[1]]
58
47
  @options = options
59
- @default_app = default_app || options && options[:default_app] || proc{|env| Rack::Response.new("Not Found", 404).finish }
48
+ @default_app = default_app || options && options[:default_app] || proc{|env| ::Rack::Response.new("Not Found", 404).finish }
60
49
  @ignore_trailing_slash = options && options.key?(:ignore_trailing_slash) ? options[:ignore_trailing_slash] : true
61
50
  @redirect_trailing_slash = options && options.key?(:redirect_trailing_slash) ? options[:redirect_trailing_slash] : false
62
51
  @middleware = options && options.key?(:middleware) ? options[:middleware] : false
@@ -148,7 +137,14 @@ class HttpRouter
148
137
 
149
138
  # Returns the HttpRouter::Response object if the env is matched, otherwise, returns +nil+.
150
139
  def recognize(env)
151
- response = @root.find(env.is_a?(Hash) ? Rack::Request.new(env) : env)
140
+ response = recognize_full(env)
141
+ response.is_a?(Array) ? response.first : response
142
+ end
143
+
144
+ # Returns the HttpRouter::Response object if the env is matched, an array of HttpRouter::Response objects or otherwise, returns +nil+. If it
145
+ # returns an array, this represents a set of possible matches.
146
+ def recognize_full(env)
147
+ @root.find(env.is_a?(Hash) ? ::Rack::Request.new(env) : env)
152
148
  end
153
149
 
154
150
  # Generate a URL for a specified route. This will accept a list of variable values plus any other variable names named as a hash.
@@ -167,12 +163,9 @@ class HttpRouter
167
163
  # # ==> "/123.html?fun=inthesun"
168
164
  def url(route, *args)
169
165
  case route
170
- when Symbol
171
- url(@named_routes[route], *args)
172
- when nil
173
- raise UngeneratableRouteException
174
- else
175
- route.url(*args)
166
+ when Symbol then url(@named_routes[route], *args)
167
+ when nil then raise UngeneratableRouteException
168
+ else route.url(*args)
176
169
  end
177
170
  end
178
171
 
@@ -181,17 +174,28 @@ class HttpRouter
181
174
  # be available under the key <tt>router.params</tt>. The HttpRouter::Response object will be available under the key <tt>router.response</tt> if
182
175
  # a response is available.
183
176
  def call(env)
184
- request = Rack::Request.new(env)
177
+ request = ::Rack::Request.new(env)
185
178
  if redirect_trailing_slash? && (request.head? || request.get?) && request.path_info[-1] == ?/
186
- response = Rack::Response.new
179
+ response = ::Rack::Response.new
187
180
  response.redirect(request.path_info[0, request.path_info.size - 1], 302)
188
181
  response.finish
189
182
  else
190
183
  env['router'] = self
191
- if response = recognize(request) and !@middleware
192
- if response.matched? && response.route.dest
184
+ if response = recognize_full(request) and !@middleware
185
+ if response.is_a?(Array)
186
+ call_env = env.dup
187
+ response.each do |match|
188
+ if match.route.dest.respond_to?(:call)
189
+ process_params(call_env, match)
190
+ consume_path!(call_env, match)
191
+ app_response = match.route.dest.call(call_env)
192
+ return app_response unless app_response.first == 404 or app_response.first == 410
193
+ else
194
+ return response
195
+ end
196
+ end
197
+ elsif response.matched? && response.route.dest
193
198
  process_params(env, response)
194
- consume_path!(request, response) if response.partial_match?
195
199
  return response.route.dest.call(env) if response.route.dest.respond_to?(:call)
196
200
  elsif !response.matched?
197
201
  return [response.status, response.headers, []]
@@ -239,7 +243,6 @@ class HttpRouter
239
243
  new_route = route.clone(cloned_router)
240
244
  cloned_router.add_route(new_route).compile
241
245
  new_route.name(route.named) if route.named
242
-
243
246
  if route.dest
244
247
  begin
245
248
  new_route.to route.dest.clone
@@ -265,9 +268,9 @@ class HttpRouter
265
268
 
266
269
  private
267
270
 
268
- def consume_path!(request, response)
269
- request.env["SCRIPT_NAME"] = (request.env["SCRIPT_NAME"] + response.matched_path)
270
- request.env["PATH_INFO"] = response.remaining_path.nil? || response.remaining_path == '' ? '/' : response.remaining_path
271
+ def consume_path!(env, response)
272
+ env["SCRIPT_NAME"] = (env["SCRIPT_NAME"] + response.matched_path)
273
+ env["PATH_INFO"] = response.remaining_path.nil? || response.remaining_path == '' ? '/' : response.remaining_path
271
274
  end
272
275
 
273
276
  def process_params(env, response)
@@ -131,6 +131,13 @@ describe "HttpRouter#generate" do
131
131
  end
132
132
  end
133
133
 
134
+ context "with nil values" do
135
+ it "shouldn't use nil values" do
136
+ @router.add("/url(/:var)").name(:test).compile
137
+ @router.url(:test, :var => nil).should == "/url"
138
+ end
139
+ end
140
+
134
141
  context "with a matching" do
135
142
  it "should raise an exception when the route is invalid" do
136
143
  @router.add("/:var").matching(:var => /\d+/).name(:test).compile
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe "Rack::Urlmap replacement" do
4
4
  it "should map urls" do
5
- HttpRouter.override_rack_urlmap!
5
+ HttpRouter::Rack.override_rack_urlmap!
6
6
  map = Rack::URLMap.new(
7
7
  "http://www.example.org/test" => proc {|env| [200, {}, ['test']]},
8
8
  "http://www.example.org/:test" => proc {|env| [200, {}, ['variable']]}
@@ -58,38 +58,54 @@ describe "HttpRouter#recognize" do
58
58
 
59
59
  end
60
60
 
61
+ context("with multiple partial matching") do
62
+ it "should match partially" do
63
+ @router.add("/test").partial.to{|env| [200, {}, ['/test',env['PATH_INFO']]]}
64
+ @router.add("/").partial.to{|env| [200, {}, ['/',env['PATH_INFO']]]}
65
+ @router.call(Rack::MockRequest.env_for('/test/optional')).last.should == ['/test', '/optional']
66
+ @router.call(Rack::MockRequest.env_for('/testing/optional')).last.should == ['/', '/testing/optional']
67
+ end
68
+ end
69
+
70
+
61
71
  context("with proc acceptance") do
62
72
  it "should match" do
63
- @router.add("/test").arbitrary(Proc.new{|req| req.host == 'hellodooly' }).to(:test1)
64
- @router.add("/test").arbitrary(Proc.new{|req| req.host == 'lovelove' }).arbitrary{|req| req.port == 80}.to(:test2)
65
- @router.add("/test").arbitrary(Proc.new{|req| req.host == 'lovelove' }).arbitrary{|req| req.port == 8080}.to(:test3)
73
+ @router.add("/test").arbitrary(Proc.new{|req, params, dest| req.host == 'hellodooly' }).to(:test1)
74
+ @router.add("/test").arbitrary(Proc.new{|req, params, dest| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 80}.to(:test2)
75
+ @router.add("/test").arbitrary(Proc.new{|req, params, dest| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 8080}.to(:test3)
66
76
  response = @router.recognize(Rack::MockRequest.env_for('http://lovelove:8080/test'))
67
77
  response.dest.should == :test3
68
78
  end
69
79
 
70
80
  it "should still use an existing less specific node if possible" do
71
81
  @router.add("/test").to(:test4)
72
- @router.add("/test").arbitrary(Proc.new{|req| req.host == 'hellodooly' }).to(:test1)
73
- @router.add("/test").arbitrary(Proc.new{|req| req.host == 'lovelove' }).arbitrary{|req| req.port == 80}.to(:test2)
74
- @router.add("/test").arbitrary(Proc.new{|req| req.host == 'lovelove' }).arbitrary{|req| req.port == 8080}.to(:test3)
82
+ @router.add("/test").arbitrary(Proc.new{|req, params, dest| req.host == 'hellodooly' }).to(:test1)
83
+ @router.add("/test").arbitrary(Proc.new{|req, params, dest| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 80}.to(:test2)
84
+ @router.add("/test").arbitrary(Proc.new{|req, params, dest| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 8080}.to(:test3)
75
85
  response = @router.recognize(Rack::MockRequest.env_for('http://lovelove:8081/test'))
76
86
  response.dest.should == :test4
77
87
  end
78
88
 
79
89
  it "should match with request conditions" do
80
- @router.add("/test").get.arbitrary(Proc.new{|req| req.host == 'lovelove' }).arbitrary{|req| req.port == 80}.to(:test1)
81
- @router.add("/test").get.arbitrary(Proc.new{|req| req.host == 'lovelove' }).arbitrary{|req| req.port == 8080}.to(:test2)
90
+ @router.add("/test").get.arbitrary(Proc.new{|req, params, dest| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 80}.to(:test1)
91
+ @router.add("/test").get.arbitrary(Proc.new{|req, params, dest| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 8080}.to(:test2)
82
92
  response = @router.recognize(Rack::MockRequest.env_for('http://lovelove:8080/test'))
83
93
  response.dest.should == :test2
84
94
  end
85
95
 
86
96
  it "should still use an existing less specific node if possible with request conditions" do
87
- @router.add("/test").get.arbitrary(Proc.new{|req| req.host == 'lovelove' }).arbitrary{|req| req.port == 80}.to(:test1)
88
- @router.add("/test").get.arbitrary(Proc.new{|req| req.host == 'lovelove' }).arbitrary{|req| req.port == 8080}.to(:test2)
97
+ @router.add("/test").get.arbitrary(Proc.new{|req, params, dest| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 80}.to(:test1)
98
+ @router.add("/test").get.arbitrary(Proc.new{|req, params, dest| req.host == 'lovelove' }).arbitrary{|req, params, dest| req.port == 8080}.to(:test2)
89
99
  @router.add("/test").get.to(:test3)
90
100
  response = @router.recognize(Rack::MockRequest.env_for('http://lovelove:8081/test'))
91
101
  response.dest.should == :test3
92
102
  end
103
+
104
+ it "should pass params and dest" do
105
+ @router.add("/:test").get.arbitrary(Proc.new{|req, params, dest| params[:test] == 'test' and dest == :test1 }).to(:test1)
106
+ response = @router.recognize(Rack::MockRequest.env_for('/test'))
107
+ response.dest.should == :test1
108
+ end
93
109
  end
94
110
 
95
111
  context("with trailing slashes") do
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: http_router
3
3
  version: !ruby/object:Gem::Version
4
- hash: 49
4
+ hash: 15
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 3
9
- - 17
10
- version: 0.3.17
8
+ - 4
9
+ - 0
10
+ version: 0.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Joshua Hull
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-09-08 00:00:00 -07:00
18
+ date: 2010-10-04 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -169,8 +169,6 @@ files:
169
169
  - examples/variable.ru
170
170
  - examples/variable_with_regex.ru
171
171
  - http_router.gemspec
172
- - lib/ext/rack/rack_mapper.rb
173
- - lib/ext/rack/rack_urlmap.rb
174
172
  - lib/http_router.rb
175
173
  - lib/http_router/glob.rb
176
174
  - lib/http_router/interface/sinatra.rb
@@ -178,6 +176,9 @@ files:
178
176
  - lib/http_router/optional_compiler.rb
179
177
  - lib/http_router/parts.rb
180
178
  - lib/http_router/path.rb
179
+ - lib/http_router/rack.rb
180
+ - lib/http_router/rack/builder.rb
181
+ - lib/http_router/rack/url_map.rb
181
182
  - lib/http_router/response.rb
182
183
  - lib/http_router/root.rb
183
184
  - lib/http_router/route.rb