http_router 0.10.2 → 0.11.0
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 +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
|