http_router 0.6.2 → 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +3 -3
- data/benchmarks/rack_mount.rb +1 -1
- data/benchmarks/rack_recognition_bm.rb +4 -4
- data/http_router.gemspec +2 -2
- data/lib/http_router.rb +28 -6
- data/lib/http_router/node.rb +21 -19
- data/lib/http_router/node/regex.rb +4 -4
- data/lib/http_router/optional_compiler.rb +1 -1
- data/lib/http_router/regex_route.rb +2 -2
- data/lib/http_router/request.rb +1 -1
- data/lib/http_router/route.rb +27 -6
- data/lib/http_router/version.rb +1 -1
- data/test/helper.rb +2 -2
- data/test/rack/test_route.rb +1 -1
- data/test/test_generate.rb +3 -3
- data/test/test_interstitial.rb +1 -1
- data/test/test_misc.rb +22 -28
- data/test/test_mounting.rb +81 -87
- data/test/test_recognize.rb +1 -1
- data/test/test_request.rb +1 -1
- data/test/test_variable.rb +15 -3
- metadata +6 -6
data/README.rdoc
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
* Partial matches.
|
9
9
|
* Supports interstitial variables (e.g. /my-:variable-brings.all.the.boys/yard) and unnamed variable /one/:/two
|
10
10
|
* Very fast and small code base (~1,000 loc).
|
11
|
-
* Sinatra
|
11
|
+
* Sinatra via https://github.com/joshbuddy/http_router_sinatra
|
12
12
|
|
13
13
|
== Usage
|
14
14
|
|
@@ -36,12 +36,12 @@ As well, you can escape the following characters with a backslash: <tt>( ) : *</
|
|
36
36
|
Once you have a route object, use <tt>HttpRouter::Route#to</tt> to add a destination and <tt>HttpRouter::Route#name</tt> to name it.
|
37
37
|
|
38
38
|
e.g.
|
39
|
-
|
39
|
+
|
40
40
|
r = HttpRouter.new
|
41
41
|
r.add('/test/:variable(.:format)').name(:my_test_path).to {|env| [200, {}, "Hey dude #{env['router.params'][:variable]}"]}
|
42
42
|
r.add('/test').redirect("http://www.google.com/")
|
43
43
|
r.add('/static').static('/my_file_system')
|
44
|
-
|
44
|
+
|
45
45
|
As well, you can support regex matching and request conditions. To add a regex match, use <tt>matching(:id => /\d+/)</tt>.
|
46
46
|
To match on a request condition you can use <tt>condition(:request_method => %w(POST HEAD))</tt> or more succinctly <tt>request_method('POST', 'HEAD')</tt>.
|
47
47
|
|
data/benchmarks/rack_mount.rb
CHANGED
@@ -28,19 +28,19 @@ RBench.run(TIMES) do
|
|
28
28
|
report "4 levels, static" do
|
29
29
|
u.call(simple2_env).first == 200 or raise
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
report "8 levels, static" do
|
33
33
|
u.call(simple3_env).first == 200 or raise
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
report "4 levels, 1 dynamic" do
|
37
37
|
u.call(simple_and_dynamic_env).first == 200 or raise
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
report "8 levels, 3 dynamic" do
|
41
41
|
u.call(simple_and_dynamic_env1).first == 200 or raise
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
report "4 levels, 1 greedy" do
|
45
45
|
u.call(simple_and_dynamic_env2).first == 200 or raise
|
46
46
|
end
|
data/http_router.gemspec
CHANGED
@@ -7,8 +7,8 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.version = HttpRouter::VERSION
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
9
|
s.authors = ["Joshua Hull"]
|
10
|
-
s.summary = "A kick-ass HTTP router for use in Rack
|
11
|
-
s.description = "This library allows you to recognize and build URLs in a Rack application.
|
10
|
+
s.summary = "A kick-ass HTTP router for use in Rack"
|
11
|
+
s.description = "This library allows you to recognize and build URLs in a Rack application."
|
12
12
|
s.email = %q{joshbuddy@gmail.com}
|
13
13
|
s.extra_rdoc_files = ['README.rdoc']
|
14
14
|
s.files = `git ls-files`.split("\n")
|
data/lib/http_router.rb
CHANGED
@@ -9,17 +9,19 @@ require 'http_router/regex_route'
|
|
9
9
|
require 'http_router/optional_compiler'
|
10
10
|
|
11
11
|
class HttpRouter
|
12
|
-
|
12
|
+
|
13
13
|
attr_reader :root, :routes, :known_methods, :named_routes
|
14
|
-
attr_accessor :default_app
|
14
|
+
attr_accessor :default_app, :url_mount
|
15
15
|
|
16
16
|
UngeneratableRouteException = Class.new(RuntimeError)
|
17
17
|
InvalidRouteException = Class.new(RuntimeError)
|
18
18
|
MissingParameterException = Class.new(RuntimeError)
|
19
19
|
|
20
|
-
def initialize(
|
20
|
+
def initialize(options = nil, &blk)
|
21
21
|
reset!
|
22
|
-
@
|
22
|
+
@options = options
|
23
|
+
@default_app = default_app || options && options[:default_app] || proc{|env| ::Rack::Response.new("Not Found", 404).finish }
|
24
|
+
@ignore_trailing_slash = options && options.key?(:ignore_trailing_slash) ? options[:ignore_trailing_slash] : true
|
23
25
|
instance_eval(&blk) if blk
|
24
26
|
end
|
25
27
|
|
@@ -30,11 +32,15 @@ class HttpRouter
|
|
30
32
|
else
|
31
33
|
Route.new(self, path, opts)
|
32
34
|
end
|
33
|
-
|
35
|
+
add_route(route)
|
34
36
|
route.to(app) if app
|
35
37
|
route
|
36
38
|
end
|
37
39
|
|
40
|
+
def add_route(route)
|
41
|
+
@routes << route
|
42
|
+
end
|
43
|
+
|
38
44
|
def add_with_request_method(path, method, opts = {}, &app)
|
39
45
|
route = add(path, opts).send(method.to_sym)
|
40
46
|
route.to(app) if app
|
@@ -68,7 +74,7 @@ class HttpRouter
|
|
68
74
|
@default_app.call(env)
|
69
75
|
end
|
70
76
|
end
|
71
|
-
|
77
|
+
|
72
78
|
def reset!
|
73
79
|
@root = Node.new(self)
|
74
80
|
@default_app = Proc.new{ |env| Rack::Response.new("Your request couldn't be found", 404).finish }
|
@@ -104,4 +110,20 @@ class HttpRouter
|
|
104
110
|
end
|
105
111
|
uri
|
106
112
|
end
|
113
|
+
|
114
|
+
# Creates a deep-copy of the router.
|
115
|
+
def clone(klass = self.class)
|
116
|
+
cloned_router = klass.new(@options)
|
117
|
+
@routes.each do |route|
|
118
|
+
new_route = route.clone(cloned_router)
|
119
|
+
cloned_router.add_route(new_route)
|
120
|
+
new_route.name(route.named) if route.named
|
121
|
+
begin
|
122
|
+
new_route.to route.dest.clone
|
123
|
+
rescue
|
124
|
+
new_route.to route.dest
|
125
|
+
end
|
126
|
+
end
|
127
|
+
cloned_router
|
128
|
+
end
|
107
129
|
end
|
data/lib/http_router/node.rb
CHANGED
@@ -29,26 +29,26 @@ class HttpRouter
|
|
29
29
|
def linear(request)
|
30
30
|
@linear && @linear.each{|n| n[request]}
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def lookup(request)
|
34
34
|
if @lookup && @lookup[request.path.first]
|
35
35
|
request = request.clone
|
36
36
|
@lookup[request.path.shift][request]
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
def variable(request)
|
41
41
|
@variable && @variable[request]
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
def glob(request)
|
45
45
|
@glob && @glob[request]
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
def request(request)
|
49
49
|
@request && @request[request]
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
def arbitrary(request)
|
53
53
|
@arbitrary && @arbitrary.each{|n| n[request]}
|
54
54
|
end
|
@@ -132,38 +132,40 @@ class HttpRouter
|
|
132
132
|
@arbitrary << Arbitrary.new(@router, allow_partial, blk, param_names)
|
133
133
|
@arbitrary.last
|
134
134
|
end
|
135
|
-
|
136
|
-
def add_match(regexp, matching_indicies = [0], priority = 0)
|
135
|
+
|
136
|
+
def add_match(regexp, matching_indicies = [0], priority = 0, splitting_indicies = nil)
|
137
|
+
add_prioritized_match(Regex.new(@router, regexp, matching_indicies, priority, splitting_indicies))
|
138
|
+
end
|
139
|
+
|
140
|
+
def add_spanning_match(regexp, matching_indicies = [0], priority = 0, splitting_indicies = nil)
|
141
|
+
add_prioritized_match(SpanningRegex.new(@router, regexp, matching_indicies, priority, splitting_indicies))
|
142
|
+
end
|
143
|
+
|
144
|
+
def add_prioritized_match(match)
|
137
145
|
@linear ||= []
|
138
|
-
if priority != 0
|
146
|
+
if match.priority != 0
|
139
147
|
@linear.each_with_index { |n, i|
|
140
|
-
if priority > (n.priority || 0)
|
141
|
-
@linear[i, 0] =
|
148
|
+
if match.priority > (n.priority || 0)
|
149
|
+
@linear[i, 0] = match
|
142
150
|
return @linear[i]
|
143
151
|
end
|
144
152
|
}
|
145
153
|
end
|
146
|
-
@linear <<
|
154
|
+
@linear << match
|
147
155
|
@linear.last
|
148
156
|
end
|
149
157
|
|
150
|
-
def add_spanning_match(regexp, matching_indicies = [0])
|
151
|
-
@linear ||= []
|
152
|
-
@linear << SpanningRegex.new(@router, regexp, matching_indicies)
|
153
|
-
@linear.last
|
154
|
-
end
|
155
|
-
|
156
158
|
def add_free_match(regexp)
|
157
159
|
@linear ||= []
|
158
160
|
@linear << FreeRegex.new(@router, regexp)
|
159
161
|
@linear.last
|
160
162
|
end
|
161
|
-
|
163
|
+
|
162
164
|
def add_destination(route)
|
163
165
|
@destination ||= []
|
164
166
|
@destination << route
|
165
167
|
end
|
166
|
-
|
168
|
+
|
167
169
|
def add_lookup(part)
|
168
170
|
@lookup ||= {}
|
169
171
|
@lookup[part] ||= Node.new(@router)
|
@@ -2,11 +2,10 @@ class HttpRouter
|
|
2
2
|
class Node
|
3
3
|
class Regex < Node
|
4
4
|
alias_method :node_lookup, :[]
|
5
|
+
attr_reader :matcher, :splitting_indicies
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
def initialize(router, matcher, capturing_indicies, priority = 0)
|
9
|
-
@router, @matcher, @capturing_indicies, @priority = router, matcher, capturing_indicies, priority
|
7
|
+
def initialize(router, matcher, capturing_indicies, priority = 0, splitting_indicies = nil)
|
8
|
+
@router, @matcher, @capturing_indicies, @priority, @splitting_indicies = router, matcher, capturing_indicies, priority, splitting_indicies
|
10
9
|
end
|
11
10
|
|
12
11
|
def [](request)
|
@@ -19,6 +18,7 @@ class HttpRouter
|
|
19
18
|
end
|
20
19
|
|
21
20
|
def add_params(request, match)
|
21
|
+
@splitting_indicies.each { |idx| request.params << unescape(match[idx]).split(/\//) } if @splitting_indicies
|
22
22
|
@capturing_indicies.each { |idx| request.params << unescape(match[idx]) }
|
23
23
|
end
|
24
24
|
end
|
@@ -22,7 +22,7 @@ class HttpRouter
|
|
22
22
|
def add_to_current_set(c)
|
23
23
|
(@start_index...@end_index).each { |path_index| @paths[path_index] << c }
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
# over current working set, double @paths
|
27
27
|
def double_paths
|
28
28
|
(@start_index...@end_index).each { |path_index| @paths << @paths[path_index].dup }
|
@@ -1,11 +1,11 @@
|
|
1
1
|
class HttpRouter
|
2
2
|
class RegexRoute < Route
|
3
3
|
def initialize(router, path, opts = {})
|
4
|
-
@router, @
|
4
|
+
@router, @original_path, @opts = router, path, opts
|
5
5
|
end
|
6
6
|
|
7
7
|
def compile
|
8
|
-
add_non_path_to_tree(@router.root.add_free_match(
|
8
|
+
add_non_path_to_tree(@router.root.add_free_match(@original_path), path, [])
|
9
9
|
@compiled = true
|
10
10
|
end
|
11
11
|
|
data/lib/http_router/request.rb
CHANGED
data/lib/http_router/route.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'url_mount'
|
2
|
+
|
1
3
|
class HttpRouter
|
2
4
|
class Route
|
3
5
|
attr_reader :default_values, :matches_with, :router, :path, :conditions
|
@@ -126,6 +128,10 @@ class HttpRouter
|
|
126
128
|
@router.append_querystring(result, extra_params)
|
127
129
|
end
|
128
130
|
|
131
|
+
def clone(new_router)
|
132
|
+
Route.new(new_router, @original_path.dup, as_options)
|
133
|
+
end
|
134
|
+
|
129
135
|
def url_with_params(*args)
|
130
136
|
options = args.last.is_a?(Hash) ? args.pop : nil
|
131
137
|
options = options.nil? ? default_values.dup : default_values.merge(options) if default_values
|
@@ -137,9 +143,8 @@ class HttpRouter
|
|
137
143
|
end
|
138
144
|
raise UngeneratableRouteException unless path
|
139
145
|
result, params = path.url(args, options)
|
140
|
-
|
141
|
-
|
142
|
-
[result, params]
|
146
|
+
mount_point = router.url_mount && router.url_mount.url(options)
|
147
|
+
mount_point ? [File.join(mount_point, result), params] : [result, params]
|
143
148
|
end
|
144
149
|
|
145
150
|
def significant_variable_names
|
@@ -203,14 +208,26 @@ class HttpRouter
|
|
203
208
|
node.add_lookup(parts[0])
|
204
209
|
end
|
205
210
|
else
|
211
|
+
capturing_indicies = []
|
212
|
+
splitting_indicies = []
|
206
213
|
captures = 0
|
207
214
|
priority = 0
|
215
|
+
spans = false
|
208
216
|
regex = parts.inject('') do |reg, part|
|
209
217
|
reg << case part[0]
|
210
218
|
when ?\\
|
211
219
|
Regexp.quote(part[1].chr)
|
212
220
|
when ?:
|
213
221
|
captures += 1
|
222
|
+
capturing_indicies << captures
|
223
|
+
name = part[1, part.size].to_sym
|
224
|
+
param_names << name
|
225
|
+
matches_with[name] = @opts[name]
|
226
|
+
"(#{(@opts[name] || '[^/]*?')})"
|
227
|
+
when ?*
|
228
|
+
spans = true
|
229
|
+
captures += 1
|
230
|
+
splitting_indicies << captures
|
214
231
|
name = part[1, part.size].to_sym
|
215
232
|
param_names << name
|
216
233
|
matches_with[name] = @opts[name]
|
@@ -220,9 +237,8 @@ class HttpRouter
|
|
220
237
|
Regexp.quote(part)
|
221
238
|
end
|
222
239
|
end
|
223
|
-
|
224
|
-
|
225
|
-
node = node.add_match(Regexp.new("#{regex}$"), capturing_indicies, priority)
|
240
|
+
node = spans ? node.add_spanning_match(Regexp.new("#{regex}$"), capturing_indicies, priority, splitting_indicies) :
|
241
|
+
node.add_match(Regexp.new("#{regex}$"), capturing_indicies, priority, splitting_indicies)
|
226
242
|
end
|
227
243
|
end
|
228
244
|
add_non_path_to_tree(node, path, param_names)
|
@@ -239,6 +255,11 @@ class HttpRouter
|
|
239
255
|
@arbitrary.each{|a| nodes.map!{|n| n.add_arbitrary(a, match_partially?, names)} } if @arbitrary
|
240
256
|
path_obj = Path.new(self, path, names)
|
241
257
|
nodes.each{|n| n.add_destination(path_obj)}
|
258
|
+
if dest.respond_to?(:url_mount=)
|
259
|
+
urlmount = UrlMount.new(@original_path, @default_values)
|
260
|
+
urlmount.url_mount = router.url_mount if router.url_mount
|
261
|
+
dest.url_mount = urlmount
|
262
|
+
end
|
242
263
|
path_obj
|
243
264
|
end
|
244
265
|
end
|
data/lib/http_router/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -29,7 +29,7 @@ class MiniTest::Unit::TestCase
|
|
29
29
|
response.last.each {|p| body << p}
|
30
30
|
assert_equal expect, body
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
def assert_header(header, response)
|
34
34
|
response = Rack::MockRequest.env_for(response) if response.is_a?(String)
|
35
35
|
response = router.call(response) if response.is_a?(Hash)
|
@@ -64,7 +64,7 @@ class MiniTest::Unit::TestCase
|
|
64
64
|
assert_equal 404, response.first
|
65
65
|
end
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
def assert_generate(path, route, *args)
|
69
69
|
if route.is_a?(String)
|
70
70
|
router.reset!
|
data/test/rack/test_route.rb
CHANGED
data/test/test_generate.rb
CHANGED
@@ -19,12 +19,12 @@ class TestGenerate < MiniTest::Unit::TestCase
|
|
19
19
|
assert_generate '/test', '/:var', :var => 'test'
|
20
20
|
assert_generate '/test', '/:var', 'test'
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def test_array_with_extras
|
24
24
|
assert_generate '/test?query=string', '/:var', :var => 'test', :query => 'string'
|
25
25
|
assert_generate '/test?query=string', '/:var', 'test', :query => 'string'
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def test_multiple_dynamics
|
29
29
|
assert_generate '/one/two', "/:var/:baz", :var => 'one', :baz => 'two'
|
30
30
|
assert_generate '/one/two', "/:var/:baz", 'one', 'two'
|
@@ -60,7 +60,7 @@ class TestGenerate < MiniTest::Unit::TestCase
|
|
60
60
|
assert_generate '/var/fooz', "/:var1(/:var2)", :var1 => 'var', :var2 => 'fooz'
|
61
61
|
assert_raises(HttpRouter::UngeneratableRouteException) { router.url(router.add("/:var1(/:var2)").to(:test), :var2 => 'fooz') }
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
def test_optionals_with_format
|
65
65
|
assert_generate '/var', "/:var1(/:var2.:format)", 'var'
|
66
66
|
assert_generate '/var/fooz.html', "/:var1(/:var2.:format)", 'var', 'fooz', 'html'
|
data/test/test_interstitial.rb
CHANGED
@@ -35,7 +35,7 @@ class TestInterstitial < MiniTest::Unit::TestCase
|
|
35
35
|
assert_route r5, '/one-value-time-one-variable', {:var1 => 'one', :var2 => 'value', :var3 => 'time', :var4 => 'one', :var5 => 'variable'}
|
36
36
|
assert_route r6, '/one-value-time-one-value-time', {:var1 => 'one', :var2 => 'value', :var3 => 'time', :var4 => 'one', :var5 => 'value', :var6 => 'time'}
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
def test_regex_with_mutliple_variables
|
40
40
|
with_regex, without_regex = router {
|
41
41
|
add("/:common_variable.:matched").matching(:matched => /\d+/)
|
data/test/test_misc.rb
CHANGED
@@ -1,30 +1,24 @@
|
|
1
1
|
class TestMisc < MiniTest::Unit::TestCase
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
# assert_equal r1.routes.size, r2.routes.size
|
25
|
-
# assert_equal '/another', r1.url(:test)
|
26
|
-
# assert_equal '/test2', r2.url(:test)
|
27
|
-
# assert_equal :test, r1.routes.first.dest
|
28
|
-
# assert_equal :test, r2.routes.first.dest
|
29
|
-
#end
|
2
|
+
def test_cloning
|
3
|
+
r1 = HttpRouter.new {
|
4
|
+
add('/test').name(:test_route).to :test
|
5
|
+
}
|
6
|
+
r2 = r1.clone
|
7
|
+
|
8
|
+
r2.add('/test2').name(:test).to(:test2)
|
9
|
+
assert_equal 2, r2.routes.size
|
10
|
+
|
11
|
+
assert_equal 404, r1.recognize(Rack::Request.new(Rack::MockRequest.env_for('/test2'))).first
|
12
|
+
assert r2.recognize(Rack::Request.new(Rack::MockRequest.env_for('/test2')))
|
13
|
+
assert_equal r1.routes.first, r1.named_routes[:test_route]
|
14
|
+
assert_equal r2.routes.first, r2.named_routes[:test_route]
|
15
|
+
|
16
|
+
r1.add('/another').name(:test).to(:test2)
|
17
|
+
|
18
|
+
assert_equal r1.routes.size, r2.routes.size
|
19
|
+
assert_equal '/another', r1.url(:test)
|
20
|
+
assert_equal '/test2', r2.url(:test)
|
21
|
+
assert_equal :test, r1.routes.first.dest
|
22
|
+
assert_equal :test, r2.routes.first.dest
|
23
|
+
end
|
30
24
|
end
|
data/test/test_mounting.rb
CHANGED
@@ -1,89 +1,83 @@
|
|
1
1
|
class TestMounting < MiniTest::Unit::TestCase
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
#
|
39
|
-
#def test_nest3
|
40
|
-
# @r3 = HttpRouter.new
|
41
|
-
# @r1.add("/foo(/:bar)").default(:bar => "barry").to(@r2)
|
42
|
-
# @r2.add("/hi").name(:hi).compile
|
43
|
-
# @r2.add("/mounted").to(@r3)
|
44
|
-
# @r3.add("/endpoint").name(:endpoint).compile
|
45
|
-
#
|
46
|
-
# assert_equal "/foo/barry/hi", @r2.url(:hi)
|
47
|
-
# assert_equal "/foo/barry/mounted/endpoint", @r3.url(:endpoint)
|
48
|
-
# assert_equal "/foo/flower/mounted/endpoint", @r3.url(:endpoint, :bar => "flower")
|
49
|
-
#end
|
50
|
-
#
|
51
|
-
#def test_with_default_host
|
52
|
-
# @r1.add("/mounted").default(:host => "example.com").to(@r2)
|
53
|
-
# assert_equal "http://example.com/mounted/bar", @r2.url(:test)
|
54
|
-
#end
|
55
|
-
#
|
56
|
-
#def test_with_host
|
57
|
-
# @r1.add("/mounted").to(@r2)
|
58
|
-
# assert_equal "/mounted/bar", @r2.url(:test)
|
59
|
-
# assert_equal "http://example.com/mounted/bar", @r2.url(:test, :host => "example.com")
|
60
|
-
#end
|
61
|
-
#
|
62
|
-
#def test_with_scheme
|
63
|
-
# @r1.add("/mounted").to(@r2)
|
64
|
-
# assert_equal "/mounted/bar", @r2.url(:test)
|
65
|
-
# assert_equal "https://example.com/mounted/bar", @r2.url(:test, :scheme => "https", :host => "example.com")
|
66
|
-
#end
|
67
|
-
#
|
68
|
-
#def test_clone
|
69
|
-
# @r3 = HttpRouter.new
|
70
|
-
# @r1.add("/first").to(@r2)
|
71
|
-
# @r2.add("/second").to(@r3)
|
72
|
-
# r1 = @r1.clone
|
73
|
-
# assert @r1.routes.first
|
74
|
-
# r2 = r1.routes.first.dest
|
75
|
-
# assert r2
|
76
|
-
# assert_equal @r1.routes.first.dest.object_id, @r2.object_id
|
77
|
-
# assert r2.object_id != @r2.object_id
|
78
|
-
# assert_equal 2, r2.routes.size
|
79
|
-
# r3 = r2.routes.last.dest
|
80
|
-
# assert_instance_of HttpRouter, r3
|
81
|
-
# assert r3.object_id != @r3.object_id
|
82
|
-
#end
|
83
|
-
end
|
2
|
+
def setup
|
3
|
+
@r1 = HttpRouter.new
|
4
|
+
@r2 = HttpRouter.new
|
5
|
+
@r2.add("/bar").name(:test).to{|env| [200, {}, []]}
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_url_mount_for_child_route
|
9
|
+
route = @r1.add("/foo").to(@r2)
|
10
|
+
assert_equal "/foo", @r2.url_mount.url
|
11
|
+
assert_equal "/foo/bar", @r2.url(:test)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_default_values
|
15
|
+
route = @r1.add("/foo/:bar").default(:bar => "baz").to(@r2)
|
16
|
+
assert_equal "/foo/baz/bar", @r2.url(:test)
|
17
|
+
assert_equal "/foo/haha/bar", @r2.url(:test, :bar => "haha")
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_multiple_values
|
21
|
+
@r1.add("/foo/:bar/:baz").default(:bar => "bar").to(@r2)
|
22
|
+
assert_equal "/foo/bar/baz/bar", @r2.url(:test, :baz => "baz")
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_bubble_params
|
26
|
+
route = @r1.add("/foo/:bar").default(:bar => "baz").to(@r2)
|
27
|
+
assert_equal "/foo/baz/bar?bang=ers", @r2.url(:test, :bang => "ers")
|
28
|
+
assert_equal "/foo/haha/bar?bang=ers", @r2.url(:test, :bar => "haha", :bang => "ers")
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_path_with_optional
|
32
|
+
@r1.add("/foo(/:bar)").to(@r2)
|
33
|
+
@r2.add("/hey(/:there)").name(:test).to{|env| [200, {}, []]}
|
34
|
+
assert_equal "/foo/hey", @r2.url(:test)
|
35
|
+
assert_equal "/foo/bar/hey", @r2.url(:test, :bar => "bar")
|
36
|
+
assert_equal "/foo/bar/hey/there", @r2.url(:test, :bar => "bar", :there => "there")
|
37
|
+
end
|
84
38
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
39
|
+
def test_nest3
|
40
|
+
@r3 = HttpRouter.new
|
41
|
+
@r1.add("/foo(/:bar)").default(:bar => "barry").to(@r2)
|
42
|
+
@r2.add("/hi").name(:hi).to{|env| [200, {}, []]}
|
43
|
+
@r2.add("/mounted").to(@r3)
|
44
|
+
@r3.add("/endpoint").name(:endpoint).to{|env| [200, {}, []]}
|
45
|
+
|
46
|
+
assert_equal "/foo/barry/hi", @r2.url(:hi)
|
47
|
+
assert_equal "/foo/barry/mounted/endpoint", @r3.url(:endpoint)
|
48
|
+
assert_equal "/foo/flower/mounted/endpoint", @r3.url(:endpoint, :bar => "flower")
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_with_default_host
|
52
|
+
@r1.add("/mounted").default(:host => "example.com").to(@r2)
|
53
|
+
assert_equal "http://example.com/mounted/bar", @r2.url(:test)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_with_host
|
57
|
+
@r1.add("/mounted").to(@r2)
|
58
|
+
assert_equal "/mounted/bar", @r2.url(:test)
|
59
|
+
assert_equal "http://example.com/mounted/bar", @r2.url(:test, :host => "example.com")
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_with_scheme
|
63
|
+
@r1.add("/mounted").to(@r2)
|
64
|
+
assert_equal "/mounted/bar", @r2.url(:test)
|
65
|
+
assert_equal "https://example.com/mounted/bar", @r2.url(:test, :scheme => "https", :host => "example.com")
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_clone
|
69
|
+
@r3 = HttpRouter.new
|
70
|
+
@r1.add("/first").to(@r2)
|
71
|
+
@r2.add("/second").to(@r3)
|
72
|
+
r1 = @r1.clone
|
73
|
+
assert @r1.routes.first
|
74
|
+
r2 = r1.routes.first.dest
|
75
|
+
assert r2
|
76
|
+
assert_equal @r1.routes.first.dest.object_id, @r2.object_id
|
77
|
+
assert r2.object_id != @r2.object_id
|
78
|
+
assert_equal 2, r2.routes.size
|
79
|
+
r3 = r2.routes.last.dest
|
80
|
+
assert_instance_of HttpRouter, r3
|
81
|
+
assert r3.object_id != @r3.object_id
|
82
|
+
end
|
83
|
+
end
|
data/test/test_recognize.rb
CHANGED
@@ -40,7 +40,7 @@ class TestRecognition < MiniTest::Unit::TestCase
|
|
40
40
|
assert_body '/optional', router.call(Rack::MockRequest.env_for('/test/optional'))
|
41
41
|
assert_body '/', router.call(Rack::MockRequest.env_for('/test'))
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
def test_partial_root
|
45
45
|
router.add("/*").to { |env| Rack::Response.new(env['PATH_INFO']).finish }
|
46
46
|
assert_body '/optional', router.call(Rack::MockRequest.env_for('/optional'))
|
data/test/test_request.rb
CHANGED
@@ -83,7 +83,7 @@ class TestRequest < MiniTest::Unit::TestCase
|
|
83
83
|
}
|
84
84
|
assert_route router.add("/test").host('host2'), Rack::MockRequest.env_for('http://host2/test', :method => 'POST')
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
def test_match_on_scheme
|
88
88
|
http, https = router { get("/test").scheme('http'); get("/test").scheme('https') }
|
89
89
|
assert_status 405, Rack::MockRequest.env_for('https://example.org/test', :method => 'POST')
|
data/test/test_variable.rb
CHANGED
@@ -19,7 +19,7 @@ class TestVariable < MiniTest::Unit::TestCase
|
|
19
19
|
assert_route static, '/one'
|
20
20
|
assert_route nil, '/two'
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def test_variable_and_static
|
24
24
|
dynamic, static = router {
|
25
25
|
add("/foo/:id")
|
@@ -83,13 +83,25 @@ class TestVariable < MiniTest::Unit::TestCase
|
|
83
83
|
def test_glob_with_static
|
84
84
|
assert_route '/test/*variable/test', '/test/one/two/three/test', {:variable => ['one', 'two', 'three']}
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
|
+
def test_glob_with_variable
|
88
|
+
assert_route '/test/*variable/:test', '/test/one/two/three', {:variable => ['one', 'two'], :test => 'three'}
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_glob_with_format
|
92
|
+
assert_route '/test/*variable.:format', 'test/one/two/three.html', {:variable => ['one', 'two', 'three'], :format => 'html'}
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_glob_with_literal
|
96
|
+
assert_route '/test/*variable.html', 'test/one/two/three.html', {:variable => ['one', 'two', 'three']}
|
97
|
+
end
|
98
|
+
|
87
99
|
def test_glob_with_regex
|
88
100
|
r = router { add('/test/*variable/anymore')}
|
89
101
|
assert_route r, '/test/123/345/567/anymore', {:variable => ['123', '345', '567']}
|
90
102
|
assert_route nil, '/test/123/345/567'
|
91
103
|
end
|
92
|
-
|
104
|
+
|
93
105
|
def test_regex_and_greedy
|
94
106
|
with_regex, without_regex = router {
|
95
107
|
add("/:common_variable/:matched").matching(:matched => /\d+/)
|
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: 1
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 6
|
9
|
-
-
|
10
|
-
version: 0.6.
|
9
|
+
- 3
|
10
|
+
version: 0.6.3
|
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: 2011-03-
|
18
|
+
date: 2011-03-22 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -138,7 +138,7 @@ dependencies:
|
|
138
138
|
version: 1.0.0
|
139
139
|
type: :development
|
140
140
|
version_requirements: *id008
|
141
|
-
description: This library allows you to recognize and build URLs in a Rack application.
|
141
|
+
description: This library allows you to recognize and build URLs in a Rack application.
|
142
142
|
email: joshbuddy@gmail.com
|
143
143
|
executables: []
|
144
144
|
|
@@ -236,6 +236,6 @@ rubyforge_project: http_router
|
|
236
236
|
rubygems_version: 1.3.7
|
237
237
|
signing_key:
|
238
238
|
specification_version: 3
|
239
|
-
summary: A kick-ass HTTP router for use in Rack
|
239
|
+
summary: A kick-ass HTTP router for use in Rack
|
240
240
|
test_files: []
|
241
241
|
|