http_router 0.2.3 → 0.2.4

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/.gitignore CHANGED
@@ -1 +1,4 @@
1
1
  pkg
2
+ *.gem
3
+ .bundle
4
+ rdoc
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source :rubygems
2
+
3
+ gem 'rack', '>=1.0'
4
+ gem 'url_mount', '>=0.2.1'
5
+
6
+ group :development do
7
+ gem 'rspec'
8
+ gem 'rake'
9
+ gem 'sinatra'
10
+ gem 'rbench'
11
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,43 @@
1
+ ---
2
+ dependencies:
3
+ rake:
4
+ group:
5
+ - :development
6
+ version: ">= 0"
7
+ url_mount:
8
+ group:
9
+ - :default
10
+ version: ">= 0.2.1"
11
+ rspec:
12
+ group:
13
+ - :development
14
+ version: ">= 0"
15
+ rack:
16
+ group:
17
+ - :default
18
+ version: ">= 1.0"
19
+ sinatra:
20
+ group:
21
+ - :development
22
+ version: ">= 0"
23
+ rbench:
24
+ group:
25
+ - :development
26
+ version: ">= 0"
27
+ specs:
28
+ - rake:
29
+ version: 0.8.7
30
+ - rack:
31
+ version: 1.1.0
32
+ - rbench:
33
+ version: 0.2.3
34
+ - rspec:
35
+ version: 1.3.0
36
+ - sinatra:
37
+ version: "1.0"
38
+ - url_mount:
39
+ version: 0.2.1
40
+ hash: 31358295b6fc19c69280f917c4fa3db0d1a7d48d
41
+ sources:
42
+ - Rubygems:
43
+ uri: http://gemcutter.org
data/Rakefile CHANGED
@@ -1,11 +1,8 @@
1
+ require 'rubygems'
1
2
  require 'spec'
2
3
  require 'spec/rake/spectask'
3
4
  Spec::Rake::SpecTask.new(:spec) do |t|
4
5
  t.spec_opts ||= []
5
- t.ruby_opts << "-rrubygems"
6
- t.ruby_opts << "-Ilib"
7
- t.ruby_opts << "-rhttp_router"
8
- t.ruby_opts << "-rspec/spec_helper"
9
6
  t.spec_opts << "--options" << "spec/spec.opts"
10
7
  t.spec_files = FileList['spec/**/*_spec.rb']
11
8
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.3
1
+ 0.2.4
data/http_router.gemspec CHANGED
@@ -21,7 +21,8 @@ Gem::Specification.new do |s|
21
21
  s.test_files = `git ls-files spec`.split("\n")
22
22
 
23
23
  # dependencies
24
- s.add_dependency "rack", ">= 1.0.0"
24
+ s.add_dependency "rack", ">= 1.0.0"
25
+ s.add_dependency "url_mount", ">=0.2"
25
26
 
26
27
  if s.respond_to? :specification_version then
27
28
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
@@ -1,13 +1,13 @@
1
1
  class HttpRouter
2
2
  class Glob < Variable
3
- def matches?(parts, whole_path)
4
- @matches_with.nil? or (!parts.empty? and match = @matches_with.match(parts.first) and match.begin(0))
3
+ def matches?(parts)
4
+ @matches_with.nil? or (!parts.empty? and match = @matches_with.match(parts.first) and match.begin(0)) ? match : nil
5
5
  end
6
6
 
7
- def consume(parts, whole_path)
7
+ def consume(match, parts)
8
8
  if @matches_with
9
9
  params = [parts.shift]
10
- params << parts.shift while matches?(parts, whole_path)
10
+ params << parts.shift while matches?(parts)
11
11
  params
12
12
  else
13
13
  params = parts.dup
@@ -139,7 +139,6 @@ class HttpRouter
139
139
 
140
140
  def find_on_parts(request, parts, params)
141
141
  if parts and !parts.empty?
142
- whole_path = parts.join('/')
143
142
  if parts.size == 1 and parts.first == ''
144
143
  potential_match = find_on_parts(request, [], params)
145
144
  if potential_match and (router.ignore_trailing_slash? or potential_match.value && potential_match.value.route.trailing_slash_ignore?)
@@ -151,12 +150,12 @@ class HttpRouter
151
150
  response = nil
152
151
  dupped_parts = nil
153
152
  next_node = @linear.find do |(tester, node)|
154
- if tester.respond_to?(:matches?) and tester.matches?(parts, whole_path)
153
+ if tester.respond_to?(:matches?) and match = tester.matches?(parts)
155
154
  dupped_parts = parts.dup
156
- params << tester.consume(dupped_parts, whole_path)
155
+ params << tester.consume(match, dupped_parts)
157
156
  parts.replace(dupped_parts) if response = node.find_on_parts(request, dupped_parts, params)
