http_router 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/ext/rack/rack_mapper.rb +57 -0
- data/lib/ext/rack/uri_escape.rb +26 -0
- data/lib/http_router/glob.rb +2 -1
- data/lib/http_router/{sinatra.rb → interface/sinatra.rb} +7 -7
- data/lib/http_router/node.rb +109 -59
- data/lib/http_router/path.rb +23 -2
- data/lib/http_router/response.rb +36 -15
- data/lib/http_router/root.rb +12 -63
- data/lib/http_router/route.rb +74 -24
- data/lib/http_router/variable.rb +16 -9
- data/lib/http_router.rb +55 -31
- data/spec/generate_spec.rb +81 -12
- data/spec/misc_spec.rb +38 -0
- data/spec/rack/dispatch_spec.rb +2 -2
- data/spec/rack/generate_spec.rb +1 -1
- data/spec/recognize_spec.rb +25 -2
- data/spec/sinatra/recognize_spec.rb +2 -2
- metadata +14 -6
- data/lib/rack/uri_escape.rb +0 -38
data/Rakefile
CHANGED
@@ -10,7 +10,7 @@ begin
|
|
10
10
|
end
|
11
11
|
Jeweler::GemcutterTasks.new
|
12
12
|
rescue LoadError
|
13
|
-
puts "Jeweler not available. Install it with:
|
13
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
14
14
|
end
|
15
15
|
|
16
16
|
require 'spec'
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Replacement for {Rack::Builder} which using HttpRouter to map requests instead of a simple Hash.
|
2
|
+
# As well, add convenience methods for the request methods.
|
3
|
+
class Rack::Builder
|
4
|
+
def initialize(&block)
|
5
|
+
@router = HttpRouter.new
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
# Maps a path to a block.
|
10
|
+
# @param path [String] Path to map to.
|
11
|
+
# @param options [Hash] Options for added path.
|
12
|
+
# @see HttpRouter#add
|
13
|
+
def map(path, options = nil, &block)
|
14
|
+
@router.add(path).with_options(options).to(&block)
|
15
|
+
@ins << @router unless @ins.last == @router
|
16
|
+
end
|
17
|
+
|
18
|
+
# Maps a path with request methods `HEAD` and `GET` to a block.
|
19
|
+
# @param path [String] Path to map to.
|
20
|
+
# @param options [Hash] Options for added path.
|
21
|
+
# @see HttpRouter#add
|
22
|
+
def get(path, options = nil, &block)
|
23
|
+
@router.get(path).with_options(options).to(&block)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Maps a path with request methods `POST` to a block.
|
27
|
+
# @param path [String] Path to map to.
|
28
|
+
# @param options [Hash] Options for added path.
|
29
|
+
# @see HttpRouter#add
|
30
|
+
def post(path, options = nil, &block)
|
31
|
+
@router.post(path).with_options(options).to(&block)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Maps a path with request methods `PUT` to a block.
|
35
|
+
# @param path [String] Path to map to.
|
36
|
+
# @param options [Hash] Options for added path.
|
37
|
+
# @see HttpRouter#add
|
38
|
+
def put(path, options = nil, &block)
|
39
|
+
@router.put(path).with_options(options).to(&block)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Maps a path with request methods `DELETE` to a block.
|
43
|
+
# @param path [String] Path to map to.
|
44
|
+
# @param options [Hash] Options for added path.
|
45
|
+
# @see HttpRouter#add
|
46
|
+
def delete(path, options = nil, &block)
|
47
|
+
@router.delete(path).with_options(options).to(&block)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Maps a path with request methods `HEAD` to a block.
|
51
|
+
# @param path [String] Path to map to.
|
52
|
+
# @param options [Hash] Options for added path.
|
53
|
+
# @see HttpRouter#add
|
54
|
+
def head(path, options = nil, &block)
|
55
|
+
@router.head(path).with_options(options).to(&block)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Rack::Utils
|
2
|
+
def uri_escape(s)
|
3
|
+
s.to_s.gsub(/([^:\/?\[\]\-_~\.!\$&'\(\)\*\+,;=@a-zA-Z0-9]+)/n) {
|
4
|
+
'%'<<$1.unpack('H2'*$1.size).join('%').upcase
|
5
|
+
}
|
6
|
+
end
|
7
|
+
module_function :uri_escape
|
8
|
+
end unless Rack::Utils.respond_to?(:uri_escape)
|
9
|
+
|
10
|
+
module Rack::Utils
|
11
|
+
def uri_escape!(s)
|
12
|
+
s.to_s.gsub!(/([^:\/?\[\]\-_~\.!\$&'\(\)\*\+,;=@a-zA-Z0-9]+)/n) {
|
13
|
+
'%'<<$1.unpack('H2'*$1.size).join('%').upcase
|
14
|
+
}
|
15
|
+
end
|
16
|
+
module_function :uri_escape!
|
17
|
+
end unless Rack::Utils.respond_to?(:uri_escape!)
|
18
|
+
|
19
|
+
module Rack::Utils
|
20
|
+
def uri_unescape(s)
|
21
|
+
gsub(/((?:%[0-9a-fA-F]{2})+)/n){
|
22
|
+
[$1.delete('%')].pack('H*')
|
23
|
+
}
|
24
|
+
end
|
25
|
+
module_function :uri_unescape
|
26
|
+
end unless Rack::Utils.respond_to?(:uri_unescape)
|
data/lib/http_router/glob.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
class HttpRouter
|
2
2
|
class Glob < Variable
|
3
|
-
def matches(parts, whole_path)
|
3
|
+
def matches(env, parts, whole_path)
|
4
4
|
if @matches_with && match = @matches_with.match(parts.first)
|
5
5
|
params = [parts.shift]
|
6
6
|
while !parts.empty? and match = @matches_with.match(parts.first)
|
7
7
|
params << parts.shift
|
8
8
|
end
|
9
|
+
return unless additional_matchers(env, params)
|
9
10
|
whole_path.replace(parts.join('/'))
|
10
11
|
params
|
11
12
|
else
|
@@ -1,4 +1,4 @@
|
|
1
|
-
$LOAD_PATH << File.join(File.dirname(__FILE__), '..')
|
1
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', '..')
|
2
2
|
require 'http_router'
|
3
3
|
|
4
4
|
class HttpRouter
|
@@ -26,17 +26,17 @@ class HttpRouter
|
|
26
26
|
private
|
27
27
|
def route!(base=self.class, pass_block=nil)
|
28
28
|
if base.router and match = base.router.recognize(@request)
|
29
|
-
if match.
|
30
|
-
route_eval {
|
31
|
-
match.headers.each{|k,v| response[k] = v}
|
32
|
-
status match.status
|
33
|
-
}
|
34
|
-
else
|
29
|
+
if match.matched?
|
35
30
|
@block_params = match.params
|
36
31
|
(@params ||= {}).merge!(match.params_as_hash)
|
37
32
|
pass_block = catch(:pass) do
|
38
33
|
route_eval(&match.route.dest)
|
39
34
|
end
|
35
|
+
else
|
36
|
+
route_eval {
|
37
|
+
match.headers.each{|k,v| response[k] = v}
|
38
|
+
status match.status
|
39
|
+
}
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
data/lib/http_router/node.rb
CHANGED
@@ -3,37 +3,41 @@ class HttpRouter
|
|
3
3
|
attr_accessor :value, :variable, :catchall
|
4
4
|
attr_reader :linear, :lookup, :request_node, :extension_node
|
5
5
|
|
6
|
-
def initialize
|
6
|
+
def initialize(base)
|
7
|
+
@router = base
|
7
8
|
reset!
|
8
9
|
end
|
9
10
|
|
10
11
|
def reset!
|
11
|
-
@linear =
|
12
|
-
@lookup =
|
12
|
+
@linear = nil
|
13
|
+
@lookup = nil
|
13
14
|
@catchall = nil
|
14
15
|
end
|
15
16
|
|
16
17
|
def add(val)
|
17
18
|
if val.is_a?(Variable)
|
18
19
|
if val.matches_with
|
19
|
-
new_node =
|
20
|
+
new_node = router.node
|
21
|
+
create_linear
|
20
22
|
@linear << [val, new_node]
|
21
23
|
new_node
|
22
24
|
else
|
23
|
-
@catchall ||=
|
25
|
+
@catchall ||= router.node
|
24
26
|
@catchall.variable = val
|
25
27
|
@catchall
|
26
28
|
end
|
27
29
|
elsif val.is_a?(Regexp)
|
28
|
-
|
30
|
+
create_linear
|
31
|
+
@linear << [val, router.node]
|
29
32
|
@linear.last.last
|
30
33
|
else
|
31
|
-
|
34
|
+
create_lookup
|
35
|
+
@lookup[val] ||= router.node
|
32
36
|
end
|
33
37
|
end
|
34
38
|
|
35
39
|
def add_extension(ext)
|
36
|
-
@extension_node ||=
|
40
|
+
@extension_node ||= router.node
|
37
41
|
@extension_node.add(ext)
|
38
42
|
end
|
39
43
|
|
@@ -43,7 +47,7 @@ class HttpRouter
|
|
43
47
|
elsif @request_node
|
44
48
|
current_node = @request_node
|
45
49
|
while current_node.request_method
|
46
|
-
current_node = (current_node.catchall ||=
|
50
|
+
current_node = (current_node.catchall ||= router.request_node)
|
47
51
|
end
|
48
52
|
[current_node]
|
49
53
|
else
|
@@ -52,12 +56,14 @@ class HttpRouter
|
|
52
56
|
end
|
53
57
|
|
54
58
|
protected
|
59
|
+
|
60
|
+
attr_reader :router
|
55
61
|
|
56
62
|
def transplant_value
|
57
63
|
if @value
|
58
64
|
target_node = @request_node
|
59
65
|
while target_node.request_method
|
60
|
-
target_node = (target_node.catchall ||=
|
66
|
+
target_node = (target_node.catchall ||= router.request_node)
|
61
67
|
end
|
62
68
|
target_node.value = @value
|
63
69
|
@value = nil
|
@@ -65,89 +71,133 @@ class HttpRouter
|
|
65
71
|
end
|
66
72
|
|
67
73
|
def generate_request_method_tree(request_options)
|
68
|
-
raise if (request_options.keys & RequestNode::RequestMethods).size != request_options.size
|
69
|
-
|
70
|
-
|
71
|
-
current_nodes = [@request_node ||= RequestNode.new]
|
74
|
+
raise(UnsupportedRequestConditionError.new) if (request_options.keys & RequestNode::RequestMethods).size != request_options.size
|
75
|
+
current_nodes = [self]
|
72
76
|
RequestNode::RequestMethods.each do |method|
|
73
|
-
|
74
|
-
if
|
75
|
-
|
77
|
+
if request_options.key?(method) # so, the request method we care about it ..
|
78
|
+
if current_nodes == [self]
|
79
|
+
current_nodes = [@request_node ||= router.request_node]
|
80
|
+
end
|
81
|
+
|
82
|
+
for current_node_index in (0...current_nodes.size)
|
83
|
+
current_node = current_nodes.at(current_node_index)
|
84
|
+
if request_options.key?(method) #we care about the method
|
76
85
|
unless current_node.request_method
|
77
86
|
current_node.request_method = method
|
78
87
|
end
|
79
|
-
|
80
88
|
case RequestNode::RequestMethods.index(method) <=> RequestNode::RequestMethods.index(current_node.request_method)
|
81
89
|
when 0 #use this node
|
82
90
|
if request_options[method].is_a?(Regexp)
|
83
|
-
|
84
|
-
|
91
|
+
new_node = router.request_node
|
92
|
+
current_nodes[current_node_index] = new_node
|
93
|
+
current_node.create_linear
|
94
|
+
current_node.linear << [request_options[method], new_node]
|
85
95
|
elsif request_options[method].is_a?(Array)
|
86
|
-
|
96
|
+
current_node.create_lookup
|
97
|
+
current_nodes[current_node_index] = request_options[method].map{|val| current_node.lookup[val] ||= router.request_node}
|
87
98
|
else
|
88
|
-
|
99
|
+
current_node.create_lookup
|
100
|
+
current_nodes[current_node_index] = (current_node.lookup[request_options[method]] ||= router.request_node)
|
89
101
|
end
|
90
102
|
when 1 #this node is farther ahead
|
91
|
-
current_nodes[current_node_index] = (current_node.catchall ||=
|
92
|
-
redo
|
103
|
+
current_nodes[current_node_index] = (current_node.catchall ||= router.request_node)
|
93
104
|
when -1 #this method is more important than the current node
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
current_nodes[current_node_index] = new_node
|
105
|
+
next_node = current_node.dup
|
106
|
+
current_node.reset!
|
107
|
+
current_node.request_method = method
|
98
108
|
redo
|
99
109
|
end
|
100
110
|
else
|
101
|
-
|
102
|
-
redo
|
111
|
+
current_node.catchall ||= router.request_node
|
103
112
|
end
|
104
|
-
elsif !current_node
|
105
|
-
@request_node = RequestNode.new
|
106
|
-
current_nodes[current_node_index] = @request_node
|
107
|
-
redo
|
108
|
-
else
|
109
|
-
current_node.catchall ||= RequestNode.new
|
110
113
|
end
|
114
|
+
current_nodes.flatten!
|
115
|
+
elsif current_nodes.first.is_a?(RequestNode) && !current_nodes.first.request_method.nil?
|
116
|
+
current_nodes.map!{|n| n.catchall ||= router.request_node}
|
111
117
|
end
|
112
|
-
current_nodes.flatten!
|
113
118
|
end
|
114
119
|
transplant_value
|
115
120
|
current_nodes
|
116
121
|
end
|
117
122
|
|
118
|
-
def
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
123
|
+
def find_on_parts(request, parts, extension, params)
|
124
|
+
if parts.empty? && extension_node && extension
|
125
|
+
parts << extension
|
126
|
+
extension_node.find_on_parts(request, parts, extension, params)
|
127
|
+
else
|
128
|
+
if @linear && !@linear.empty?
|
129
|
+
whole_path = parts.join('/')
|
130
|
+
next_node = @linear.find do |(tester, node)|
|
131
|
+
if tester.is_a?(Regexp) and match = whole_path.match(tester) #and match.index == 0 TODO
|
132
|
+
whole_path.slice!(0,match[0].size)
|
133
|
+
parts.replace(router.split(whole_path))
|
134
|
+
node
|
135
|
+
elsif new_params = tester.matches(request.env, parts, whole_path)
|
136
|
+
params << new_params
|
137
|
+
node
|
138
|
+
else
|
139
|
+
nil
|
133
140
|
end
|
134
141
|
end
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
142
|
+
return next_node.last.find_on_parts(request, parts, extension, params) if next_node
|
143
|
+
end
|
144
|
+
if match = @lookup && @lookup[parts.first]
|
145
|
+
parts.shift
|
146
|
+
match.find_on_parts(request, parts, extension, params)
|
147
|
+
elsif @catchall
|
148
|
+
params << @catchall.variable.matches(request.env, parts, whole_path)
|
149
|
+
parts.shift
|
150
|
+
@catchall.find_on_parts(request, parts, extension, params)
|
151
|
+
elsif parts.size == 1 && parts.first == '' && (value && value.route.trailing_slash_ignore?)
|
152
|
+
parts.shift
|
153
|
+
find_on_parts(request, parts, extension, params)
|
154
|
+
elsif request_node
|
155
|
+
request_node.find_on_request_methods(request)
|
156
|
+
elsif @value
|
157
|
+
self
|
158
|
+
else
|
159
|
+
nil
|
141
160
|
end
|
142
161
|
end
|
143
|
-
current_node
|
144
162
|
end
|
145
163
|
|
164
|
+
def create_linear
|
165
|
+
@linear ||= []
|
166
|
+
end
|
167
|
+
|
168
|
+
def create_lookup
|
169
|
+
@lookup ||= {}
|
170
|
+
end
|
146
171
|
end
|
147
172
|
|
148
173
|
class RequestNode < Node
|
149
174
|
RequestMethods = [:request_method, :host, :port, :scheme]
|
150
175
|
attr_accessor :request_method
|
176
|
+
|
177
|
+
def find_on_request_methods(request)
|
178
|
+
if @request_method
|
179
|
+
request_value = request.send(request_method)
|
180
|
+
if @linear && !@linear.empty?
|
181
|
+
next_node = @linear.find do |(regexp, node)|
|
182
|
+
regexp === request_value
|
183
|
+
end
|
184
|
+
next_node &&= next_node.find_on_request_methods(request)
|
185
|
+
return next_node if next_node
|
186
|
+
end
|
187
|
+
if @lookup and next_node = (@lookup[request_value] && @lookup[request_value].find_on_request_methods(request))
|
188
|
+
return next_node
|
189
|
+
elsif next_node = (@catchall && @catchall.find_on_request_methods(request))
|
190
|
+
return next_node
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
if @value
|
195
|
+
self
|
196
|
+
else
|
197
|
+
current_node = request_method == :request_method ? Response.unmatched(405, {"Allow" => @lookup.keys.join(", ")}) : nil
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
151
201
|
end
|
152
202
|
|
153
203
|
end
|
data/lib/http_router/path.rb
CHANGED
@@ -5,14 +5,35 @@ class HttpRouter
|
|
5
5
|
attr_accessor :route
|
6
6
|
def initialize(path, parts, extension)
|
7
7
|
@path, @parts, @extension = path, parts, extension
|
8
|
-
|
8
|
+
if duplicate_variable_names = variable_names.dup.uniq!
|
9
|
+
raise AmbiguousVariableException.new("You have duplicate variable name present: #{duplicate_variable_names.join(', ')}")
|
10
|
+
end
|
11
|
+
|
12
|
+
eval_path = path.gsub(/[:\*]([a-zA-Z0-9_]+)/) {"\#{args.shift || (options && options.delete(:#{$1})) || raise(MissingParameterException.new(\"missing parameter #{$1}\"))}" }
|
9
13
|
instance_eval "
|
10
14
|
def raw_url(args,options)
|
11
|
-
\"#{
|
15
|
+
\"#{eval_path}\"
|
12
16
|
end
|
13
17
|
"
|
14
18
|
end
|
15
19
|
|
20
|
+
def ===(other_path)
|
21
|
+
return false if @parts.size != other_path.parts.size
|
22
|
+
@parts.each_with_index {|p,i|
|
23
|
+
return unless compare_parts(p, other_path.parts[i])
|
24
|
+
}
|
25
|
+
compare_parts(@extension, other_path.extension)
|
26
|
+
end
|
27
|
+
|
28
|
+
def compare_parts(p1, p2)
|
29
|
+
case p1
|
30
|
+
when Glob then p2.is_a?(Glob)
|
31
|
+
when Variable then p2.is_a?(Variable)
|
32
|
+
else
|
33
|
+
p1 == p2
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
16
37
|
def url(args, options)
|
17
38
|
path = raw_url(args, options)
|
18
39
|
raise TooManyParametersException.new unless args.empty?
|
data/lib/http_router/response.rb
CHANGED
@@ -1,25 +1,46 @@
|
|
1
1
|
class HttpRouter
|
2
|
-
|
3
|
-
|
2
|
+
module Response
|
3
|
+
def self.matched(*args)
|
4
|
+
Matched.new(*args)
|
5
|
+
end
|
4
6
|
|
5
|
-
def
|
6
|
-
|
7
|
-
super
|
8
|
-
@params_as_hash = path.variable_names.zip(params).inject({}) {|h, (k,v)| h[k] = v; h }
|
9
|
-
@params_as_hash[path.extension.name] = extension if path.extension && path.extension.is_a?(Variable)
|
7
|
+
def self.unmatched(*args)
|
8
|
+
Unmatched.new(*args)
|
10
9
|
end
|
11
10
|
|
12
|
-
|
13
|
-
|
11
|
+
private
|
12
|
+
class Unmatched < Struct.new(:status, :headers)
|
13
|
+
def matched?
|
14
|
+
false
|
15
|
+
end
|
14
16
|
end
|
17
|
+
|
18
|
+
class Matched < Struct.new(:path, :params, :extension, :matched_path, :remaining_path)
|
19
|
+
attr_reader :params_as_hash, :route
|
20
|
+
|
21
|
+
def initialize(path, params, extension, matched_path, remaining_path)
|
22
|
+
raise if matched_path.nil?
|
23
|
+
super
|
24
|
+
@params_as_hash = path.variable_names.zip(params).inject({}) {|h, (k,v)| h[k] = v; h }
|
25
|
+
@params_as_hash[path.extension.name] = extension if path.extension && path.extension.is_a?(Variable)
|
26
|
+
end
|
27
|
+
|
28
|
+
def matched?
|
29
|
+
true
|
30
|
+
end
|
31
|
+
|
32
|
+
def route
|
33
|
+
path.route
|
34
|
+
end
|
15
35
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
36
|
+
def dest
|
37
|
+
route.dest
|
38
|
+
end
|
39
|
+
alias_method :destination, :dest
|
20
40
|
|
21
|
-
|
22
|
-
|
41
|
+
def partial_match?
|
42
|
+
remaining_path
|
43
|
+
end
|
23
44
|
end
|
24
45
|
end
|
25
46
|
end
|
data/lib/http_router/root.rb
CHANGED
@@ -1,10 +1,5 @@
|
|
1
1
|
class HttpRouter
|
2
2
|
class Root < Node
|
3
|
-
def initialize(base)
|
4
|
-
@base = base
|
5
|
-
reset!
|
6
|
-
end
|
7
|
-
|
8
3
|
def add_path(path)
|
9
4
|
node = path.parts.inject(self) { |node, part| node.add(part) }
|
10
5
|
if path.extension
|
@@ -15,69 +10,23 @@ class HttpRouter
|
|
15
10
|
|
16
11
|
def find(request)
|
17
12
|
path = request.path_info.dup
|
18
|
-
path.slice!(-1) if
|
13
|
+
path.slice!(-1) if router.ignore_trailing_slash? && path[-1] == ?/
|
19
14
|
extension = extract_extension(path)
|
20
|
-
parts =
|
15
|
+
parts = router.split(path)
|
21
16
|
parts << '' if path[path.size - 1] == ?/
|
22
|
-
|
23
17
|
params = []
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
18
|
+
process_response(
|
19
|
+
find_on_parts(request, parts, extension, params),
|
20
|
+
parts,
|
21
|
+
extension,
|
22
|
+
params,
|
23
|
+
request
|
24
|
+
)
|
29
25
|
end
|
30
26
|
|
31
27
|
private
|
32
|
-
|
33
|
-
def process_parts(parts, extension, params)
|
34
|
-
current_node = self
|
35
|
-
loop do
|
36
|
-
if parts.empty? && current_node.extension_node && extension
|
37
|
-
parts << extension
|
38
|
-
current_node = current_node.extension_node
|
39
|
-
end
|
40
|
-
break if current_node.nil? || (current_node.value && current_node.value.route.partially_match?) || parts.empty?
|
41
|
-
unless current_node.linear.empty?
|
42
|
-
whole_path = parts.join('/')
|
43
|
-
next_node = current_node.linear.find do |(tester, node)|
|
44
|
-
if tester.is_a?(Regexp) and match = whole_path.match(tester)
|
45
|
-
whole_path.slice!(0,match[0].size)
|
46
|
-
parts.replace(@base.split(whole_path))
|
47
|
-
node
|
48
|
-
elsif new_params = tester.matches(parts, whole_path)
|
49
|
-
params << new_params
|
50
|
-
node
|
51
|
-
else
|
52
|
-
nil
|
53
|
-
end
|
54
|
-
end
|
55
|
-
if next_node
|
56
|
-
current_node = next_node.last
|
57
|
-
next
|
58
|
-
end
|
59
|
-
end
|
60
|
-
if match = current_node.lookup[parts.first]
|
61
|
-
parts.shift
|
62
|
-
current_node = match
|
63
|
-
elsif current_node.catchall
|
64
|
-
params << current_node.catchall.variable.matches(parts, whole_path)
|
65
|
-
parts.shift
|
66
|
-
current_node = current_node.catchall
|
67
|
-
elsif parts.size == 1 && parts.first == '' && current_node && (current_node.value && current_node.value.route.trailing_slash_ignore?)
|
68
|
-
parts.shift
|
69
|
-
elsif current_node.request_node
|
70
|
-
break
|
71
|
-
else
|
72
|
-
current_node = nil
|
73
|
-
break
|
74
|
-
end
|
75
|
-
end
|
76
|
-
current_node
|
77
|
-
end
|
78
|
-
|
79
28
|
def process_response(node, parts, extension, params, request)
|
80
|
-
if node.
|
29
|
+
if node.respond_to?(:matched?) && !node.matched?
|
81
30
|
node
|
82
31
|
elsif node && node.value
|
83
32
|
if parts.empty?
|
@@ -103,10 +52,10 @@ class HttpRouter
|
|
103
52
|
|
104
53
|
def post_match(path, params, extension, matched_path, remaining_path = nil)
|
105
54
|
if path.route.partially_match? || path.matches_extension?(extension)
|
106
|
-
Response.
|
55
|
+
Response.matched(path, params, extension, matched_path, remaining_path)
|
107
56
|
else
|
108
57
|
nil
|
109
58
|
end
|
110
59
|
end
|
111
60
|
end
|
112
|
-
end
|
61
|
+
end
|