http_router 0.10.2 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/Rakefile +7 -5
- data/benchmarks/gen2.rb +1 -1
- data/benchmarks/rack_mount.rb +8 -14
- data/examples/rack_mapper.ru +12 -13
- data/examples/variable_with_regex.ru +1 -1
- data/http_router.gemspec +1 -1
- data/lib/http_router.rb +159 -62
- data/lib/http_router/generation_helper.rb +29 -0
- data/lib/http_router/generator.rb +150 -0
- data/lib/http_router/node.rb +27 -17
- data/lib/http_router/node/abstract_request_node.rb +31 -0
- data/lib/http_router/node/host.rb +9 -0
- data/lib/http_router/node/lookup.rb +8 -10
- data/lib/http_router/node/path.rb +23 -38
- data/lib/http_router/node/request_method.rb +16 -0
- data/lib/http_router/node/root.rb +104 -10
- data/lib/http_router/node/scheme.rb +9 -0
- data/lib/http_router/node/user_agent.rb +9 -0
- data/lib/http_router/regex_route_generation.rb +10 -0
- data/lib/http_router/request.rb +7 -17
- data/lib/http_router/response.rb +4 -0
- data/lib/http_router/route.rb +16 -277
- data/lib/http_router/route_helper.rb +126 -0
- data/lib/http_router/util.rb +1 -37
- data/lib/http_router/version.rb +1 -1
- data/test/common/generate.txt +1 -1
- data/test/generation.rb +15 -11
- data/test/generic.rb +2 -3
- data/test/helper.rb +15 -10
- data/test/rack/test_route.rb +0 -5
- data/test/test_misc.rb +50 -40
- data/test/test_mounting.rb +27 -26
- data/test/test_recognition.rb +1 -76
- metadata +104 -161
- data/.rspec +0 -1
- data/lib/http_router/node/arbitrary.rb +0 -30
- data/lib/http_router/node/request.rb +0 -52
- data/lib/http_router/rack.rb +0 -19
- data/lib/http_router/rack/builder.rb +0 -61
- data/lib/http_router/rack/url_map.rb +0 -16
- data/lib/http_router/regex_route.rb +0 -39
data/.gitignore
CHANGED
data/Rakefile
CHANGED
@@ -96,10 +96,12 @@ namespace :test do
|
|
96
96
|
c = $1
|
97
97
|
raise "out was nil" if out.nil?
|
98
98
|
test = out.shift
|
99
|
-
c
|
100
|
-
|
101
|
-
|
102
|
-
|
99
|
+
if c['Last-Modified'] == test['Last-Modified']
|
100
|
+
assertion_count += 1
|
101
|
+
else
|
102
|
+
raise "expected #{c.inspect}, received #{test.inspect}" unless c.strip == test.strip
|
103
|
+
assertion_count += 1
|
104
|
+
end
|
103
105
|
end
|
104
106
|
end
|
105
107
|
raise "no assertions were raised in #{example}" if assertion_count.zero?
|
@@ -131,7 +133,7 @@ namespace :test do
|
|
131
133
|
msg = expected.dup
|
132
134
|
msg << " was expected to be "
|
133
135
|
msg << "\#{__example_runner.inspect}"
|
134
|
-
current_example << "raise \"#{msg.gsub('"', '\\"')}\" unless __example_runner.strip == #{expected}\n" if in_example
|
136
|
+
current_example << "raise \"#{msg.gsub('"', '\\"')}\" unless (__example_runner.respond_to?(:strip) ? __example_runner.strip : __example_runner) == #{expected}\n" if in_example
|
135
137
|
when ''
|
136
138
|
unless current_example.empty?
|
137
139
|
examples << current_example
|
data/benchmarks/gen2.rb
CHANGED
@@ -10,7 +10,7 @@ u.add('/simple')
|
|
10
10
|
u.add('/simple/:variable') .name(:one_variable).to{}
|
11
11
|
u.add('/simple/:var1/:var2/:var3') .name(:three_variables).to{}
|
12
12
|
u.add('/simple/:v1/:v2/:v3/:v4/:v5/:v6/:v7/:v8') .name(:eight_variables).to{}
|
13
|
-
u.add('/with_condition/:cond1/:cond2').
|
13
|
+
u.add('/with_condition/:cond1/:cond2').matches_with(:cond1 => /^\d+$/, :cond2 => /^[a-z]+$/) .name(:two_conditions).to{}
|
14
14
|
|
15
15
|
TIMES = 50_000
|
16
16
|
|
data/benchmarks/rack_mount.rb
CHANGED
@@ -3,12 +3,13 @@ require 'rbench'
|
|
3
3
|
require 'rack'
|
4
4
|
require 'rack/mount'
|
5
5
|
#require '../usher/lib/usher'
|
6
|
-
|
6
|
+
$: << 'lib'
|
7
|
+
require 'http_router'
|
7
8
|
|
8
9
|
set = Rack::Mount::RouteSet.new do |set|
|
9
10
|
set.add_route(proc{|env| [200, {'Content-type'=>'text/html'}, []]}, {:path => '/simple'}, {}, :simple)
|
10
11
|
set.add_route(proc{|env| [200, {'Content-type'=>'text/html'}, []]}, {:path => '/simple/again'}, {}, :again)
|
11
|
-
set.add_route(proc{|env| [200, {'Content-type'=>'text/html'}, []]}, {:path =>
|
12
|
+
set.add_route(proc{|env| [200, {'Content-type'=>'text/html'}, []]}, {:path => %r{/simple/(.*?)}}, {}, :more)
|
12
13
|
end
|
13
14
|
|
14
15
|
#u = Usher::Interface.for(:rack)
|
@@ -16,32 +17,25 @@ end
|
|
16
17
|
#u.add('/simple/again').to(proc{|env| [200, {'Content-type'=>'text/html'}, []]})
|
17
18
|
#u.add('/dynamic/anything').to(proc{|env| [200, {'Content-type'=>'text/html'}, []]})
|
18
19
|
|
19
|
-
hr = HttpRouter.new
|
20
|
-
hr.add('/simple').to(proc{|env| [200, {'Content-type'=>'text/html'}, []]})
|
21
|
-
hr.add('/simple/again').to(proc{|env| [200, {'Content-type'=>'text/html'}, []]})
|
22
|
-
hr.add('/dynamic/anything').to(proc{|env| [200, {'Content-type'=>'text/html'}, []]})
|
23
|
-
|
24
20
|
TIMES = 50_000
|
25
21
|
|
26
22
|
simple_env = Rack::MockRequest.env_for('/simple')
|
27
23
|
simple2_env = Rack::MockRequest.env_for('/simple/again')
|
28
|
-
|
24
|
+
dynamic_env = Rack::MockRequest.env_for('/simple/something')
|
29
25
|
|
30
|
-
3.times do
|
31
26
|
|
32
27
|
RBench.run(TIMES) do
|
33
28
|
|
34
29
|
report "2 levels, static" do
|
35
|
-
set.
|
30
|
+
set.call(simple_env).first == 200 or raise
|
36
31
|
end
|
37
32
|
|
38
33
|
report "4 levels, static" do
|
39
|
-
set.
|
34
|
+
set.call(simple2_env).first == 200 or raise
|
40
35
|
end
|
41
36
|
|
42
|
-
report "4 levels,
|
43
|
-
set.
|
37
|
+
report "4 levels, static" do
|
38
|
+
set.call(dynamic_env).first == 200 or raise
|
44
39
|
end
|
45
40
|
|
46
41
|
end
|
47
|
-
end
|
data/examples/rack_mapper.ru
CHANGED
@@ -1,19 +1,18 @@
|
|
1
1
|
require 'http_router'
|
2
|
-
HttpRouter
|
2
|
+
run HttpRouter.new do
|
3
|
+
add('/get/:id', :match_with => {:id => /\d+/}) { |env|
|
4
|
+
[200, {'Content-type' => 'text/plain'}, ["My id is #{env['router.params'][:id]}, which is a number\n"]]
|
5
|
+
}
|
3
6
|
|
4
|
-
|
5
|
-
|
6
|
-
}
|
7
|
-
|
8
|
-
# you have post, get, head, put and delete.
|
9
|
-
post('/get/:id') { |env|
|
10
|
-
[200, {'Content-type' => 'text/plain'}, ["My id is #{env['router.params'][:id]} and you posted!\n"]]
|
11
|
-
}
|
12
|
-
|
13
|
-
map('/get/:id') { |env|
|
14
|
-
[200, {'Content-type' => 'text/plain'}, ["My id is #{env['router.params'][:id]}\n"]]
|
15
|
-
}
|
7
|
+
# you have post, get, head, put and delete.
|
8
|
+
post('/get/:id') { |env|
|
9
|
+
[200, {'Content-type' => 'text/plain'}, ["My id is #{env['router.params'][:id]} and you posted!\n"]]
|
10
|
+
}
|
16
11
|
|
12
|
+
map('/get/:id') { |env|
|
13
|
+
[200, {'Content-type' => 'text/plain'}, ["My id is #{env['router.params'][:id]}\n"]]
|
14
|
+
}
|
15
|
+
end
|
17
16
|
|
18
17
|
# $ curl http://127.0.0.1:3000/get/foo
|
19
18
|
# => My id is foo
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'http_router'
|
2
2
|
|
3
3
|
run HttpRouter.new {
|
4
|
-
get('/get/:id'
|
4
|
+
get('/get/:id', :id => /\d+/).to { |env| [200, {'Content-type' => 'text/plain'}, ["id is #{Integer(env['router.params'][:id]) * 2} * 2\n"]]}
|
5
5
|
}
|
6
6
|
|
7
7
|
# $ curl http://127.0.0.1:3000/get/123
|
data/http_router.gemspec
CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.add_development_dependency 'rbench'
|
29
29
|
s.add_development_dependency 'json'
|
30
30
|
s.add_development_dependency 'phocus'
|
31
|
-
s.add_development_dependency 'bundler'
|
31
|
+
s.add_development_dependency 'bundler'
|
32
32
|
s.add_development_dependency 'thin', '= 1.2.8'
|
33
33
|
|
34
34
|
if s.respond_to? :specification_version then
|
data/lib/http_router.rb
CHANGED
@@ -7,25 +7,29 @@ require 'http_router/node'
|
|
7
7
|
require 'http_router/request'
|
8
8
|
require 'http_router/response'
|
9
9
|
require 'http_router/route'
|
10
|
-
require 'http_router/
|
11
|
-
require 'http_router/
|
10
|
+
require 'http_router/generator'
|
11
|
+
require 'http_router/route_helper'
|
12
|
+
require 'http_router/generation_helper'
|
13
|
+
require 'http_router/regex_route_generation'
|
12
14
|
require 'http_router/util'
|
13
15
|
|
14
16
|
class HttpRouter
|
15
|
-
|
16
|
-
attr_reader :root, :routes, :known_methods, :named_routes, :nodes
|
17
|
-
attr_accessor :default_app, :url_mount
|
18
|
-
|
19
17
|
# Raised when a url is not able to be generated for the given parameters
|
20
18
|
InvalidRouteException = Class.new(RuntimeError)
|
21
19
|
# Raised when a Route is not able to be generated due to a missing parameter.
|
22
20
|
MissingParameterException = Class.new(RuntimeError)
|
23
|
-
# Raised when a Route is compiled twice
|
24
|
-
DoubleCompileError = Class.new(RuntimeError)
|
25
21
|
# Raised an invalid request value is used
|
26
22
|
InvalidRequestValueError = Class.new(RuntimeError)
|
27
23
|
# Raised when there are extra parameters passed in to #url
|
28
24
|
TooManyParametersException = Class.new(RuntimeError)
|
25
|
+
# Raised when there are left over options
|
26
|
+
LeftOverOptions = Class.new(RuntimeError)
|
27
|
+
|
28
|
+
RecognizeResponse = Struct.new(:matches, :acceptable_methods)
|
29
|
+
|
30
|
+
attr_reader :root, :routes, :named_routes, :nodes
|
31
|
+
attr_writer :route_class
|
32
|
+
attr_accessor :default_app, :url_mount, :default_host, :default_port, :default_scheme
|
29
33
|
|
30
34
|
# Creates a new HttpRouter.
|
31
35
|
# Can be called with either <tt>HttpRouter.new(proc{|env| ... }, { .. options .. })</tt> or with the first argument omitted.
|
@@ -34,14 +38,13 @@ class HttpRouter
|
|
34
38
|
# * :default_app -- Default application used if there is a non-match on #call. Defaults to 404 generator.
|
35
39
|
# * :ignore_trailing_slash -- Ignore a trailing / when attempting to match. Defaults to +true+.
|
36
40
|
# * :redirect_trailing_slash -- On trailing /, redirect to the same path without the /. Defaults to +false+.
|
37
|
-
# * :known_methods -- Array of http methods tested for 405s.
|
38
41
|
def initialize(*args, &blk)
|
39
42
|
default_app, options = args.first.is_a?(Hash) ? [nil, args.first] : [args.first, args[1]]
|
40
|
-
@options
|
43
|
+
@options = options
|
41
44
|
@default_app = default_app || options && options[:default_app] || proc{|env| ::Rack::Response.new("Not Found", 404, {'X-Cascade' => 'pass'}).finish }
|
42
45
|
@ignore_trailing_slash = options && options.key?(:ignore_trailing_slash) ? options[:ignore_trailing_slash] : true
|
43
46
|
@redirect_trailing_slash = options && options.key?(:redirect_trailing_slash) ? options[:redirect_trailing_slash] : false
|
44
|
-
@
|
47
|
+
@route_class = Route
|
45
48
|
reset!
|
46
49
|
instance_eval(&blk) if blk
|
47
50
|
end
|
@@ -62,33 +65,55 @@ class HttpRouter
|
|
62
65
|
#
|
63
66
|
# Returns the route object.
|
64
67
|
def add(*args, &app)
|
65
|
-
|
68
|
+
uncompile
|
69
|
+
opts = args.last.is_a?(Hash) ? args.pop : nil
|
66
70
|
path = args.first
|
67
|
-
route =
|
71
|
+
route = route_class.new
|
72
|
+
add_route route
|
73
|
+
route.path = path if path
|
74
|
+
route.process_opts(opts) if opts
|
68
75
|
route.to(app) if app
|
69
76
|
route
|
70
77
|
end
|
71
78
|
|
72
79
|
def add_route(route)
|
73
80
|
@routes << route
|
74
|
-
route
|
81
|
+
@named_routes[route.name] << route if route.name
|
82
|
+
route.router = self
|
83
|
+
end
|
84
|
+
|
85
|
+
# Extends the route class with custom features.
|
86
|
+
#
|
87
|
+
# Example:
|
88
|
+
# router = HttpRouter.new { extend_route { attr_accessor :controller } }
|
89
|
+
# router.add('/foo', :controller => :foo).to{|env| [200, {}, ['foo!']]}
|
90
|
+
# matches, other_methods = router.recognize(Rack::MockRequest.env_for('/foo'))
|
91
|
+
# matches.first.route.controller
|
92
|
+
# # ==> :foo
|
93
|
+
def extend_route(&blk)
|
94
|
+
@route_class = Class.new(Route) if @route_class == Route
|
95
|
+
@route_class.class_eval(&blk)
|
96
|
+
@extended_route_class = nil
|
97
|
+
end
|
98
|
+
|
99
|
+
def route_class
|
100
|
+
@extended_route_class ||= begin
|
101
|
+
@route_class.send(:include, RouteHelper)
|
102
|
+
@route_class.send(:include, GenerationHelper)
|
103
|
+
@route_class
|
104
|
+
end
|
75
105
|
end
|
76
106
|
|
77
107
|
# Adds a path that only responds to the request method +GET+.
|
78
108
|
#
|
79
109
|
# Returns the route object.
|
80
|
-
def get(path, opts = {}, &app); add_with_request_method(path, :get, opts, &app); end
|
110
|
+
def get(path, opts = {}, &app); add_with_request_method(path, [:get, :head], opts, &app); end
|
81
111
|
|
82
112
|
# Adds a path that only responds to the request method +POST+.
|
83
113
|
#
|
84
114
|
# Returns the route object.
|
85
115
|
def post(path, opts = {}, &app); add_with_request_method(path, :post, opts, &app); end
|
86
116
|
|
87
|
-
# Adds a path that only responds to the request method +HEAD+.
|
88
|
-
#
|
89
|
-
# Returns the route object.
|
90
|
-
def head(path, opts = {}, &app); add_with_request_method(path, :head, opts, &app); end
|
91
|
-
|
92
117
|
# Adds a path that only responds to the request method +DELETE+.
|
93
118
|
#
|
94
119
|
# Returns the route object.
|
@@ -99,35 +124,50 @@ class HttpRouter
|
|
99
124
|
# Returns the route object.
|
100
125
|
def put(path, opts = {}, &app); add_with_request_method(path, :put, opts, &app); end
|
101
126
|
|
127
|
+
# Adds a path that only responds to the request method +PATCH+.
|
128
|
+
#
|
129
|
+
# Returns the route object.
|
130
|
+
def patch(path, opts = {}, &app); add_with_request_method(path, :patch, opts, &app); end
|
131
|
+
|
132
|
+
# Adds a path that only responds to the request method +OPTIONS+.
|
133
|
+
#
|
134
|
+
# Returns the route object.
|
135
|
+
def trace(path, opts = {}, &app); add_with_request_method(path, :trace, opts, &app); end
|
136
|
+
|
102
137
|
# Adds a path that only responds to the request method +OPTIONS+.
|
103
138
|
#
|
104
139
|
# Returns the route object.
|
105
|
-
def
|
140
|
+
def conenct(path, opts = {}, &app); add_with_request_method(path, :conenct, opts, &app); end
|
106
141
|
|
107
142
|
# Performs recoginition without actually calling the application and returns an array of all
|
108
143
|
# matching routes or nil if no match was found.
|
109
|
-
def recognize(env)
|
110
|
-
|
144
|
+
def recognize(env, &callback)
|
145
|
+
if callback
|
146
|
+
request = call(env, &callback)
|
147
|
+
[request.called?, request.acceptable_methods]
|
148
|
+
else
|
149
|
+
matches = []
|
150
|
+
callback ||= Proc.new {|match| matches << match}
|
151
|
+
request = call(env, &callback)
|
152
|
+
[matches.empty? ? nil : matches, request.acceptable_methods]
|
153
|
+
end
|
111
154
|
end
|
112
155
|
|
113
156
|
# Rack compatible #call. If matching route is found, and +dest+ value responds to #call, processing will pass to the matched route. Otherwise,
|
114
157
|
# the default application will be called. The router will be available in the env under the key <tt>router</tt>. And parameters matched will
|
115
158
|
# be available under the key <tt>router.params</tt>.
|
116
|
-
def call(env,
|
117
|
-
|
118
|
-
|
119
|
-
response = catch(:success) { @root[request] }
|
120
|
-
if perform_call
|
121
|
-
response or no_response(env)
|
122
|
-
else
|
123
|
-
request.matches.empty? ? nil : request.matches
|
124
|
-
end
|
159
|
+
def call(env, &callback)
|
160
|
+
compile
|
161
|
+
call(env, &callback)
|
125
162
|
end
|
163
|
+
alias_method :compiling_call, :call
|
126
164
|
|
127
165
|
# Resets the router to a clean state.
|
128
166
|
def reset!
|
167
|
+
uncompile
|
129
168
|
@routes, @named_routes, @root = [], Hash.new{|h,k| h[k] = []}, Node::Root.new(self)
|
130
169
|
@default_app = Proc.new{ |env| ::Rack::Response.new("Your request couldn't be found", 404).finish }
|
170
|
+
@default_host, @default_port, @default_scheme = 'localhost', 80, 'http'
|
131
171
|
end
|
132
172
|
|
133
173
|
# Assigns the default application.
|
@@ -140,22 +180,32 @@ class HttpRouter
|
|
140
180
|
#
|
141
181
|
# Example:
|
142
182
|
# router = HttpRouter.new
|
143
|
-
# router.add('/:foo.:format'
|
144
|
-
# router.
|
183
|
+
# router.add('/:foo.:format', :name => :test).to{|env| [200, {}, []]}
|
184
|
+
# router.path(:test, 123, 'html')
|
145
185
|
# # ==> "/123.html"
|
146
|
-
# router.
|
186
|
+
# router.path(:test, 123, :format => 'html')
|
147
187
|
# # ==> "/123.html"
|
148
|
-
# router.
|
188
|
+
# router.path(:test, :foo => 123, :format => 'html')
|
149
189
|
# # ==> "/123.html"
|
150
|
-
# router.
|
190
|
+
# router.path(:test, :foo => 123, :format => 'html', :fun => 'inthesun')
|
151
191
|
# # ==> "/123.html?fun=inthesun"
|
152
192
|
def url(route, *args)
|
153
|
-
|
154
|
-
|
155
|
-
when Route then return route.url(*args)
|
156
|
-
end
|
157
|
-
raise(InvalidRouteException)
|
193
|
+
compile
|
194
|
+
url(route, *args)
|
158
195
|
end
|
196
|
+
alias_method :compiling_url, :url
|
197
|
+
|
198
|
+
def url_ns(route, *args)
|
199
|
+
compile
|
200
|
+
url_ns(route, *args)
|
201
|
+
end
|
202
|
+
alias_method :compiling_url_ns, :url_ns
|
203
|
+
|
204
|
+
def path(route, *args)
|
205
|
+
compile
|
206
|
+
path(route, *args)
|
207
|
+
end
|
208
|
+
alias_method :compiling_path, :path
|
159
209
|
|
160
210
|
# This method is invoked when a Path object gets called with an env. Override it to implement custom path processing.
|
161
211
|
def process_destination_path(path, env)
|
@@ -182,14 +232,8 @@ class HttpRouter
|
|
182
232
|
def clone(klass = self.class)
|
183
233
|
cloned_router = klass.new(@options)
|
184
234
|
@routes.each do |route|
|
185
|
-
new_route = route.
|
235
|
+
new_route = route.create_clone(cloned_router)
|
186
236
|
cloned_router.add_route(new_route)
|
187
|
-
new_route.name(route.named) if route.named
|
188
|
-
begin
|
189
|
-
new_route.to route.dest.clone
|
190
|
-
rescue
|
191
|
-
new_route.to route.dest
|
192
|
-
end
|
193
237
|
end
|
194
238
|
cloned_router
|
195
239
|
end
|
@@ -204,21 +248,14 @@ class HttpRouter
|
|
204
248
|
env['PATH_INFO'] = ''
|
205
249
|
end
|
206
250
|
|
207
|
-
def no_response(env)
|
208
|
-
|
209
|
-
|
210
|
-
test_env = ::Rack::Request.new(env.clone)
|
211
|
-
test_env.env['REQUEST_METHOD'] = m
|
212
|
-
test_env.env['_HTTP_ROUTER_405_TESTING_ACCEPTANCE'] = true
|
213
|
-
test_request = Request.new(test_env.path_info, test_env, 405)
|
214
|
-
@root[test_request]
|
215
|
-
!test_request.matches.empty?
|
216
|
-
end
|
217
|
-
supported_methods.empty? ? @default_app.call(env) : [405, {'Allow' => supported_methods.sort.join(", ")}, []]
|
251
|
+
def no_response(request, env)
|
252
|
+
request.acceptable_methods.empty? ?
|
253
|
+
@default_app.call(env) : [405, {'Allow' => request.acceptable_methods.sort.join(", ")}, []]
|
218
254
|
end
|
219
255
|
|
220
256
|
def to_s
|
221
|
-
|
257
|
+
compile
|
258
|
+
"#<HttpRouter:0x#{object_id.to_s(16)} number of routes (#{routes.size}) ignore_trailing_slash? (#{ignore_trailing_slash?}) redirect_trailing_slash? (#{redirect_trailing_slash?})>"
|
222
259
|
end
|
223
260
|
|
224
261
|
def inspect
|
@@ -226,9 +263,69 @@ class HttpRouter
|
|
226
263
|
"#{to_s}\n#{'=' * head.size}\n#{@root.inspect}"
|
227
264
|
end
|
228
265
|
|
266
|
+
def uncompile
|
267
|
+
return unless @compiled
|
268
|
+
instance_eval "undef :path; alias :path :compiling_path
|
269
|
+
undef :url; alias :url :compiling_url
|
270
|
+
undef :url_ns; alias :url_ns :compiling_url_ns
|
271
|
+
undef :call; alias :call :compiling_call", __FILE__, __LINE__
|
272
|
+
@root.uncompile
|
273
|
+
@compiled = false
|
274
|
+
end
|
275
|
+
|
276
|
+
def raw_url(route, *args)
|
277
|
+
case route
|
278
|
+
when Symbol then @named_routes.key?(route) && @named_routes[route].each{|r| url = r.url(*args); return url if url}
|
279
|
+
when Route then return route.url(*args)
|
280
|
+
end
|
281
|
+
raise(InvalidRouteException.new "No route (url) could be generated for #{route.inspect}")
|
282
|
+
end
|
283
|
+
|
284
|
+
def raw_url_ns(route, *args)
|
285
|
+
case route
|
286
|
+
when Symbol then @named_routes.key?(route) && @named_routes[route].each{|r| url = r.url_ns(*args); return url if url}
|
287
|
+
when Route then return route.url_ns(*args)
|
288
|
+
end
|
289
|
+
raise(InvalidRouteException.new "No route (url_ns) could be generated for #{route.inspect}")
|
290
|
+
end
|
291
|
+
|
292
|
+
def raw_path(route, *args)
|
293
|
+
case route
|
294
|
+
when Symbol then @named_routes.key?(route) && @named_routes[route].each{|r| path = r.path(*args); return path if path}
|
295
|
+
when Route then return route.path(*args)
|
296
|
+
end
|
297
|
+
raise(InvalidRouteException.new "No route (path) could be generated for #{route.inspect}")
|
298
|
+
end
|
299
|
+
|
300
|
+
def raw_call(env, &blk)
|
301
|
+
rack_request = ::Rack::Request.new(env)
|
302
|
+
request = Request.new(rack_request.path_info, rack_request)
|
303
|
+
if blk
|
304
|
+
@root.call(request, &blk)
|
305
|
+
request
|
306
|
+
else
|
307
|
+
@root.call(request) or no_response(request, env)
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
229
311
|
private
|
312
|
+
def compile
|
313
|
+
return if @compiled
|
314
|
+
@root.compile(@routes)
|
315
|
+
@named_routes.each do |_, routes|
|
316
|
+
routes.sort!{|r1, r2| r2.max_param_count <=> r1.max_param_count }
|
317
|
+
end
|
318
|
+
|
319
|
+
instance_eval "undef :path; alias :path :raw_path
|
320
|
+
undef :url; alias :url :raw_url
|
321
|
+
undef :url_ns; alias :url_ns :raw_url_ns
|
322
|
+
undef :call; alias :call :raw_call", __FILE__, __LINE__
|
323
|
+
@compiled = true
|
324
|
+
end
|
325
|
+
|
230
326
|
def add_with_request_method(path, method, opts = {}, &app)
|
231
|
-
|
327
|
+
opts[:request_method] = method
|
328
|
+
route = add(path, opts)
|
232
329
|
route.to(app) if app
|
233
330
|
route
|
234
331
|
end
|