158
- elsif tester.respond_to?(:match) and match = tester.match(whole_path) and match.begin(0) == 0
159
- dupped_parts = router.split(whole_path[match[0].size, whole_path.size])
157
+ elsif tester.respond_to?(:match) and match = tester.match(parts.whole_path) and match.begin(0) == 0
158
+ dupped_parts = router.split(parts.whole_path[match[0].size, parts.whole_path.size])
160
159
  parts.replace(dupped_parts) if response = node.find_on_parts(request, dupped_parts, params)
161
160
  else
162
161
  nil
@@ -168,7 +167,7 @@ class HttpRouter
168
167
  parts.shift
169
168
  return match.find_on_parts(request, parts, params)
170
169
  elsif @catchall
171
- params << @catchall.variable.consume(parts, whole_path)
170
+ params << @catchall.variable.consume(nil, parts)
172
171
  return @catchall.find_on_parts(request, parts, params)
173
172
  end
174
173
  end
@@ -0,0 +1,21 @@
1
+ class HttpRouter
2
+ class Parts < Array
3
+ def initialize(path)
4
+ super((path[0] == ?/ ? path[1, path.size] : path).split('/'))
5
+ end
6
+
7
+ def whole_path
8
+ @whole_path ||= join('/')
9
+ end
10
+
11
+ def shift
12
+ @whole_path = nil
13
+ super
14
+ end
15
+
16
+ def replace(ary)
17
+ @whole_path = nil
18
+ super
19
+ end
20
+ end
21
+ end
@@ -1,4 +1,3 @@
1
- require 'cgi'
2
1
  class HttpRouter
3
2
  class Path
4
3
  attr_reader :parts, :route
@@ -58,9 +57,9 @@ class HttpRouter
58
57
  params.each do |k,v|
59
58
  case v
60
59
  when Array
61
- v.each { |v_part| uri << '&' << CGI.escape(k.to_s) << '%5B%5D=' << CGI.escape(v_part.to_s) }
60
+ v.each { |v_part| uri << '&' << Rack::Utils.escape(k.to_s) << '%5B%5D=' << Rack::Utils.escape(v_part.to_s) }
62
61
  else
63
- uri << '&' << CGI.escape(k.to_s) << '=' << CGI.escape(v.to_s)
62
+ uri << '&' << Rack::Utils.escape(k.to_s) << '=' << Rack::Utils.escape(v.to_s)
64
63
  end
65
64
  end
66
65
  uri[uri_size] = ??
@@ -30,8 +30,8 @@ class HttpRouter
30
30
  end
31
31
 
32
32
  # Creates a deep uncompiled copy of this route.
33
- def clone
34
- Route.new(@router, @original_path.dup).with_options(as_options)
33
+ def clone(new_router)
34
+ Route.new(new_router, @original_path.dup).with_options(as_options)
35
35
  end
36
36
 
37
37
  # Uses an option hash to apply conditions to a Route.
@@ -75,27 +75,27 @@ class HttpRouter
75
75
  def get
76
76
  request_method('GET')
77
77
  end
78
-
78
+
79
79
  # Causes this route to recognize the POST request method. Returns +self+.
80
80
  def post
81
81
  request_method('POST')
82
82
  end
83
-
83
+
84
84
  # Causes this route to recognize the HEAD request method. Returns +self+.
85
85
  def head
86
86
  request_method('HEAD')
87
87
  end
88
-
88
+
89
89
  # Causes this route to recognize the PUT request method. Returns +self+.
90
90
  def put
91
91
  request_method('PUT')
92
92
  end
93
-
93
+
94
94
  # Causes this route to recognize the DELETE request method. Returns +self+.
95
95
  def delete
96
96
  request_method('DELETE')
97
97
  end
98
-
98
+
99
99
  # Sets a request condition for the route
100
100
  # Returns +self+.
101
101
  #
@@ -147,6 +147,11 @@ class HttpRouter
147
147
  def to(dest = nil, &block)
148
148
  compile
149
149
  @dest = dest || block
150
+ if @dest.respond_to?(:url_mount=)
151
+ urlmount = UrlMount.new(@original_path, @default_values)
152
+ urlmount.url_mount = router.url_mount if router.url_mount
153
+ @dest.url_mount = urlmount
154
+ end
150
155
  self
151
156
  end
152
157
 
@@ -161,12 +166,12 @@ class HttpRouter
161
166
  @arbitrary << (proc || block)
162
167
  self
163
168
  end
164
-
169
+
165
170
  # Compile state for route. Returns +true+ or +false+.
166
171
  def compiled?
167
172
  !@paths.nil?
168
173
  end
169
-
174
+
170
175
  # Compiles the route and inserts it into the tree. This is called automatically when you add a destination via #to to the route. Until a route
171
176
  # is compiled, it will not be recognized.
172
177
  def compile
@@ -189,7 +194,7 @@ class HttpRouter
189
194
  end
190
195
  self
191
196
  end
