http_router 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/Rakefile +6 -5
  2. data/benchmarks/rack_mount.rb +16 -45
  3. data/benchmarks/rec2.rb +8 -8
  4. data/http_router.gemspec +5 -4
  5. data/lib/http_router/interface/sinatra.rb +7 -7
  6. data/lib/http_router/node.rb +106 -105
  7. data/lib/http_router/optional_compiler.rb +14 -5
  8. data/lib/http_router/path.rb +18 -28
  9. data/lib/http_router/root.rb +17 -29
  10. data/lib/http_router/route.rb +47 -16
  11. data/lib/http_router/static.rb +5 -0
  12. data/lib/http_router/variable.rb +2 -5
  13. data/lib/http_router/version.rb +1 -1
  14. data/lib/http_router.rb +38 -65
  15. data/test/helper.rb +74 -0
  16. data/test/rack/test_dispatch.rb +120 -0
  17. data/test/rack/test_route.rb +44 -0
  18. data/test/rack/test_urlmap.rb +12 -0
  19. data/{spec → test}/sinatra/recognize_spec.rb +0 -0
  20. data/test/sinatra/test_recognize.rb +150 -0
  21. data/test/test_arbitrary.rb +50 -0
  22. data/test/test_generate.rb +93 -0
  23. data/test/test_greedy.rb +24 -0
  24. data/test/test_interstitial.rb +47 -0
  25. data/test/test_misc.rb +30 -0
  26. data/test/test_mounting.rb +89 -0
  27. data/test/test_recognize.rb +56 -0
  28. data/test/test_request.rb +85 -0
  29. data/test/test_trailing_slash.rb +28 -0
  30. data/test/test_variable.rb +108 -0
  31. metadata +41 -32
  32. data/lib/http_router/response.rb +0 -46
  33. data/spec/generate_spec.rb +0 -234
  34. data/spec/misc_spec.rb +0 -65
  35. data/spec/mounting_spec.rb +0 -5
  36. data/spec/rack/dispatch_spec.rb +0 -119
  37. data/spec/rack/generate_spec.rb +0 -29
  38. data/spec/rack/middleware_spec.rb +0 -22
  39. data/spec/rack/route_spec.rb +0 -72
  40. data/spec/rack/urlmap_spec.rb +0 -13
  41. data/spec/recognize_spec.rb +0 -497
  42. data/spec/spec_helper.rb +0 -25
@@ -1,6 +1,8 @@
1
+ require 'strscan'
2
+
1
3
  class HttpRouter
2
4
  class Route
3
- attr_reader :dest, :paths, :path, :matches_with
5
+ attr_reader :dest, :paths, :path, :matches_with, :original_path
4
6
  attr_accessor :trailing_slash_ignore, :partially_match, :default_values
5
7
 
6
8
  def initialize(router, path)
@@ -24,6 +26,10 @@ class HttpRouter
24
26
  end
25
27
  end
26
28
 
29
+ def to_s
30
+ "#{@original_path} conditions: #{@conditions.inspect} default_values: #{@default_values.inspect} name: #{named.inspect}"
31
+ end
32
+
27
33
  # Returns the options used to create this route.
28
34
  def as_options
29
35
  {:matching => @matches_with, :conditions => @conditions, :default_values => @default_values, :name => @name, :partial => @partially_match, :arbitrary => @arbitrary}
@@ -199,8 +205,14 @@ class HttpRouter
199
205
  working_set = current_node.add_request_methods(@conditions)
200
206
  working_set.map!{|node| node.add_arbitrary(@arbitrary)}
201
207
  working_set.each do |current_node|
202
- current_node.value = path
208
+ case current_node.value
209
+ when nil
210
+ current_node.value = [path]
211
+ else
212
+ current_node.value << path
213
+ end
203
214
  end
215
+ path.variable_names.each{|vn| router.variable_names << vn} unless path.static?
204
216
  end
205
217
  end
206
218
  self
@@ -240,6 +252,11 @@ class HttpRouter
240
252
 
241
253
  # Generates a URL for this route. See HttpRouter#url for how the arguments for this are structured.
242
254
  def url(*args)
255
+ result, extra_params = url_with_params(*args)
256
+ router.append_querystring(result, extra_params)
257
+ end
258
+
259
+ def url_with_params(*args)
243
260
  options = args.last.is_a?(Hash) ? args.pop : nil
