http_router 0.6.2 → 0.6.3

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/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 compatibility.
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
 
@@ -42,6 +42,6 @@ simple_and_dynamic_env = Rack::MockRequest.env_for('/dynamic/anything')
42
42
  report "4 levels, 1 dynamic" do
43
43
  set.url(simple_env, :variable, {:variable => 'onemore'})
44
44
  end
45
-
45
+
46
46
  end
47
47
  end
@@ -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 & Sinatra"
11
- s.description = "This library allows you to recognize and build URLs in a Rack application. As well it contains an interface for use within Sinatra."
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(opts = nil, &blk)
20
+ def initialize(options = nil, &blk)
21
21
  reset!
22
- @ignore_trailing_slash = opts && opts.key?(:ignore_trailing_slash) ? opts[:ignore_trailing_slash] : true
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
- @routes << route
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
@@ -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] = Regex.new(@router, regexp, matching_indicies, priority)
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 << Regex.new(@router, regexp, matching_indicies, priority)
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
- attr_reader :matcher
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, @path, @opts = router, path, opts
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(path), path, [])
8
+ add_non_path_to_tree(@router.root.add_free_match(@original_path), path, [])
9
9
  @compiled = true
10
10
  end
11
11
 
@@ -21,7 +21,7 @@ class HttpRouter
21
21
  def to_s
22
22
  "request path, #{path.inspect}"
23
23
  end
24
-
24
+
25
25
  def clone
26
26
  dup_obj = super
27
27
  dup_obj.path = path.dup
@@ -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
- #mount_point = router.url_mount && router.url_mount.url(options)
141
- #mount_point ? [File.join(mount_point, result), params] : [result, params]
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
- capturing_indicies = []
224
- captures.times {|i| capturing_indicies << i + 1}
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
@@ -1,4 +1,4 @@
1
1
  # encoding: utf-8
2
2
  class HttpRouter #:nodoc
3
- VERSION = '0.6.2'
3
+ VERSION = '0.6.3'
4
4
  end
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!
@@ -1,5 +1,5 @@
1
1
  class TestRouteExtensions < MiniTest::Unit::TestCase
2
-
2
+
3
3
  def test_redirect
4
4
  router.get("/index.html").redirect("/")
5
5
  response = router.call(Rack::MockRequest.env_for("/index.html"))
@@ -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'
@@ -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
- #def test_exceptions
3
- # assert_raises(HttpRouter::AmbiguousRouteException) {HttpRouter.new.add("/:var1(/:var2)(/:var3)").compile}
4
- # assert_raises(HttpRouter::AmbiguousVariableException) {HttpRouter.new.add("/:var1(/:var1)(/:var1)").compile}
5
- # assert_raises(HttpRouter::UnsupportedRequestConditionError) {HttpRouter.new.add("/").condition(:flibberty => 'gibet').compile}
6
- #end
7
- #
8
- #def test_cloning
9
- # r1 = HttpRouter.new {
10
- # add('/test').name(:test_route).to :test
11
- # }
12
- # r2 = r1.clone
13
- #
14
- # r2.add('/test2').name(:test).to(:test2)
15
- # assert_equal 2, r2.routes.size
16
- #
17
- # assert r1.recognize(Rack::Request.new(Rack::MockRequest.env_for('/test2'))).nil?
18
- # assert !r2.recognize(Rack::Request.new(Rack::MockRequest.env_for('/test2'))).nil?
19
- # assert_equal r1.routes.first, r1.named_routes[:test_route]
20
- # assert_equal r2.routes.first, r2.named_routes[:test_route]
21
- #
22
- # r1.add('/another').name(:test).to(:test2)
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
@@ -1,89 +1,83 @@
1
1
  class TestMounting < MiniTest::Unit::TestCase
2
- #def setup
3
- # @r1 = HttpRouter.new
4
- # @r2 = HttpRouter.new
5
- # @r2.add("/bar").name(:test).compile
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).compile
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
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
- # it "should clone my nested structure" do
86
- # end
87
- # end
88
- # end
89
- #end
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
@@ -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')
@@ -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: 3
4
+ hash: 1
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 6
9
- - 2
10
- version: 0.6.2
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-21 00:00:00 -07:00
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. As well it contains an interface for use within Sinatra.
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 & Sinatra
239
+ summary: A kick-ass HTTP router for use in Rack
240
240
  test_files: []
241
241