192
-
197
+
193
198
  # Sets the destination of this route to redirect to an arbitrary URL.
194
199
  def redirect(path, status = 302)
195
200
  raise(ArgumentError, "Status has to be an integer between 300 and 399") unless (300..399).include?(status)
@@ -201,7 +206,7 @@ class HttpRouter
201
206
  }
202
207
  self
203
208
  end
204
-
209
+
205
210
  # Sets the destination of this route to serve static files from either a directory or a single file.
206
211
  def static(root)
207
212
  if File.directory?(root)
@@ -233,11 +238,18 @@ class HttpRouter
233
238
  matching_path(args, options)
234
239
  end
235
240
  raise UngeneratableRouteException.new unless path
236
- path.url(args, options)
241
+
242
+ mount_point = nil
243
+ if !router.url_mount.nil?
244
+ mount_point = router.url_mount.url(options)
245
+ end
246
+
247
+ result = path.url(args, options)
248
+ mount_point.nil? ? result : File.join(mount_point, result)
237
249
  end
238
250
 
239
251
  private
240
-
252
+
241
253
  attr_reader :router
242
254
 
243
255
  def matching_path(params, other_hash = nil)
@@ -246,7 +258,7 @@ class HttpRouter
246
258
  else
247
259
  if params.is_a?(Array)
248
260
  significant_keys = other_hash && significant_variable_names & other_hash.keys
249
- @paths.find { |path|
261
+ @paths.find { |path|
250
262
  var_count = significant_keys ? params.size + significant_keys.size : params.size
251
263
  path.variables.size == var_count
252
264
  }
@@ -262,7 +274,7 @@ class HttpRouter
262
274
  end
263
275
  end
264
276
  end
265
-
277
+
266
278
  def extract_partial_match(path)
267
279
  path[-1] == ?* && path.slice!(-1)
268
280
  end
@@ -8,14 +8,13 @@ class HttpRouter
8
8
  @matches_with = matches_with
9
9
  end
10
10
 
11
- def matches?(parts, whole_path)
12
- @matches_with.nil? or (@matches_with and match = @matches_with.match(whole_path) and match.begin(0) == 0)
11
+ def matches?(parts)
12
+ @matches_with.nil? or (@matches_with and match = @matches_with.match(parts.whole_path) and match.begin(0) == 0) ? match : nil
13
13
  end
14
14
 
15
- def consume(parts, whole_path)
15
+ def consume(match, parts)
16
16
  if @matches_with
17
- match = @matches_with.match(whole_path)
18
- parts.replace(router.split(whole_path[match.end(0), whole_path.size]))
17
+ parts.replace(router.split(parts.whole_path[match.end(0), parts.whole_path.size]))
19
18
  match[0]
20
19
  else
21
20
  parts.shift
data/lib/http_router.rb CHANGED
@@ -1,5 +1,7 @@
1
- $LOAD_PATH << File.dirname(__FILE__)
1
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__))
2
+
2
3
  require 'rack'
4
+ require 'url_mount'
3
5
  require 'ext/rack/uri_escape'
4
6
  require 'http_router/node'
5
7
  require 'http_router/root'
@@ -9,6 +11,7 @@ require 'http_router/route'
9
11
  require 'http_router/response'
10
12
  require 'http_router/path'
11
13
  require 'http_router/optional_compiler'
14
+ require 'http_router/parts'
12
15
 
13
16
  class HttpRouter
14
17
  # Raised when a Route is not able to be generated.
@@ -29,6 +32,7 @@ class HttpRouter
29
32
  AmbiguousVariableException = Class.new(RuntimeError)
30
33
 
31
34
  attr_reader :named_routes, :routes, :root
35
+ attr_accessor :url_mount
32
36
 
33
37
  # Monkey-patches Rack::Builder to use HttpRouter.
34
38
  # See examples/rack_mapper.rb
@@ -83,7 +87,7 @@ class HttpRouter
83
87
  def default(app)
84
88
  @default_app = app
85
89
  end
86
-
90
+
87
91
  # Adds a path to be recognized.
88
92
  #
89
93
  # To assign a part of the path to a specific variable, use :variable_name within the route.
@@ -93,7 +97,7 @@ class HttpRouter
93
97
  # For example, <tt>add('/path/*id')</tt> would match <tt>/path/123/456/789</tt>, with the variable <tt>:id</tt> having the value <tt>["123", "456", "789"]</tt>.
94
98
  #
95
99
  # As well, paths can end with two optional parts, <tt>*</tt> and <tt>/?</tt>. If it ends with a <tt>*</tt>, it will match partially, returning the part of the path unmatched in the PATH_INFO value of the env. The part matched to will be returned in the SCRIPT_NAME. If it ends with <tt>/?</tt>, then a trailing / on the path will be optionally matched for that specific route. As trailing /'s are ignored by default, you probably don't actually want to use this option that frequently.