244
261
  options = options.nil? ? default_values.dup : default_values.merge(options) if default_values
245
262
  options.delete_if{ |k,v| v.nil? } if options
@@ -249,19 +266,15 @@ class HttpRouter
249
266
  matching_path(args, options)
250
267
  end
251
268
  raise UngeneratableRouteException unless path
269
+ result, params = path.url(args, options)
252
270
  mount_point = router.url_mount && router.url_mount.url(options)
253
- result = path.url(args, options)
254
- mount_point ? File.join(mount_point, result) : result
271
+ mount_point ? [File.join(mount_point, result), params] : [result, params]
255
272
  end
256
273
 
257
274
  def significant_variable_names
258
275
  @significant_variable_names ||= @path.scan(/(^|[^\\])[:\*]([a-zA-Z0-9_]+)/).map{|p| p.last.to_sym}
259
276
  end
260
277
 
261
- private
262
-
263
- attr_reader :router
264
-
265
278
  def matching_path(params, other_hash = nil)
266
279
  if @paths.size == 1
267
280
  @paths.first
@@ -285,6 +298,10 @@ class HttpRouter
285
298
  end
286
299
  end
287
300
 
301
+ private
302
+
303
+ attr_reader :router
304
+
288
305
  def extract_partial_match(path)
289
306
  path[-1] == ?* && path.slice!(-1)
290
307
  end
@@ -337,32 +354,46 @@ class HttpRouter
337
354
  end
338
355
 
339
356
  def generate_interstitial_parts(part)
340
- part_segments = part.scan(/:[a-zA-Z_0-9]+|[^:]+/)
357
+ part_segments = []
358
+ scanner = StringScanner.new(part)
359
+ while !scanner.eos?
360
+ if scanner.scan(/\\[:\*]/)
361
+ part_segments << [:static, ''] if part_segments.last.nil? or part_segments.last.first == :variable
362
+ part_segments.last.last << scanner.matched[-1].chr
363
+ elsif scanner.scan(/\\/)
364
+ # do nothing
365
+ elsif scanner.scan(/:[a-zA_Z0-9_]+/)
366
+ part_segments << [:variable, scanner.matched]
367
+ elsif scanner.scan(/./)
368
+ part_segments << [:static, ''] if part_segments.last.nil? or part_segments.last.first == :variable
369
+ part_segments.last.last << scanner.matched
370
+ end
371
+ end
341
372
  priority = 0
342
373
  if part_segments.size > 1
343
374
  index = 0
344
- segs = part_segments.map do |seg|
345
- new_seg = if seg[0] == ?:
375
+ segs = part_segments.map do |(type, seg)|
376
+ new_seg = if type == :variable
346
377
  next_index = index + 1
347
378
  v_name = seg[1, seg.size].to_sym
348
379
  matcher = @matches_with[v_name]
349
380
  scan_regex = if next_index == part_segments.size
350
381
  matcher || /^[^\/]+/
351
382
  else
352
- /^#{matcher || '[^\/]+?'}(?=#{Regexp.quote(part_segments[next_index])})/
383
+ /^#{matcher || '[^\/]+?'}(?=#{Regexp.quote(part_segments[next_index].last)})/
353
384
  end
354
- priority += 1
355
385
  router.variable(v_name, scan_regex)
356
386
  else
357
- /^#{Regexp.quote(seg)}/
387
+ priority += seg.size
388
+ Static.new("^#{Regexp.quote(seg)}")
358
389
  end
359
390
  index += 1
360
391
  new_seg
361
392
  end
362
- segs.each { |seg| seg.priority = priority if seg.respond_to?(:priority=) }
393
+ segs.each {|seg| seg.priority = priority}
363
394
  segs
364
395
  else
365
- part
396
+ [part_segments.last.last]
366
397
  end
367
398
  end
368
399
 
@@ -0,0 +1,5 @@
1
+ class HttpRouter
2
+ class Static < Regexp
3
+ attr_accessor :priority
4
+ end
5
+ end
@@ -3,11 +3,8 @@ class HttpRouter
3
3
  attr_reader :name, :matches_with
4
4
  attr_accessor :priority
5
5
 
