http_router 0.3.17 → 0.4.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/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
|