96
- #
100
+ #
97
101
  # Routes can also contain optional parts. There are surrounded with <tt>( )</tt>'s. If you need to match on a bracket in the route itself, you can escape the parentheses with a backslash.
98
102
  #
99
103
  # The second argument, options, is an optional hash that can modify the route in further ways. See HttpRouter::Route#with_options for details. Typically, you want to add further options to the route by calling additional methods on it. See HttpRouter::Route for further details.
@@ -144,7 +148,7 @@ class HttpRouter
144
148
 
145
149
  # Generate a URL for a specified route. This will accept a list of variable values plus any other variable names named as a hash.
146
150
  # This first value must be either the Route object or the name of the route.
147
- #
151
+ #
148
152
  # Example:
149
153
  # router = HttpRouter.new
150
154
  # router.add('/:foo.:format).name(:test).compile
@@ -167,7 +171,7 @@ class HttpRouter
167
171
  end
168
172
  end
169
173
 
170
- # Rack compatible #call. If matching route is found, and +dest+ value responds to #call, processing will pass to the matched route. Otherwise,
174
+ # Rack compatible #call. If matching route is found, and +dest+ value responds to #call, processing will pass to the matched route. Otherwise,
171
175
  # the default application will be called. The router will be available in the env under the key <tt>router</tt>. And parameters matched will
172
176
  # be available under the key <tt>router.params</tt>. The HttpRouter::Response object will be available under the key <tt>router.response</tt> if
173
177
  # a response is available.
@@ -192,7 +196,7 @@ class HttpRouter
192
196
  @default_app.call(env)
193
197
  end
194
198
  end
195
-
199
+
196
200
  # Returns a new node
197
201
  def node(*args)
198
202
  Node.new(self, *args)
@@ -211,7 +215,7 @@ class HttpRouter
211
215
  def variable(*args)
212
216
  Variable.new(self, *args)
213
217
  end
214
-
218
+
215
219
  # Returns a new glob
216
220
  def glob(*args)
217
221
  Glob.new(self, *args)
@@ -219,16 +223,25 @@ class HttpRouter
219
223
 
220
224
  # Creates a deep-copy of the router.
221
225
  def clone
222
- cloned_router = HttpRouter.new(@default_app, @options, &@init_block)
226
+ cloned_router = HttpRouter.new(@default_app, @options)
223
227
  @routes.each do |route|
224
- new_route = route.clone
225
- new_route.instance_variable_set(:@router, cloned_router)
228
+ new_route = route.clone(cloned_router)
229
+ cloned_router.add_route(new_route).compile
230
+ new_route.name(route.named) if route.named
231
+
232
+ if route.dest
233
+ begin
234
+ new_route.to route.dest.clone
235
+ rescue
236
+ new_route.to route.dest
237
+ end
238
+ end
226
239
  end
227
240
  cloned_router
228
241
  end
229
242
 
230
243
  def split(path)
231
- (path[0] == ?/ ? path[1, path.size] : path).split('/')
244
+ Parts.new(path)
232
245
  end
233
246
 
234
247
  private
@@ -1,3 +1,4 @@
1
+ require 'spec_helper'
1
2
  describe "HttpRouter#generate" do
2
3
  before(:each) do
3
4
  @router = HttpRouter.new
@@ -32,7 +33,7 @@ describe "HttpRouter#generate" do
32
33
  @router.add("/:var").name(:test).compile
33
34
  @router.url(:test, 'test', :query => 'string').should == '/test?query=string'
34
35
  end
35
-
36
+
36
37
  it "should generate with multiple dynamics" do
37
38
  @router.add("/:var/:baz").name(:test).compile
38
39
  @router.url(:test, 'one', 'two').should == '/one/two'
@@ -49,7 +50,7 @@ describe "HttpRouter#generate" do
49
50
  @router.add("/test.:format").name(:test).compile
50
51
  @router.url(:test, :format => 'html').should == '/test.html'
51
52
  end
52
-
53
+
53
54
  it "should generate with format as a symbol" do
54
55
  @router.add("/test.:format").name(:test).compile
55
56
  @router.url(:test, :format => :html).should == '/test.html'
@@ -60,24 +61,24 @@ describe "HttpRouter#generate" do
60
61
  @router.url(:test, 'html').should == '/test.html'
61
62
  @router.url(:test).should == '/test'
62
63
  end
63
-
64
+
64
65
  it "should generate a dynamic path and a format" do
65
66
  @router.add("/:var1.:format").name(:test).compile
66
67
  @router.url(:test, 'var', :format => 'html').should == '/var.html'
67
68
  end
68
-
69
+
69
70
  it "should generate a dynamic path and an optional format" do
70
71
  @router.add("/:var1(.:format)").name(:test).compile
71
72
  @router.url(:test, 'var').should == '/var'
72
73
  @router.url(:test, 'var', :format => 'html').should == '/var.html'
