http_router 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +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
|