6
- def initialize(router, name, matches_with = nil)
7
- @router = router
8
- @name = name
9
- @matches_with = matches_with
10
- @priority = 0
6
+ def initialize(router, name, matches_with = nil, priority = 0)
7
+ @router, @name, @matches_with, @priority = router, name, matches_with, priority
11
8
  end
12
9
 
13
10
  def matches?(parts)
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  class HttpRouter #:nodoc
3
- VERSION = '0.4.1'
3
+ VERSION = '0.5.0'
4
4
  end
data/lib/http_router.rb CHANGED
@@ -4,9 +4,9 @@ require 'url_mount'
4
4
  require 'http_router/node'
5
5
  require 'http_router/root'
6
6
  require 'http_router/variable'
7
+ require 'http_router/static'
7
8
  require 'http_router/glob'
8
9
  require 'http_router/route'
9
- require 'http_router/response'
10
10
  require 'http_router/path'
11
11
  require 'http_router/optional_compiler'
12
12
  require 'http_router/parts'
@@ -31,7 +31,7 @@ class HttpRouter
31
31
  # Raised when there is a potential conflict of variable names within your Route.
32
32
  AmbiguousVariableException = Class.new(RuntimeError)
33
33
 
34
- attr_reader :named_routes, :routes, :root, :request_methods_specified
34
+ attr_reader :named_routes, :routes, :root, :request_methods_specified, :variable_names
35
35
  attr_accessor :url_mount
36
36
 
37
37
  # Creates a new HttpRouter.
@@ -41,23 +41,16 @@ class HttpRouter
41
41
  # * :default_app -- Default application used if there is a non-match on #call. Defaults to 404 generator.
42
42
  # * :ignore_trailing_slash -- Ignore a trailing / when attempting to match. Defaults to +true+.
43
43
  # * :redirect_trailing_slash -- On trailing /, redirect to the same path without the /. Defaults to +false+.
44
- # * :middleware -- On recognition, store the route Response in env['router.response'] and always call the default app. Defaults to +false+.
45
44
  def initialize(*args, &block)
46
45
  default_app, options = args.first.is_a?(Hash) ? [nil, args.first] : [args.first, args[1]]
47
46
  @options = options
48
47
  @default_app = default_app || options && options[:default_app] || proc{|env| ::Rack::Response.new("Not Found", 404).finish }
49
48
  @ignore_trailing_slash = options && options.key?(:ignore_trailing_slash) ? options[:ignore_trailing_slash] : true
50
49
  @redirect_trailing_slash = options && options.key?(:redirect_trailing_slash) ? options[:redirect_trailing_slash] : false
51
- @middleware = options && options.key?(:middleware) ? options[:middleware] : false
52
- @request_methods_specified = Set.new
53
- @routes = []
54
- @named_routes = {}
55
50
  @init_block = block
51
+ @handle_unavailable_route = Proc.new{ raise UngeneratableRouteException }
56
52
  reset!
57
- if block
58
- instance_eval(&block)
59
- @routes.each {|r| r.compile}
60
- end
53
+ instance_eval(&block) if block
61
54
  end
62
55
 
63
56
  # Ignore trailing slash feature enabled? See #initialize for details.
@@ -73,8 +66,10 @@ class HttpRouter
73
66
  # Resets the router to a clean state.
74
67
  def reset!
75
68
  @root = Root.new(self)
76
- @routes.clear
77
- @named_routes.clear
69
+ @request_methods_specified = Set.new
70
+ @routes = []
71
+ @named_routes = {}
72
+ @variable_names = Set.new
78
73
  end
79
74
 
80
75
  # Assigns the default application.
@@ -135,18 +130,6 @@ class HttpRouter
135
130
  add(path, options).delete
136
131
  end
137
132
 
138
- # Returns the HttpRouter::Response object if the env is matched, otherwise, returns +nil+.
139
- def recognize(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)
148
- end
149
-
150
133
  # Generate a URL for a specified route. This will accept a list of variable values plus any other variable names named as a hash.
151
134
  # This first value must be either the Route object or the name of the route.
152
135
  #
@@ -164,8 +147,18 @@ class HttpRouter
164
147
  def url(route, *args)
165
148
  case route
166
149
  when Symbol then url(@named_routes[route], *args)