73
74
  end
74
-
75
+
75
76
  it "should generate multiple dynamics and a format" do
76
77
  @router.add("/:foo/:bar.:format").name(:test).compile
77
78
  @router.url(:test, 'var', 'baz', 'html').should == '/var/baz.html'
78
79
  @router.url(:test, :foo => 'var', :bar => 'baz', :format => 'html').should == '/var/baz.html'
79
80
  end
80
-
81
+
81
82
  it "should generate multiple dynamics and an optional format" do
82
83
  @router.add("/:foo/:bar(.:format)").name(:test).compile
83
84
  @router.url(:test, 'var', 'baz').should == '/var/baz'
@@ -137,5 +138,90 @@ describe "HttpRouter#generate" do
137
138
  end
138
139
  end
139
140
 
141
+ context "url mounting" do
142
+ context "nested routes" do
143
+ before(:each) do
144
+ @r1 = HttpRouter.new
145
+ @r2 = HttpRouter.new
146
+ @r2.add("/bar").name(:test).compile
147
+ end
148
+
149
+ it "should set the url mount on a child route" do
150
+ route = @r1.add("/foo").to(@r2)
151
+ @r2.url_mount.url.should == "/foo"
152
+ @r2.url(:test).should == "/foo/bar"
153
+ end
154
+
155
+ it "should set any default values on the url mount" do
156
+ route = @r1.add("/foo/:bar").default(:bar => "baz").to(@r2)
157
+ @r2.url(:test).should == "/foo/baz/bar"
158
+ @r2.url(:test, :bar => "haha").should == "/foo/haha/bar"
159
+ end
160
+
161
+ it "should use multiple variables" do
162
+ @r1.add("/foo/:bar/:baz").default(:bar => "bar").to(@r2)
163
+ @r2.url(:test, :baz => "baz").should == "/foo/bar/baz/bar"
164
+ end
165
+
166
+ it "should not steal parameters from the defaults it doesn't need" do
167
+ route = @r1.add("/foo/:bar").default(:bar => "baz").to(@r2)
168
+ @r2.url(:test, :bang => "ers").should == "/foo/baz/bar?bang=ers"
169
+ @r2.url(:test, :bar => "haha", :bang => "ers").should == "/foo/haha/bar?bang=ers"
170
+ end
171
+
172
+ it "should generate on a path with an optional variable" do
173
+ @r1.add("/foo(/:bar)").to(@r2)
174
+ @r2.add("/hey(/:there)").name(:test).compile
175
+ @r2.url(:test).should == "/foo/hey"
176
+ @r2.url(:test, :bar => "bar").should == "/foo/bar/hey"
177
+ @r2.url(:test, :bar => "bar", :there => "there").should == "/foo/bar/hey/there"
178
+ end
179
+
180
+ it "should nest 3 times deeply" do
181
+ @r3 = HttpRouter.new
182
+ @r1.add("/foo(/:bar)").default(:bar => "barry").to(@r2)
183
+ @r2.add("/hi").name(:hi).compile
184
+ @r2.add("/mounted").to(@r3)
185
+ @r3.add("/endpoint").name(:endpoint).compile
186
+
187
+ @r2.url(:hi).should == "/foo/barry/hi"
188
+ @r3.url(:endpoint).should == "/foo/barry/mounted/endpoint"
189
+ @r3.url(:endpoint, :bar => "flower").should == "/foo/flower/mounted/endpoint"
190
+ end
191
+
192
+ it "should allow me to set the host via a default" do
193
+ @r1.add("/mounted").default(:host => "example.com").to(@r2)
194
+ @r2.url(:test).should == "http://example.com/mounted/bar"
195
+ end
196
+
197
+ it "should allow me to set the host via an option" do
198
+ @r1.add("/mounted").to(@r2)
199
+ @r2.url(:test).should == "/mounted/bar"
200
+ @r2.url(:test, :host => "example.com").should == "http://example.com/mounted/bar"
201
+ end
202
+
203
+ it "should allow me to set the scheme via an option" do
204
+ @r1.add("/mounted").to(@r2)
205
+ @r2.url(:test).should == "/mounted/bar"
206
+ @r2.url(:test, :scheme => "https", :host => "example.com").should == "https://example.com/mounted/bar"
207
+ end
208
+
209
+ it "should clone my nested structure" do
210
+ @r3 = HttpRouter.new
211
+ @r1.add("/first").to(@r2)
212
+ @r2.add("/second").to(@r3)
213
+ r1 = @r1.clone
214
+ @r1.routes.first.should_not be_nil
215
+ r2 = r1.routes.first.dest
216
+ r2.should_not be_nil
217
+ @r1.routes.first.dest.object_id.should == @r2.object_id
218
+ r2.object_id.should_not == @r2.object_id
219
+ r2.routes.should have(2).route
220
+ r3 = r2.routes.last.dest
221
+ r3.should be_an_instance_of(HttpRouter)
222
+ r3.object_id.should_not == @r3.object_id
223
+ end
224
+ end
225
+ end
140
226
  end
