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