http_router 0.7.2 → 0.7.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/benchmarks/gen2.rb +7 -5
- data/benchmarks/rec2.rb +3 -3
- data/lib/http_router.rb +13 -11
- data/lib/http_router/node.rb +3 -7
- data/lib/http_router/node/arbitrary.rb +6 -4
- data/lib/http_router/node/free_regex.rb +1 -1
- data/lib/http_router/node/spanning_regex.rb +1 -1
- data/lib/http_router/regex_route.rb +1 -0
- data/lib/http_router/request.rb +4 -0
- data/lib/http_router/route.rb +26 -25
- data/lib/http_router/version.rb +1 -1
- data/test/test_arbitrary.rb +8 -0
- metadata +4 -4
data/Rakefile
CHANGED
data/benchmarks/gen2.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rbench'
|
3
3
|
#require 'lib/usher'
|
4
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
5
|
+
|
4
6
|
require 'lib/http_router'
|
5
7
|
|
6
8
|
u = HttpRouter.new
|
7
|
-
u.add('/simple') .name(:simple).compile
|
8
|
-
u.add('/simple/:variable') .name(:one_variable).compile
|
9
|
-
u.add('/simple/:var1/:var2/:var3') .name(:three_variables).compile
|
10
|
-
u.add('/simple/:v1/:v2/:v3/:v4/:v5/:v6/:v7/:v8') .name(:eight_variables).compile
|
11
|
-
u.add('/with_condition/:cond1/:cond2').matching(:cond1 => /^\d+$/, :cond2 => /^[a-z]+$/) .name(:two_conditions).compile
|
9
|
+
u.add('/simple') .name(:simple).send(:compile)
|
10
|
+
u.add('/simple/:variable') .name(:one_variable).send(:compile)
|
11
|
+
u.add('/simple/:var1/:var2/:var3') .name(:three_variables).send(:compile)
|
12
|
+
u.add('/simple/:v1/:v2/:v3/:v4/:v5/:v6/:v7/:v8') .name(:eight_variables).send(:compile)
|
13
|
+
u.add('/with_condition/:cond1/:cond2').matching(:cond1 => /^\d+$/, :cond2 => /^[a-z]+$/) .name(:two_conditions).send(:compile)
|
12
14
|
|
13
15
|
TIMES = 50_000
|
14
16
|
|
data/benchmarks/rec2.rb
CHANGED
@@ -25,7 +25,7 @@ puts Benchmark.measure {
|
|
25
25
|
puts "u.routes.size: #{u.routes.size}"
|
26
26
|
}
|
27
27
|
#
|
28
|
-
TIMES =
|
28
|
+
TIMES = 10_000
|
29
29
|
|
30
30
|
#simple_env =
|
31
31
|
#simple2_env =
|
@@ -34,7 +34,7 @@ TIMES = 50_000
|
|
34
34
|
#simple_and_dynamic_env1 = Rack::MockRequest.env_for('/rails/controller/action/id')
|
35
35
|
#simple_and_dynamic_env2 = Rack::MockRequest.env_for('/greedy/controller/action/id')
|
36
36
|
#simple_and_dynamic_env3 = Rack::MockRequest.env_for('/greedy/hey.hello.html')
|
37
|
-
5.times {
|
37
|
+
#5.times {
|
38
38
|
RBench.run(TIMES) do
|
39
39
|
|
40
40
|
report "2 levels, static" do
|
@@ -62,5 +62,5 @@ TIMES = 50_000
|
|
62
62
|
#end
|
63
63
|
|
64
64
|
end
|
65
|
-
}
|
65
|
+
#}
|
66
66
|
puts `ps -o rss= -p #{Process.pid}`.to_i
|
data/lib/http_router.rb
CHANGED
@@ -11,7 +11,7 @@ require 'http_router/optional_compiler'
|
|
11
11
|
|
12
12
|
class HttpRouter
|
13
13
|
|
14
|
-
attr_reader :root, :routes, :known_methods, :named_routes
|
14
|
+
attr_reader :root, :routes, :known_methods, :named_routes
|
15
15
|
attr_accessor :default_app, :url_mount
|
16
16
|
|
17
17
|
# Raised when a Route is not able to be generated.
|
@@ -29,7 +29,6 @@ class HttpRouter
|
|
29
29
|
# * :ignore_trailing_slash -- Ignore a trailing / when attempting to match. Defaults to +true+.
|
30
30
|
# * :redirect_trailing_slash -- On trailing /, redirect to the same path without the /. Defaults to +false+.
|
31
31
|
# * :known_methods -- Array of http methods tested for 405s.
|
32
|
-
# * :request_methods -- Array of methods to use on request
|
33
32
|
def initialize(*args, &blk)
|
34
33
|
default_app, options = args.first.is_a?(Hash) ? [nil, args.first] : [args.first, args[1]]
|
35
34
|
@options = options
|
@@ -37,7 +36,6 @@ class HttpRouter
|
|
37
36
|
@ignore_trailing_slash = options && options.key?(:ignore_trailing_slash) ? options[:ignore_trailing_slash] : true
|
38
37
|
@redirect_trailing_slash = options && options.key?(:redirect_trailing_slash) ? options[:redirect_trailing_slash] : false
|
39
38
|
@known_methods = Set.new(options && options[:known_methods] || [])
|
40
|
-
@request_methods = options && options[:request_methods] || [:host, :scheme, :request_method, :user_agent]
|
41
39
|
reset!
|
42
40
|
instance_eval(&blk) if blk
|
43
41
|
end
|
@@ -123,14 +121,7 @@ class HttpRouter
|
|
123
121
|
request = Request.new(rack_request.path_info, rack_request, perform_call)
|
124
122
|
response = catch(:success) { @root[request] }
|
125
123
|
if response.nil?
|
126
|
-
|
127
|
-
test_env = ::Rack::Request.new(rack_request.env.clone)
|
128
|
-
test_env.env['REQUEST_METHOD'] = m
|
129
|
-
test_env.env['_HTTP_ROUTER_405_TESTING_ACCEPTANCE'] = true
|
130
|
-
test_request = Request.new(test_env.path_info, test_env, 405)
|
131
|
-
catch(:success) { @root[test_request] }
|
132
|
-
end
|
133
|
-
supported_methods.empty? ? (perform_call ? @default_app.call(env) : nil) : [405, {'Allow' => supported_methods.sort.join(", ")}, []]
|
124
|
+
no_response(env, perform_call)
|
134
125
|
elsif response
|
135
126
|
response
|
136
127
|
elsif perform_call
|
@@ -203,6 +194,17 @@ class HttpRouter
|
|
203
194
|
end
|
204
195
|
|
205
196
|
private
|
197
|
+
def no_response(env, perform_call = true)
|
198
|
+
supported_methods = (@known_methods - [env['REQUEST_METHOD']]).select do |m|
|
199
|
+
test_env = ::Rack::Request.new(env.clone)
|
200
|
+
test_env.env['REQUEST_METHOD'] = m
|
201
|
+
test_env.env['_HTTP_ROUTER_405_TESTING_ACCEPTANCE'] = true
|
202
|
+
test_request = Request.new(test_env.path_info, test_env, 405)
|
203
|
+
catch(:success) { @root[test_request] }
|
204
|
+
end
|
205
|
+
supported_methods.empty? ? (perform_call ? @default_app.call(env) : nil) : [405, {'Allow' => supported_methods.sort.join(", ")}, []]
|
206
|
+
end
|
207
|
+
|
206
208
|
def add_with_request_method(path, method, opts = {}, &app)
|
207
209
|
route = add(path, opts).send(method.to_sym)
|
208
210
|
route.to(app) if app
|
data/lib/http_router/node.rb
CHANGED
@@ -18,8 +18,7 @@ class HttpRouter
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def [](request)
|
21
|
-
@matchers.each {|m| m[request] }
|
22
|
-
nil
|
21
|
+
@matchers.each {|m| m[request] }; nil
|
23
22
|
end
|
24
23
|
|
25
24
|
def add_variable
|
@@ -66,11 +65,8 @@ class HttpRouter
|
|
66
65
|
end
|
67
66
|
|
68
67
|
def unescape(val)
|
69
|
-
val.to_s.gsub(/((?:%[0-9a-fA-F]{2})+)/n){ [$1.delete('%')].pack('H*') }
|
70
|
-
|
71
|
-
|
72
|
-
def join_whole_path(request)
|
73
|
-
request.path * '/'
|
68
|
+
val.to_s.gsub!(/((?:%[0-9a-fA-F]{2})+)/n){ [$1.delete('%')].pack('H*') }
|
69
|
+
val
|
74
70
|
end
|
75
71
|
end
|
76
72
|
end
|
@@ -8,10 +8,12 @@ class HttpRouter
|
|
8
8
|
|
9
9
|
def [](request)
|
10
10
|
if request.path.empty? or (request.path.size == 1 and request.path[0] == '') or @allow_partial
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
11
|
+
catch(:pass) do
|
12
|
+
request = request.clone
|
13
|
+
request.continue = proc { |state| super(request) if state }
|
14
|
+
params = @param_names.nil? ? {} : Hash[@param_names.zip(request.params)]
|
15
|
+
@blk.call(request, params)
|
16
|
+
end
|
15
17
|
end
|
16
18
|
end
|
17
19
|
end
|
@@ -8,7 +8,7 @@ class HttpRouter
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def [](request)
|
11
|
-
whole_path = "/#{
|
11
|
+
whole_path = "/#{request.joined_path}"
|
12
12
|
if match = @matcher.match(whole_path) and match[0].size == whole_path.size
|
13
13
|
request = request.clone
|
14
14
|
request.extra_env['router.regex_match'] = match
|
@@ -2,7 +2,7 @@ class HttpRouter
|
|
2
2
|
class Node
|
3
3
|
class SpanningRegex < Regex
|
4
4
|
def [](request)
|
5
|
-
whole_path =
|
5
|
+
whole_path = request.joined_path
|
6
6
|
if match = @matcher.match(whole_path) and match.begin(0).zero?
|
7
7
|
request = request.clone
|
8
8
|
add_params(request, match)
|
data/lib/http_router/request.rb
CHANGED
data/lib/http_router/route.rb
CHANGED
@@ -10,19 +10,22 @@ class HttpRouter
|
|
10
10
|
@original_path = path
|
11
11
|
@path = path
|
12
12
|
@opts = opts
|
13
|
-
@arbitrary = opts[:arbitrary] || opts[:__arbitrary__]
|
14
|
-
@conditions = opts[:conditions] || opts[:__conditions__] || {}
|
15
|
-
name(opts[:name]) if opts.key?(:name)
|
16
|
-
@opts.merge!(opts[:matching]) if opts[:matching]
|
17
13
|
@matches_with = {}
|
18
14
|
@default_values = opts[:default_values] || {}
|
19
15
|
if @original_path[-1] == ?*
|
20
16
|
@match_partially = true
|
21
17
|
path.slice!(-1)
|
22
|
-
elsif opts.key?(:partial)
|
23
|
-
@match_partially = opts[:partial]
|
24
18
|
end
|
25
19
|
@paths = OptionalCompiler.new(path).paths
|
20
|
+
process_opts
|
21
|
+
end
|
22
|
+
|
23
|
+
def process_opts
|
24
|
+
@arbitrary = @opts[:arbitrary] || @opts[:__arbitrary__]
|
25
|
+
@conditions = @opts[:conditions] || @opts[:__conditions__] || {}
|
26
|
+
@opts.merge!(@opts[:matching]) if @opts[:matching]
|
27
|
+
@match_partially = @opts[:partial] if @match_partially.nil? && @opts.key?(:partial)
|
28
|
+
name(@opts[:name]) if @opts.key?(:name)
|
26
29
|
end
|
27
30
|
|
28
31
|
def as_options
|
@@ -252,29 +255,27 @@ class HttpRouter
|
|
252
255
|
private
|
253
256
|
def add_non_path_to_tree(node, path, names)
|
254
257
|
path_obj = Path.new(self, path, names)
|
255
|
-
destination = Proc.new
|
256
|
-
if
|
257
|
-
if req.
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
env['SCRIPT_NAME'] += req.rack_request.path_info[0, req.rack_request.path_info.size - env['PATH_INFO'].size]
|
265
|
-
else
|
266
|
-
env["PATH_INFO"] = ''
|
267
|
-
env["SCRIPT_NAME"] += req.rack_request.path_info
|
268
|
-
end
|
269
|
-
response = path_obj.route.dest.call(env)
|
270
|
-
router.pass_on_response(response) ? throw(:pass) : throw(:success, response)
|
258
|
+
destination = Proc.new do |req, params|
|
259
|
+
if req.path.empty? or match_partially? or (@router.ignore_trailing_slash? and req.path.size == 1 and req.path.last == '')
|
260
|
+
if req.perform_call
|
261
|
+
env = req.rack_request.dup.env
|
262
|
+
env['router.params'] ||= {}
|
263
|
+
env['router.params'].merge!(path_obj.hashify_params(req.params))
|
264
|
+
matched = if match_partially?
|
265
|
+
env['PATH_INFO'] = "/#{req.path.join('/')}"
|
266
|
+
env['SCRIPT_NAME'] += req.rack_request.path_info[0, req.rack_request.path_info.size - env['PATH_INFO'].size]
|
271
267
|
else
|
272
|
-
|
268
|
+
env["PATH_INFO"] = ''
|
269
|
+
env["SCRIPT_NAME"] += req.rack_request.path_info
|
273
270
|
end
|
271
|
+
response = path_obj.route.dest.call(env)
|
272
|
+
router.pass_on_response(response) ? throw(:pass) : throw(:success, response)
|
273
|
+
else
|
274
|
+
throw :success, Response.new(req, path_obj)
|
274
275
|
end
|
275
276
|
end
|
276
|
-
|
277
|
-
node = node.add_request(@conditions)
|
277
|
+
end
|
278
|
+
node = node.add_request(@conditions) unless @conditions.empty?
|
278
279
|
@arbitrary.each{|a| node = node.add_arbitrary(a, match_partially?, names)} if @arbitrary
|
279
280
|
node.add_destination(destination, @match_partially)
|
280
281
|
if dest.respond_to?(:url_mount=)
|
data/lib/http_router/version.rb
CHANGED
data/test/test_arbitrary.rb
CHANGED
@@ -48,6 +48,14 @@ class TestArbitrary < MiniTest::Unit::TestCase
|
|
48
48
|
assert_route r, '/test', {:test => 'test'}
|
49
49
|
end
|
50
50
|
|
51
|
+
def test_passing
|
52
|
+
never, route = router {
|
53
|
+
add('test').arbitrary(Proc.new{|req, params| throw :pass })
|
54
|
+
add("test")
|
55
|
+
}
|
56
|
+
assert_route route, 'http://lovelove:8080/test'
|
57
|
+
end
|
58
|
+
|
51
59
|
def test_continue
|
52
60
|
no, yes = router {
|
53
61
|
add('test').arbitrary_with_continue{|req, p| req.continue[false]}
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: http_router
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 5
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 7
|
9
|
-
-
|
10
|
-
version: 0.7.
|
9
|
+
- 3
|
10
|
+
version: 0.7.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-04-
|
18
|
+
date: 2011-04-26 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|