141
227
  end
data/spec/misc_spec.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'spec_helper'
1
2
  describe "HttpRouter" do
2
3
  before(:each) do
3
4
  @router = HttpRouter.new
@@ -43,17 +44,17 @@ describe "HttpRouter" do
43
44
  add('/test').name(:test_route).to :test
44
45
  }
45
46
  r2 = r1.clone
46
-
47
+
47
48
  r2.add('/test2').name(:test).to(:test2)
48
49
  r2.routes.size.should == 2
49
-
50
+
50
51
  r1.recognize(Rack::MockRequest.env_for('/test2')).should be_nil
51
52
  r2.recognize(Rack::MockRequest.env_for('/test2')).should_not be_nil
52
53
  r1.named_routes[:test_route].should == r1.routes.first
53
54
  r2.named_routes[:test_route].should == r2.routes.first
54
55
 
55
56
  r1.add('/another').name(:test).to(:test2)
56
-
57
+
57
58
  r1.routes.size.should == r2.routes.size
58
59
  r1.url(:test).should == '/another'
59
60
  r2.url(:test).should == '/test2'
@@ -61,4 +62,4 @@ describe "HttpRouter" do
61
62
  r2.routes.first.dest.should == :test
62
63
  end
63
64
  end
64
- end
65
+ end
@@ -0,0 +1,5 @@
1
+ describe "mounting" do
2
+ before(:each) do
3
+ @router = HttpRouter.new
4
+ end
5
+ end
@@ -1,6 +1,3 @@
1
- route_set = HttpRouter.new
2
- route_set.extend(CallWithMockRequestMixin)
3
-
4
1
  describe "HttpRouter route dispatching with redirect_on_trailing_delimiters" do
5
2
  before(:each) do
6
3
  @route_set = HttpRouter.new(:redirect_trailing_slash => true)
@@ -18,78 +15,79 @@ end
18
15
 
19
16
  describe "HttpRouter route dispatching" do
20
17
  before(:each) do
21
- route_set.reset!
18
+ @route_set = HttpRouter.new(:redirect_trailing_slash => true)
19
+ @route_set.extend(CallWithMockRequestMixin)
22
20
  @app = MockApp.new("Hello World!")
23
21
  end
24
22
 
25
23
  describe "HTTP GET" do
26
24
  before(:each) do
27
- route_set.reset!
28
- route_set.add('/sample').request_method('GET').to(@app)
25
+ @route_set.reset!
26
+ @route_set.add('/sample').request_method('GET').to(@app)
29
27
  end
30
28
 
31
29
  it "should dispatch a request" do
32
- response = route_set.call_with_mock_request
30
+ response = @route_set.call_with_mock_request
33
31
  response.body.should eql("Hello World!")
34
32
  end
35
33
 
36
34
  it "should write router.params" do
37
- response = route_set.call_with_mock_request
35
+ response = @route_set.call_with_mock_request
38
36
  @app.env["router.params"].should == {}
39
37
  end
40
38
  end
41
39
 
42
40
  describe "HTTP POST" do
43
41
  before(:each) do
44
- route_set.reset!
45
- route_set.add('/sample').post.to(@app)
46
- route_set.add('/sample').to(MockApp.new("You shouldn't get here if you are using POST"))
42
+ @route_set.reset!
43
+ @route_set.add('/sample').post.to(@app)
44
+ @route_set.add('/sample').to(MockApp.new("You shouldn't get here if you are using POST"))
47
45
  end
48
46
 
49
47
  it "should dispatch a POST request" do
50
- response = route_set.call_with_mock_request('/sample', 'POST')
48
+ response = @route_set.call_with_mock_request('/sample', 'POST')
51
49
  response.body.should eql("Hello World!")
52
50
  end
53
51
 
54
52
  it "shouldn't dispatch a GET request" do
55
- response = route_set.call_with_mock_request('/sample', 'GET')
53
+ response = @route_set.call_with_mock_request('/sample', 'GET')
56
54
  response.body.should eql("You shouldn't get here if you are using POST")
57
55
  end
58
56
 
59
57
  it "should write router.params" do
60
- response = route_set.call_with_mock_request("/sample", 'POST')
58
+ response = @route_set.call_with_mock_request("/sample", 'POST')
61
59
  @app.env["router.params"].should == {}
62
60
  end
63
61
  end
64
62
 
65
63
  it "should returns HTTP 405 if the method mis-matches" do
66
- route_set.reset!
67
- route_set.post('/sample').to(@app)
68
- route_set.put('/sample').to(@app)
69
- response = route_set.call_with_mock_request('/sample', 'GET')
64
+ @route_set.reset!
65
+ @route_set.post('/sample').to(@app)
66
+ @route_set.put('/sample').to(@app)
67
+ response = @route_set.call_with_mock_request('/sample', 'GET')
70
68
  response.status.should eql(405)
