howl-router 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/howl-router.rb +7 -5
- data/lib/howl-router/matcher.rb +2 -2
- data/lib/howl-router/padrino/core.rb +23 -5
- data/lib/howl-router/padrino/ext/class_methods.rb +18 -2
- data/lib/howl-router/padrino/route.rb +2 -2
- data/lib/howl-router/route.rb +2 -3
- data/lib/howl-router/router.rb +33 -27
- data/lib/howl-router/version.rb +1 -1
- data/test/howl_test.rb +27 -2
- data/test/padrino_test.rb +15 -15
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dfff431b9195d8c14a112b7b379afd00c0bf4c04
|
4
|
+
data.tar.gz: 50df61f61b201f3a22d14e0e62a1ddf6d125bc6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5926b02c4d7cdc8a1d126f6229c9af946b2a1655115ae34545e3acee887eea749c9232375a8a2fb11749b2526197ef7834c5b1a5642c1ded6c724b43c389bacf
|
7
|
+
data.tar.gz: d4bb4df2257a0ac345677c052a4859de0826b0f47f41f51a97f116b9dd6f73d9360a3f6b63a4d15f042c26d21535c94ba6da01fd0567f171658a893f8f37f244
|
data/lib/howl-router.rb
CHANGED
@@ -16,6 +16,10 @@ class Howl
|
|
16
16
|
:server_error => 500
|
17
17
|
}
|
18
18
|
|
19
|
+
def initialize(&block)
|
20
|
+
instance_eval(&block) if block_given?
|
21
|
+
end
|
22
|
+
|
19
23
|
# Generate a route, and add to routes.
|
20
24
|
#
|
21
25
|
# @param [String, Symbol] verb The verb decide a acceptable request method.
|
@@ -30,10 +34,8 @@ class Howl
|
|
30
34
|
# @return [Howl::Route] Return a generated Howl::Route instance.
|
31
35
|
#
|
32
36
|
def add(verb, path, options = {}, &block)
|
33
|
-
|
34
|
-
|
35
|
-
route.path_for_generation = options[:path_for_generation] if options[:path_for_generation]
|
36
|
-
route.verb = verb
|
37
|
+
route = Route.new(path, &block)
|
38
|
+
route.verb = verb.downcase.to_sym
|
37
39
|
route.router = router
|
38
40
|
router.routes << route
|
39
41
|
route
|
@@ -149,7 +151,7 @@ class Howl
|
|
149
151
|
else
|
150
152
|
params_for_expand = params.dup
|
151
153
|
end
|
152
|
-
return matcher.mustermann? ? matcher.expand(params_for_expand) : route.
|
154
|
+
return matcher.mustermann? ? matcher.expand(params_for_expand) : route.path
|
153
155
|
end
|
154
156
|
raise InvalidRouteException
|
155
157
|
end
|
data/lib/howl-router/matcher.rb
CHANGED
@@ -49,7 +49,7 @@ class Howl
|
|
49
49
|
|
50
50
|
# @return [Boolean] This matcher's handler is mustermann ?
|
51
51
|
def mustermann?
|
52
|
-
handler.
|
52
|
+
handler.instance_of?(Mustermann::Sinatra)
|
53
53
|
end
|
54
54
|
|
55
55
|
# @return [Mustermann::Rails] Return a Mustermann::Rails when @path is string.
|
@@ -57,7 +57,7 @@ class Howl
|
|
57
57
|
def handler
|
58
58
|
@handler ||= case @path
|
59
59
|
when String
|
60
|
-
Mustermann.new(@path, :
|
60
|
+
Mustermann.new(@path, :capture => @capture)
|
61
61
|
when Regexp
|
62
62
|
/^(?:#{@path})$/
|
63
63
|
end
|
@@ -4,10 +4,9 @@ class Howl
|
|
4
4
|
module Padrino
|
5
5
|
class Core < ::Howl
|
6
6
|
def add(verb, path, options = {}, &block)
|
7
|
-
|
8
|
-
(router.routes_with_verbs[verb] ||= []) << (route = Route.new(path, &block))
|
7
|
+
route = Route.new(path, &block)
|
9
8
|
route.path_for_generation = options[:path_for_generation] if options[:path_for_generation]
|
10
|
-
route.verb = verb
|
9
|
+
route.verb = verb.downcase.to_sym
|
11
10
|
route.router = router
|
12
11
|
router.routes << route
|
13
12
|
route
|
@@ -16,9 +15,7 @@ class Howl
|
|
16
15
|
def call(env)
|
17
16
|
request = Request.new(env)
|
18
17
|
return bad_request unless HTTP_VERBS.include?(request.request_method.downcase.to_sym)
|
19
|
-
|
20
18
|
compile unless compiled?
|
21
|
-
|
22
19
|
begin
|
23
20
|
matched_routes = recognize(request)
|
24
21
|
[200, {}, matched_routes]
|
@@ -31,6 +28,27 @@ class Howl
|
|
31
28
|
end
|
32
29
|
end
|
33
30
|
|
31
|
+
def path(name, *args)
|
32
|
+
params = args.delete_at(args.last.is_a?(Hash) ? -1 : 0) || {}
|
33
|
+
saved_args = args.dup
|
34
|
+
router.routes.each do |route|
|
35
|
+
next unless route.name == name
|
36
|
+
matcher = route.matcher
|
37
|
+
if !args.empty? and matcher.mustermann?
|
38
|
+
matcher_names = matcher.names
|
39
|
+
params_for_expand = Hash[matcher_names.map{|matcher_name|
|
40
|
+
[matcher_name.to_sym, (params[matcher_name.to_sym] || args.shift)]
|
41
|
+
}]
|
42
|
+
params_for_expand.merge!(Hash[params.select{|k, v| !matcher_names.include?(name.to_sym) }])
|
43
|
+
args = saved_args.dup
|
44
|
+
else
|
45
|
+
params_for_expand = params.dup
|
46
|
+
end
|
47
|
+
return matcher.mustermann? ? matcher.expand(params_for_expand) : route.path_for_generation
|
48
|
+
end
|
49
|
+
raise InvalidRouteException
|
50
|
+
end
|
51
|
+
|
34
52
|
private
|
35
53
|
|
36
54
|
def generate_response(key, headers = {})
|
@@ -2,7 +2,7 @@
|
|
2
2
|
class Howl
|
3
3
|
module Padrino
|
4
4
|
module ClassMethods
|
5
|
-
CONTENT_TYPE_ALIASES = {
|
5
|
+
CONTENT_TYPE_ALIASES = {:htm => :html} unless defined?(CONTENT_TYPE_ALIASES)
|
6
6
|
ROUTE_PRIORITY = {:high => 0, :normal => 1, :low => 2} unless defined?(ROUTE_PRIORITY)
|
7
7
|
|
8
8
|
def router
|
@@ -92,7 +92,7 @@ class Howl
|
|
92
92
|
invoke_hook(:route_added, verb, path, block)
|
93
93
|
|
94
94
|
# Howl route construction
|
95
|
-
path[0, 0] = "/" if path == "(.:format)"
|
95
|
+
path[0, 0] = "/" if path == "(.:format)?"
|
96
96
|
route = router.add(verb.downcase.to_sym, path, route_options)
|
97
97
|
route.name = name if name
|
98
98
|
route.action = action
|
@@ -139,6 +139,7 @@ class Howl
|
|
139
139
|
mime_types = types.map {|t| mime_type(t) }.compact
|
140
140
|
url_format = params[:format].to_sym if params[:format]
|
141
141
|
accepts = request.accept.map {|a| a.to_str }
|
142
|
+
accepts = [] if accepts == ["*/*"]
|
142
143
|
|
143
144
|
# per rfc2616-sec14:
|
144
145
|
# Assume */* if no ACCEPT header is given.
|
@@ -175,6 +176,21 @@ class Howl
|
|
175
176
|
matched_format
|
176
177
|
end
|
177
178
|
end
|
179
|
+
|
180
|
+
def process_path_for_parent_params(path, parent_params)
|
181
|
+
parent_prefix = parent_params.flatten.compact.uniq.map do |param|
|
182
|
+
map = (param.respond_to?(:map) && param.map ? param.map : param.to_s)
|
183
|
+
part = "#{map}/:#{param.to_s.singularize}_id/"
|
184
|
+
part = "(#{part})?" if param.respond_to?(:optional) && param.optional?
|
185
|
+
part
|
186
|
+
end
|
187
|
+
|
188
|
+
[parent_prefix, path].flatten.join("")
|
189
|
+
end
|
190
|
+
|
191
|
+
def process_path_for_provides(path, format_params)
|
192
|
+
path << "(.:format)?" unless path[-11, 11] == '(.:format)?'
|
193
|
+
end
|
178
194
|
end
|
179
195
|
end
|
180
196
|
end
|
@@ -3,8 +3,8 @@ require 'howl-router/route'
|
|
3
3
|
class Howl
|
4
4
|
module Padrino
|
5
5
|
class Route < ::Howl::Route
|
6
|
-
attr_accessor :action, :cache, :cache_key, :cache_expires_in,
|
7
|
-
:
|
6
|
+
attr_accessor :action, :cache, :cache_key, :cache_expires_in, :parent,
|
7
|
+
:use_layout, :controller, :user_agent, :path_for_generation
|
8
8
|
|
9
9
|
def before_filters(&block)
|
10
10
|
@_before_filters ||= []
|
data/lib/howl-router/route.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Howl
|
2
2
|
class Route
|
3
|
-
attr_accessor :block, :capture, :router, :
|
4
|
-
:order, :default_values, :
|
3
|
+
attr_accessor :block, :capture, :router, :name,
|
4
|
+
:order, :default_values, :verb
|
5
5
|
|
6
6
|
# @param [String, Regexp] path The path associate to this route.
|
7
7
|
# @yield The block associate to this route.
|
@@ -15,7 +15,6 @@ class Howl
|
|
15
15
|
#
|
16
16
|
def initialize(path, &block)
|
17
17
|
@path = path
|
18
|
-
@params = {}
|
19
18
|
@capture = {}
|
20
19
|
@order = 0
|
21
20
|
@block = block if block_given?
|
data/lib/howl-router/router.rb
CHANGED
@@ -1,47 +1,33 @@
|
|
1
1
|
class Howl
|
2
2
|
class Router
|
3
|
-
attr_reader :current_order, :routes
|
3
|
+
attr_reader :current_order, :routes
|
4
4
|
|
5
5
|
def initialize
|
6
6
|
reset!
|
7
7
|
end
|
8
8
|
|
9
9
|
def recognize(request)
|
10
|
-
path_info, verb, request_params = request
|
11
|
-
[request.path_info, request.request_method, request.params]
|
12
|
-
verb = verb.downcase.to_sym
|
10
|
+
path_info, verb, request_params = parse_request(request)
|
13
11
|
ignore_slash_path_info = path_info
|
14
12
|
ignore_slash_path_info = path_info[0..-2] if path_info != "/" and path_info[-1] == "/"
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
result
|
20
|
-
end
|
21
|
-
|
22
|
-
all_matched_routes = @routes.select do |route|
|
23
|
-
matcher = route.matcher
|
24
|
-
matcher.match(matcher.mustermann? ? ignore_slash_path_info : path_info)
|
25
|
-
end
|
26
|
-
raise NotFound if all_matched_routes.empty?
|
27
|
-
|
28
|
-
raise_method_not_allowed(request, all_matched_routes) unless routes_with_verbs.has_key?(verb)
|
29
|
-
result = all_matched_routes.map{|route|
|
13
|
+
matched_routes = scan_routes(path_info, ignore_slash_path_info)
|
14
|
+
raise NotFound if matched_routes.empty?
|
15
|
+
raise_method_not_allowed(request, matched_routes) unless matched_routes.find{|r|r.verb == verb}
|
16
|
+
result = matched_routes.map do |route|
|
30
17
|
next unless verb == route.verb
|
31
18
|
params, matcher = {}, route.matcher
|
32
19
|
match_data = matcher.match(matcher.mustermann? ? ignore_slash_path_info : path_info)
|
33
20
|
if match_data.names.empty?
|
34
21
|
params[:captures] = match_data.captures
|
35
22
|
else
|
36
|
-
params.merge!(
|
23
|
+
params.merge!(match_data.names.inject({}){|result, name|
|
37
24
|
result[name.to_sym] = match_data[name] ? Rack::Utils.unescape(match_data[name]) : nil
|
38
25
|
result
|
39
26
|
}).merge!(request_params){|key, self_value, new_value| self_value || new_value }
|
40
27
|
end
|
41
28
|
[route, params]
|
42
|
-
|
43
|
-
raise_method_not_allowed(request,
|
44
|
-
result
|
29
|
+
end.compact
|
30
|
+
result.empty? ? raise_method_not_allowed(request, matched_routes) : result
|
45
31
|
end
|
46
32
|
|
47
33
|
def increment_order
|
@@ -50,18 +36,38 @@ class Howl
|
|
50
36
|
|
51
37
|
def compile
|
52
38
|
return if @current_order.zero?
|
53
|
-
@routes_with_verbs.each_value{|routes_with_verb|
|
54
|
-
routes_with_verb.sort!{|a, b| a.order <=> b.order }
|
55
|
-
}
|
56
39
|
@routes.sort!{|a, b| a.order <=> b.order }
|
57
40
|
end
|
58
41
|
|
59
42
|
def reset!
|
60
43
|
@routes = []
|
61
|
-
@routes_with_verbs = {}
|
62
44
|
@current_order = 0
|
63
45
|
end
|
64
46
|
|
47
|
+
private
|
48
|
+
|
49
|
+
def scan_routes(path_info, ignore_slash_path_info)
|
50
|
+
@routes.select do |route|
|
51
|
+
matcher = route.matcher
|
52
|
+
matcher.match(matcher.mustermann? ? ignore_slash_path_info : path_info)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def parse_request(request)
|
57
|
+
if request.is_a?(Hash)
|
58
|
+
[request['PATH_INFO'], request['REQUEST_METHOD'].downcase.to_sym, {}]
|
59
|
+
else
|
60
|
+
[request.path_info, request.request_method.downcase.to_sym, parse_request_params(request.params)]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse_request_params(params)
|
65
|
+
params.inject({}) do |result, entry|
|
66
|
+
result[entry[0].to_sym] = entry[1]
|
67
|
+
result
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
65
71
|
def raise_method_not_allowed(request, matched_routes)
|
66
72
|
request.acceptable_methods = matched_routes.map(&:verb)
|
67
73
|
raise MethodNotAllowed
|
data/lib/howl-router/version.rb
CHANGED
data/test/howl_test.rb
CHANGED
@@ -84,7 +84,7 @@ describe Howl do
|
|
84
84
|
describe "generate path" do
|
85
85
|
before(:each){ @howl.reset! }
|
86
86
|
|
87
|
-
should "basic route
|
87
|
+
should "basic route" do
|
88
88
|
index = @howl.add(:get, "/"){}
|
89
89
|
index.name = :index
|
90
90
|
foo_bar = @howl.add(:post, "/foo/bar"){}
|
@@ -97,7 +97,32 @@ describe Howl do
|
|
97
97
|
assert_equal @howl.path(:users, :user_id => 1), "/users/1"
|
98
98
|
assert_equal @howl.path(:users, :user_id => 1, :query => "string"), "/users/1?query=string"
|
99
99
|
end
|
100
|
-
end
|
101
100
|
|
101
|
+
should "regexp" do
|
102
|
+
index = @howl.add(:get, /.+?/){}
|
103
|
+
index.name = :index
|
104
|
+
foo_bar = @howl.add(:post, /\d+/){}
|
105
|
+
foo_bar.name = :foo_bar
|
106
|
+
|
107
|
+
assert_equal @howl.path(:index), /.+?/
|
108
|
+
assert_equal @howl.path(:foo_bar), /\d+/
|
109
|
+
end
|
110
|
+
end
|
102
111
|
|
112
|
+
describe "#new allows block" do
|
113
|
+
should "#new support for block." do
|
114
|
+
@app = Howl.new do
|
115
|
+
foo = add(:get, "/"){"foo"}
|
116
|
+
bar = add(:post, "/"){"bar"}
|
117
|
+
foo.name = :foo
|
118
|
+
bar.name = :bar
|
119
|
+
end
|
120
|
+
get("/")
|
121
|
+
assert_equal "foo", body
|
122
|
+
post("/")
|
123
|
+
assert_equal "bar", body
|
124
|
+
assert_equal @app.path(:foo), "/"
|
125
|
+
assert_equal @app.path(:bar), "/"
|
126
|
+
end
|
127
|
+
end
|
103
128
|
end
|
data/test/padrino_test.rb
CHANGED
@@ -448,14 +448,14 @@ describe "Howl::Padrino" do
|
|
448
448
|
should "should inject the action name into the request" do
|
449
449
|
mock_app do
|
450
450
|
controller :posts do
|
451
|
-
get('/omnomnom(/:id)') { request.action.inspect }
|
451
|
+
get('/omnomnom(/:id)?') { request.action.inspect }
|
452
452
|
controller :mini do
|
453
453
|
get([:a, :b, :c]) { request.action.inspect }
|
454
454
|
end
|
455
455
|
end
|
456
456
|
end
|
457
457
|
get "/posts/omnomnom"
|
458
|
-
assert_equal "\"/omnomnom(/:id)
|
458
|
+
assert_equal "\"/omnomnom(/:id)?\"", body
|
459
459
|
get "/mini/a/b/c"
|
460
460
|
assert_equal ":a", body
|
461
461
|
end
|
@@ -873,7 +873,7 @@ describe "Howl::Padrino" do
|
|
873
873
|
|
874
874
|
should 'allow optionals' do
|
875
875
|
mock_app do
|
876
|
-
get(:show, :map => "/stories/:type(/:category)") do
|
876
|
+
get(:show, :map => "/stories/:type(/:category)?") do
|
877
877
|
"#{params[:type]}/#{params[:category]}"
|
878
878
|
end
|
879
879
|
end
|
@@ -1129,17 +1129,17 @@ describe "Howl::Padrino" do
|
|
1129
1129
|
mock_app do
|
1130
1130
|
provides :xml
|
1131
1131
|
|
1132
|
-
get("/foo"){ "Foo in #{content_type}" }
|
1133
|
-
get("/bar"){ "Bar in #{content_type}" }
|
1132
|
+
get("/foo"){ "Foo in #{content_type.inspect}" }
|
1133
|
+
get("/bar"){ "Bar in #{content_type.inspect}" }
|
1134
1134
|
end
|
1135
1135
|
|
1136
1136
|
get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
|
1137
|
-
assert_equal 'Foo in xml', body
|
1137
|
+
assert_equal 'Foo in :xml', body
|
1138
1138
|
get '/foo'
|
1139
|
-
assert_equal 'Foo in xml', body
|
1139
|
+
assert_equal 'Foo in :xml', body
|
1140
1140
|
|
1141
1141
|
get '/bar', {}, { 'HTTP_ACCEPT' => 'application/xml' }
|
1142
|
-
assert_equal 'Bar in
|
1142
|
+
assert_equal 'Bar in nil', body
|
1143
1143
|
end
|
1144
1144
|
|
1145
1145
|
should "does not allow global provides in controller" do
|
@@ -1147,18 +1147,18 @@ describe "Howl::Padrino" do
|
|
1147
1147
|
controller :base do
|
1148
1148
|
provides :xml
|
1149
1149
|
|
1150
|
-
get(:foo, "/foo"){ "Foo in #{content_type}" }
|
1151
|
-
get(:bar, "/bar"){ "Bar in #{content_type}" }
|
1150
|
+
get(:foo, "/foo"){ "Foo in #{content_type.inspect}" }
|
1151
|
+
get(:bar, "/bar"){ "Bar in #{content_type.inspect}" }
|
1152
1152
|
end
|
1153
1153
|
end
|
1154
1154
|
|
1155
1155
|
get '/foo', {}, { 'HTTP_ACCEPT' => 'application/xml' }
|
1156
|
-
assert_equal 'Foo in xml', body
|
1156
|
+
assert_equal 'Foo in :xml', body
|
1157
1157
|
get '/foo'
|
1158
|
-
assert_equal 'Foo in xml', body
|
1158
|
+
assert_equal 'Foo in :xml', body
|
1159
1159
|
|
1160
1160
|
get '/bar', {}, { 'HTTP_ACCEPT' => 'application/xml' }
|
1161
|
-
assert_equal 'Bar in
|
1161
|
+
assert_equal 'Bar in nil', body
|
1162
1162
|
end
|
1163
1163
|
|
1164
1164
|
should "map non named routes in controllers" do
|
@@ -1385,7 +1385,7 @@ describe "Howl::Padrino" do
|
|
1385
1385
|
|
1386
1386
|
should 'works with optionals params' do
|
1387
1387
|
mock_app do
|
1388
|
-
get("/foo(/:bar)") { params[:bar] }
|
1388
|
+
get("/foo(/:bar)?") { params[:bar] }
|
1389
1389
|
end
|
1390
1390
|
|
1391
1391
|
get "/foo/bar"
|
@@ -1488,7 +1488,7 @@ describe "Howl::Padrino" do
|
|
1488
1488
|
|
1489
1489
|
should "use optionals params" do
|
1490
1490
|
mock_app do
|
1491
|
-
get(:index, :map => "
|
1491
|
+
get(:index, :map => "/:foo(/:bar)?") { "#{params[:foo]}-#{params[:bar]}" }
|
1492
1492
|
end
|
1493
1493
|
get "/foo"
|
1494
1494
|
assert_equal "foo-", body
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: howl-router
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- namusyaka
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|