167
- when nil then raise UngeneratableRouteException
168
- else route.url(*args)
150
+ when Route then route.url(*args)
151
+ when nil then @handle_unavailable_route.call(:url, *args)
152
+ else
153
+ end
154
+ end
155
+
156
+ def url_with_params(route, *args)
157
+ case route
158
+ when Symbol then url_with_params(@named_routes[route], *args)
159
+ when Route then route.url_with_params(*args)
160
+ when nil then @handle_unavailable_route.call(:url_with_params, *args)
161
+ else
169
162
  end
170
163
  end
171
164
 
@@ -180,33 +173,14 @@ class HttpRouter
180
173
  response.redirect(request.path_info[0, request.path_info.size - 1], 302)
181
174
  response.finish
182
175
  else
183
- env['router'] = self
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
198
- process_params(env, response)
199
- return response.route.dest.call(env) if response.route.dest.respond_to?(:call)
200
- elsif !response.matched?
201
- return [response.status, response.headers, []]
202
- end
203
- process_params(env, response)
204
- end
205
- env['router.response'] = response
206
- @default_app.call(env)
176
+ @root.call(request) || @default_app.call(request.env)
207
177
  end
208
178
  end
209
179
 
180
+ def recognize(env)
181
+ @root.recognize(env)
182
+ end
183
+
210
184
  # Returns a new node
211
185
  def node(*args)
212
186
  Node.new(self, *args)
@@ -266,20 +240,19 @@ class HttpRouter
266
240
  s.to_s.gsub!(/((?:%[0-9a-fA-F]{2})+)/n){ [$1.delete('%')].pack('H*') }
267
241
  end
268
242
 
269
- private
270
-
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
274
- end
275
-
276
- def process_params(env, response)
277
- if env.key?('router.params')
278
- env['router.params'].merge!(response.route.default_values) if response.route.default_values
279
- env['router.params'].merge!(response.params_as_hash)
280
- else
281
- env['router.params'] = response.route.default_values ? response.route.default_values.merge(response.params_as_hash) : response.params_as_hash
243
+ def append_querystring(uri, params)
244
+ if params && !params.empty?
245
+ uri_size = uri.size
246
+ params.each do |k,v|
247
+ case v
248
+ when Array
249
+ v.each { |v_part| uri << '&' << ::Rack::Utils.escape(k.to_s) << '%5B%5D=' << ::Rack::Utils.escape(v_part.to_s) }
250
+ else
251
+ uri << '&' << ::Rack::Utils.escape(k.to_s) << '=' << ::Rack::Utils.escape(v.to_s)
252
+ end
253
+ end
254
+ uri[uri_size] = ??
282
255
  end
256
+ uri
283
257
  end
284
-
285
258
  end