71
69
  response['Allow'].should == 'POST, PUT'
72
70
  end
73
71
 
74
72
  it "should returns HTTP 404 if route doesn't exist" do
75
- response = route_set.call_with_mock_request("/not-existing-url")
73
+ response = @route_set.call_with_mock_request("/not-existing-url")
76
74
  response.status.should eql(404)
77
75
  end
78
76
 
79
77
  describe "shortcuts" do
80
78
  describe "get" do
81
79
  before(:each) do
82
- route_set.reset!
83
- route_set.get('/sample').head.to(@app)
80
+ @route_set.reset!
81
+ @route_set.get('/sample').head.to(@app)
84
82
  end
85
83
 
86
84
  it "should dispatch a GET request" do
87
- response = route_set.call_with_mock_request("/sample", "GET")
85
+ response = @route_set.call_with_mock_request("/sample", "GET")
88
86
  response.body.should eql("Hello World!")
89
87
  end
90
88
 
91
89
  it "should dispatch a HEAD request" do
92
- response = route_set.call_with_mock_request("/sample", "HEAD")
90
+ response = @route_set.call_with_mock_request("/sample", "HEAD")
93
91
  response.body.should eql("Hello World!")
94
92
  end
95
93
  end
@@ -1,3 +1,5 @@
1
+ require 'spec_helper'
2
+
1
3
  route_set = HttpRouter.new
2
4
  route_set.extend(CallWithMockRequestMixin)
3
5
 
@@ -9,12 +11,12 @@ describe "HttpRouter route generation" do
9
11
  route_set.add("/named/simple/:named_simple_var").name(:simple).compile
10
12
  route_set.add("/named/optional(/:named_optional_var)").name(:optional).compile
11
13
  end
12
-
14
+
13
15
  describe "named routes" do
14
16
  it "should generate a fixed path" do
15
17
  route_set.url(:fixed).should == "/fixed"
16
18
  end
17
-
19
+
18
20
  it "should generate a named path route" do
19
21
  route_set.url(:simple, :named_simple_var => "the_var").should == "/named/simple/the_var"
20
22
  end
@@ -1,3 +1,5 @@
1
+ require 'spec_helper'
2
+
1
3
  describe "HttpRouter as middleware" do
2
4
  before(:each) do
3
5
  @builder = Rack::Builder.new do
@@ -17,4 +19,4 @@ describe "HttpRouter as middleware" do
17
19
  @builder.call(Rack::MockRequest.env_for('/test')).last.join.should == 'test'
18
20
  end
19
21
  end
20
-
22
+
@@ -1,3 +1,5 @@
1
+ require 'spec_helper'
2
+
1
3
  describe "Rack interface extensions for Usher::Route" do
2
4
  before(:each) do
3
5
  @route_set = HttpRouter.new
@@ -1,3 +1,4 @@
1
+ require 'spec_helper'
1
2
  describe "HttpRouter#recognize" do
2
3
  before(:each) do
3
4
  @router = HttpRouter.new
@@ -10,7 +11,7 @@ describe "HttpRouter#recognize" do
10
11
  @router.recognize(Rack::MockRequest.env_for(path)).route.should == route
11
12
  end
12
13
  end
13
-
14
+
14
15
  context("with optional parts") do
15
16
  it "work either way" do
16
17
  route = @router.add("/test(/optional)").to(:test)
@@ -199,7 +200,7 @@ describe "HttpRouter#recognize" do
199
200
  response.params_as_hash[:format].should be_nil
200
201
  response.params_as_hash[:test].should == 'hey'
201
202
  end
202
-
203
+
203
204
  context "with globs" do
204
205
  it "should recognize" do
205
206
  route = @router.add('/test/*variable').to(:test)
@@ -216,9 +217,9 @@ describe "HttpRouter#recognize" do
216
217
  response.should be_nil
217
218
  end
218
219
  end
219
-
220
+
220
221
  end
221
-
222
+
222
223
  context("with interstitial variables") do
223
224
  it "should recognize" do
224
225
  route = @router.add('/one-:variable-time').to(:test)
@@ -234,14 +235,14 @@ describe "HttpRouter#recognize" do
234
235
  response.route.should == route
235
236
  response.params_as_hash[:variable].should == '123'
236
237
  end
237
-
238
+
238
239
  it "should recognize when there is an extension" do
239
240
  route = @router.add('/hey.:greed.html').to(:test)
240
241
  response = @router.recognize(Rack::MockRequest.env_for('/hey.greedyboy.html'))
241
242
  response.route.should == route
242
243
  response.params_as_hash[:greed].should == 'greedyboy'
243
244
  end
244
-
245
+
245
246
  end
246
247
 
247
248
  context("with dynamic greedy paths") do
