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.
- data/Rakefile +6 -5
- data/benchmarks/rack_mount.rb +16 -45
- data/benchmarks/rec2.rb +8 -8
- data/http_router.gemspec +5 -4
- data/lib/http_router/interface/sinatra.rb +7 -7
- data/lib/http_router/node.rb +106 -105
- data/lib/http_router/optional_compiler.rb +14 -5
- data/lib/http_router/path.rb +18 -28
- data/lib/http_router/root.rb +17 -29
- data/lib/http_router/route.rb +47 -16
- data/lib/http_router/static.rb +5 -0
- data/lib/http_router/variable.rb +2 -5
- data/lib/http_router/version.rb +1 -1
- data/lib/http_router.rb +38 -65
- data/test/helper.rb +74 -0
- data/test/rack/test_dispatch.rb +120 -0
- data/test/rack/test_route.rb +44 -0
- data/test/rack/test_urlmap.rb +12 -0
- data/{spec → test}/sinatra/recognize_spec.rb +0 -0
- data/test/sinatra/test_recognize.rb +150 -0
- data/test/test_arbitrary.rb +50 -0
- data/test/test_generate.rb +93 -0
- data/test/test_greedy.rb +24 -0
- data/test/test_interstitial.rb +47 -0
- data/test/test_misc.rb +30 -0
- data/test/test_mounting.rb +89 -0
- data/test/test_recognize.rb +56 -0
- data/test/test_request.rb +85 -0
- data/test/test_trailing_slash.rb +28 -0
- data/test/test_variable.rb +108 -0
- metadata +41 -32
- data/lib/http_router/response.rb +0 -46
- data/spec/generate_spec.rb +0 -234
- data/spec/misc_spec.rb +0 -65
- data/spec/mounting_spec.rb +0 -5
- data/spec/rack/dispatch_spec.rb +0 -119
- data/spec/rack/generate_spec.rb +0 -29
- data/spec/rack/middleware_spec.rb +0 -22
- data/spec/rack/route_spec.rb +0 -72
- data/spec/rack/urlmap_spec.rb +0 -13
- data/spec/recognize_spec.rb +0 -497
- data/spec/spec_helper.rb +0 -25
data/lib/http_router/route.rb
CHANGED
@@ -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
|
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
|
-
|
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 =
|
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
|
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
|
-
|
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 {
|
393
|
+
segs.each {|seg| seg.priority = priority}
|
363
394
|
segs
|
364
395
|
else
|
365
|
-
|
396
|
+
[part_segments.last.last]
|
366
397
|
end
|
367
398
|
end
|
368
399
|
|
data/lib/http_router/variable.rb
CHANGED
@@ -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)
|
data/lib/http_router/version.rb
CHANGED
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
|
-
@
|
77
|
-
@
|
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
|
168
|
-
|
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
|
-
|
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
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
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
|