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.
- 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
|