@@ -1,3 +1,4 @@
1
+ require 'spec_helper'
1
2
  require "sinatra"
2
3
  require "http_router/interface/sinatra"
3
4
 
@@ -79,28 +80,28 @@ describe "HttpRouter (for Sinatra) route recognition" do
79
80
  describe "mapping functionality" do
80
81
 
81
82
  it "should map a basic route" do
82
- @app.get('/hi', :name => :hi) { generate(:hi) }
83
+ @app.get('/hi', :name => :hi) { generate(:hi) }
83
84
  response = @app.call_with_mock_request('/hi')
84
85
  response.status.should == 200
85
86
  response.body.should == "/hi"
86
87
  end
87
88
 
88
89
  it "should map a basic route ignoring trailing delimiters" do
89
- @app.get('/hi', :name => :hi) { generate(:hi) }
90
+ @app.get('/hi', :name => :hi) { generate(:hi) }
90
91
  response = @app.call_with_mock_request('/hi/')
91
92
  response.status.should == 200
92
93
  response.body.should == "/hi"
93
94
  end
94
95
 
95
96
  it "should map a basic route with params" do
96
- @app.get('/hi/:id', :name => :hi) { generate(:hi, :id => 18) }
97
+ @app.get('/hi/:id', :name => :hi) { generate(:hi, :id => 18) }
97
98
  response = @app.call_with_mock_request('/hi/1')
98
99
  response.status.should == 200
99
100
  response.body.should == "/hi/18"
100
101
  end
101
102
 
102
103
  it "should map route with params" do
103
- @app.get('/hi-:id', :name => :hi) { generate(:hi, :id => 18) }
104
+ @app.get('/hi-:id', :name => :hi) { generate(:hi, :id => 18) }
104
105
  response = @app.call_with_mock_request('/hi-1')
105
106
  response.status.should == 200
106
107
  response.body.should == "/hi-18"
@@ -137,4 +138,4 @@ describe "HttpRouter (for Sinatra) route recognition" do
137
138
  response.body.should_not match(/__sinatra__/)
138
139
  end
139
140
  end
140
- end
141
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,8 @@
1
- require 'rack'
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require 'rubygems'
3
+ require 'http_router'
4
+ require 'spec'
5
+ require 'spec/autorun'
2
6
 
3
7
  module CallWithMockRequestMixin
4
8
  def call_with_mock_request(url = "/sample", method = "GET", params = Hash.new)
@@ -21,4 +25,4 @@ class MockApp
21
25
  @headers.merge("Content-Length" => @body.length.to_s)
22
26
  [@status, @headers, [@body]]
23
27
  end
24
- end
28
+ end
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: 17
4
+ hash: 31
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 3
10
- version: 0.2.3
9
+ - 4
10
+ version: 0.2.4
11
11
  platform: ruby
12
12
  authors:
13
13
  - Joshua Hull
@@ -34,6 +34,21 @@ dependencies:
34
34
  version: 1.0.0
35
35
  type: :runtime
36
36
  version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: url_mount
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 15
46
+ segments:
47
+ - 0
48
+ - 2
49
+ version: "0.2"
50
+ type: :runtime
51
+ version_requirements: *id002
37
52
  description: A kick-ass HTTP router for use in Rack & Sinatra
38
53
  email: joshbuddy@gmail.com
39
54
  executables: []
@@ -44,6 +59,8 @@ extra_rdoc_files:
44
59
  - README.rdoc
45
60
  files:
46
61
  - .gitignore
62
+ - Gemfile
63
+ - Gemfile.lock
47
64
  - README.rdoc
48
65
  - Rakefile
49
66
  - VERSION
@@ -67,6 +84,7 @@ files:
67
84
  - lib/http_router/interface/sinatra.rb
68
85
  - lib/http_router/node.rb
69
86
  - lib/http_router/optional_compiler.rb
87
+ - lib/http_router/parts.rb
70
88
  - lib/http_router/path.rb
71
89
  - lib/http_router/response.rb
72
90
  - lib/http_router/root.rb
@@ -74,6 +92,7 @@ files:
74
92
  - lib/http_router/variable.rb
75
93
  - spec/generate_spec.rb
76
94
  - spec/misc_spec.rb
95
+ - spec/mounting_spec.rb
77
96
  - spec/rack/dispatch_spec.rb
78
97
  - spec/rack/generate_spec.rb
79
98
  - spec/rack/middleware_spec.rb
@@ -119,6 +138,7 @@ summary: A kick-ass HTTP router for use in Rack & Sinatra
119
138
  test_files:
120
139
  - spec/generate_spec.rb
121
140
  - spec/misc_spec.rb
141
+ - spec/mounting_spec.rb
122
142
  - spec/rack/dispatch_spec.rb
123
143
  - spec/rack/generate_spec.rb
124
144
  - spec/rack/middleware_spec.rb