http_router 0.4.1 → 0.5.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.
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