http_router 0.7.2 → 0.7.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/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
|