data/test/helper.rb ADDED
@@ -0,0 +1,74 @@
1
+ require 'minitest/autorun'
2
+ require 'phocus'
3
+
4
+ class HttpRouter::Route
5
+ def default_destination
6
+ to{|env| Rack::Response.new("Routing to #{to_s}").finish}
7
+ end
8
+ end
9
+
10
+ class MiniTest::Unit::TestCase
11
+ def router(*args, &blk)
12
+ @router ||= HttpRouter.new(*args, &blk)
13
+ if blk
14
+ @router.routes.each do |route|
15
+ route.default_destination if route.dest.nil?
16
+ end
17
+ @router.routes.size > 1 ? @router.routes : @router.routes.first
18
+ else
19
+ @router
20
+ end
21
+ end
22
+
23
+ def assert_body(expect, response)
24
+ response = router.call(response) if response.is_a?(Hash)
25
+ body = case expect
26
+ when Array then []
27
+ when String then ""
28
+ else raise
29
+ end
30
+ response.last.each {|p| body << p}
31
+ assert_equal expect, body
32
+ end
33
+
34
+ def assert_header(header, response)
35
+ response = router.call(response) if response.is_a?(Hash)
36
+ header.each{|k, v| assert_equal v, response[1][k]}
37
+ end
38
+
39
+ def assert_status(status, response)
40
+ response = router.call(response) if response.is_a?(Hash)
41
+ assert_equal status, response.first
42
+ end
43
+
44
+ def assert_route(route, request, params = nil, &blk)
45
+ if route.is_a?(String)
46
+ router.reset!
47
+ route = router.add(route)
48
+ end
49
+ route.to{|env| Rack::Response.new("Routing to #{route.to_s}").finish} if route && !route.compiled?
50
+ request = Rack::MockRequest.env_for(request) if request.is_a?(String)
51
+ response = @router.call(request)
52
+ if route
53
+ dest = "Routing to #{route.to_s}"
54
+ assert_equal [dest], response.last.body
55
+ if params
56
+ assert_equal params.size, request['router.params'].size
57
+ params.each { |k, v| assert_equal v, request['router.params'][k] }
58
+ elsif !request['router.params'].nil? and !request['router.params'].empty?
59
+ raise "Wasn't expecting any parameters, got #{request['router.params'].inspect}"
60
+ end
61
+ else
62
+ assert_equal 404, response.first
63
+ end
64
+ end
65
+
66
+ def assert_generate(path, route, *args)
67
+ if route.is_a?(String)
68
+ router.reset!
69
+ route = router.add(route).to(path.to_sym)
70
+ end
71
+ route.to{|env| Rack::Response.new("Routing to #{route.to_s}").finish} if route.respond_to?(:compiled?) && !route.compiled?
72
+ assert_equal path, router.url(route, *args)
73
+ end
74
+ end
@@ -0,0 +1,120 @@
1
+ #describe "HttpRouter route dispatching with redirect_on_trailing_delimiters" do
2
+ # before(:each) do
3
+ # @route_set = HttpRouter.new(:redirect_trailing_slash => true)
4
+ # @route_set.extend(CallWithMockRequestMixin)
5
+ # @app = MockApp.new("Hello World!")
6
+ # @route_set.add('/sample').to(@app)
7
+ # end
8
+ #
9
+ # it "should dispatch a request" do
10
+ # response = @route_set.call_with_mock_request('/sample/')
11
+ # response.headers["Location"].should == "/sample"
12
+ # end
13
+ #
14
+ #end
15
+ #
16
+ #describe "HttpRouter route dispatching" do
17
+ # before(:each) do
18
+ # @route_set = HttpRouter.new(:redirect_trailing_slash => true)
19
+ # @route_set.extend(CallWithMockRequestMixin)
20
+ # @app = MockApp.new("Hello World!")
21
+ # end
22
+ #
23
+ # describe "HTTP GET" do
24
+ # before(:each) do
25
+ # @route_set.reset!
26
+ # @route_set.add('/sample').request_method('GET').to(@app)
27
+ # end
28
+ #
29
+ # it "should dispatch a request" do
30
+ # response = @route_set.call_with_mock_request
31
+ # response.body.should eql("Hello World!")
32
+ # end
33
+ #
34
+ # it "should write router.params" do
35
+ # response = @route_set.call_with_mock_request
36
+ # @app.env["router.params"].should == {}
37
+ # end
38
+ #
39
+ # it "should write router.params for default values" do
40
+ # @route_set.add("/foobar", :default_values => {:hi => :there}).compile
41
+ # response = @route_set.call_with_mock_request("/foobar")
42
+ # env = Rack::MockRequest.env_for("/foobar")
43
+ # @route_set.call(env)
44
+ # env['router.params'].should == {:hi => :there}
45
+ # end
46
+ # end
47
+ #
48
+ # describe "HTTP POST" do
49
+ # before(:each) do
50
+ # @route_set.reset!
51
+ # @route_set.add('/sample').post.to(@app)
52
+ # @route_set.add('/sample').to(MockApp.new("You shouldn't get here if you are using POST"))
53
+ # end
54
+ #
55
+ # it "should dispatch a POST request" do
56
+ # response = @route_set.call_with_mock_request('/sample', 'POST')
57
+ # response.body.should eql("Hello World!")
58
+ # end
59
+ #
60
+ # it "shouldn't dispatch a GET request" do
61
+ # response = @route_set.call_with_mock_request('/sample', 'GET')
62
+ # response.body.should eql("You shouldn't get here if you are using POST")
63
+ # end
64
+ #
65
+ # it "should write router.params" do
66
+ # response = @route_set.call_with_mock_request("/sample", 'POST')
67
+ # @app.env["router.params"].should == {}
68
+ # end
69
+ # end
70
+ #
71
+ # it "should returns HTTP 405 if the method mis-matches" do
72
+ # @route_set.reset!
73
+ # @route_set.post('/sample').to(@app)
74
+ # @route_set.put('/sample').to(@app)
75
+ # response = @route_set.call_with_mock_request('/sample', 'GET')
76
+ # response.status.should eql(405)
77
+ # response['Allow'].should == 'POST, PUT'
78
+ # end
79
+ #
80
+ # it "should returns HTTP 404 if route doesn't exist" do
81
+ # response = @route_set.call_with_mock_request("/not-existing-url")
82
+ # response.status.should eql(404)
83
+ # end
84
+ #
85
+ # describe "shortcuts" do
86
+ # describe "get" do
87
+ # before(:each) do
88
+ # @route_set.reset!
89
+ # @route_set.get('/sample').head.to(@app)
90
+ # end
91
+ #
92
+ # it "should dispatch a GET request" do
93
+ # response = @route_set.call_with_mock_request("/sample", "GET")
94
+ # response.body.should eql("Hello World!")
95
+ # end
96
+ #
97
+ # it "should dispatch a HEAD request" do
98
+ # response = @route_set.call_with_mock_request("/sample", "HEAD")
99
+ # response.body.should eql("Hello World!")
100
+ # end
101
+ # end
102
+ # end
103
+ #
104
+ # describe "non rack app destinations" do
105
+ # it "should route to a default application when using a hash" do
106
+ # $captures = []
107
+ # @default_app = lambda do |e|
108
+ # $captures << :default
109
+ # Rack::Response.new("Default").finish
110
+ # end
111
+ # @router = HttpRouter.new
112
+ # @router.default(@default_app)
113
+ # @router.add("/default").to(:action => "default")
114
+ # response = @router.call(Rack::MockRequest.env_for("/default"))
115
+ # $captures.should == [:default]
116
+ # end
117
+ # end
118
+ #
119
+ #end
120
+ #
@@ -0,0 +1,44 @@
1
+ class TestRouteExtensions < MiniTest::Unit::TestCase
2
+
3
+ def test_redirect
4
+ router.get("/index.html").redirect("/")
5
+ response = router.call(Rack::MockRequest.env_for("/index.html"))
6
+ assert_header({'Location' => '/'}, response)
7
+ assert_status 302, response
8
+ end
9
+
10
+ def test_redirect_with_params
11
+ router.get("/:id.html").redirect('/#{params[:id]}')
12
+ response = router.call(Rack::MockRequest.env_for("/123.html"))
13
+ assert_header({'Location' => '/123'}, response)
14
+ assert_status 302, response
15
+ end
16
+
17
+ def test_static_directory
18
+ router.get("/static").static(File.dirname(__FILE__))
19
+ status, headers, body = router.call(Rack::MockRequest.env_for("/static/#{File.basename(__FILE__)}"))
20
+ assert_equal File.join(File.dirname(__FILE__), File.basename(__FILE__)), body.path
21
+ end
22
+
23
+ def test_static_file
24
+ router.get("/static-file").static(__FILE__)
25
+ status, headers, body = router.call(Rack::MockRequest.env_for("/static-file"))
26
+ assert_equal __FILE__, body.path
27
+ end
28
+
29
+ def test_chainable
30
+ router.get("/index.html").redirect("/").name(:root)
31
+ assert_equal "/index.html", router.url(:root)
32
+ end
33
+
34
+ def test_custom_status
35
+ router.get("/index.html").redirect("/", 303)
36
+ response = router.call(Rack::MockRequest.env_for("/index.html"))
37
+ assert_header({'Location' => '/'}, response)
38
+ assert_status 303, response
39
+ end
40
+
41
+ def test_raise_error_on_invalid_status
42
+ assert_raises(ArgumentError) { router.get("/index.html").redirect("/", 200) }
43
+ end
44
+ end
@@ -0,0 +1,12 @@
1
+ class TestRackUrlmap < MiniTest::Unit::TestCase
2
+
3
+ def test_map_urls
4
+ HttpRouter::Rack.override_rack_urlmap!
5
+ map = Rack::URLMap.new(
6
+ "http://www.example.org/test" => proc {|env| [200, {}, ['test']]},
7
+ "http://www.example.org/:test" => proc {|env| [200, {}, ['variable']]}
8
+ )
9
+ assert_equal 'test', map.call(Rack::MockRequest.env_for('http://www.example.org/test')).last.join
10
+ assert_equal 'variable', map.call(Rack::MockRequest.env_for('http://www.example.org/whhhaaa')).last.join
11
+ end
12
+ end
File without changes