roda 2.28.0 → 2.29.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.
- checksums.yaml +4 -4
- data/CHANGELOG +46 -0
- data/README.rdoc +25 -7
- data/doc/release_notes/2.29.0.txt +156 -0
- data/lib/roda.rb +25 -3
- data/lib/roda/plugins/_erubis_escaping.rb +2 -0
- data/lib/roda/plugins/_symbol_regexp_matchers.rb +22 -0
- data/lib/roda/plugins/assets.rb +3 -2
- data/lib/roda/plugins/branch_locals.rb +74 -0
- data/lib/roda/plugins/caching.rb +15 -7
- data/lib/roda/plugins/chunked.rb +10 -7
- data/lib/roda/plugins/content_for.rb +4 -1
- data/lib/roda/plugins/drop_body.rb +3 -2
- data/lib/roda/plugins/error_email.rb +3 -2
- data/lib/roda/plugins/error_mail.rb +3 -2
- data/lib/roda/plugins/head.rb +2 -1
- data/lib/roda/plugins/header_matchers.rb +3 -0
- data/lib/roda/plugins/heartbeat.rb +3 -2
- data/lib/roda/plugins/json.rb +5 -3
- data/lib/roda/plugins/json_parser.rb +3 -2
- data/lib/roda/plugins/mailer.rb +3 -3
- data/lib/roda/plugins/match_affix.rb +6 -0
- data/lib/roda/plugins/multi_route.rb +3 -1
- data/lib/roda/plugins/padrino_render.rb +3 -2
- data/lib/roda/plugins/params_capturing.rb +3 -3
- data/lib/roda/plugins/partials.rb +3 -3
- data/lib/roda/plugins/path.rb +4 -2
- data/lib/roda/plugins/path_rewriter.rb +2 -2
- data/lib/roda/plugins/per_thread_caching.rb +2 -0
- data/lib/roda/plugins/placeholder_string_matchers.rb +42 -0
- data/lib/roda/plugins/precompile_templates.rb +3 -2
- data/lib/roda/plugins/render.rb +86 -37
- data/lib/roda/plugins/render_each.rb +2 -1
- data/lib/roda/plugins/render_locals.rb +102 -0
- data/lib/roda/plugins/run_append_slash.rb +2 -1
- data/lib/roda/plugins/run_handler.rb +2 -1
- data/lib/roda/plugins/sinatra_helpers.rb +4 -4
- data/lib/roda/plugins/static_path_info.rb +2 -0
- data/lib/roda/plugins/static_routing.rb +1 -1
- data/lib/roda/plugins/streaming.rb +9 -4
- data/lib/roda/plugins/symbol_matchers.rb +23 -20
- data/lib/roda/plugins/view_options.rb +63 -28
- data/lib/roda/plugins/view_subdirs.rb +1 -0
- data/lib/roda/plugins/websockets.rb +2 -0
- data/lib/roda/version.rb +1 -1
- data/spec/composition_spec.rb +2 -2
- data/spec/matchers_spec.rb +6 -5
- data/spec/plugin/_erubis_escaping_spec.rb +5 -5
- data/spec/plugin/backtracking_array_spec.rb +0 -2
- data/spec/plugin/branch_locals_spec.rb +88 -0
- data/spec/plugin/content_for_spec.rb +8 -2
- data/spec/plugin/halt_spec.rb +8 -0
- data/spec/plugin/header_matchers_spec.rb +20 -5
- data/spec/plugin/multi_route_spec.rb +1 -1
- data/spec/plugin/named_templates_spec.rb +2 -2
- data/spec/plugin/params_capturing_spec.rb +1 -1
- data/spec/plugin/per_thread_caching_spec.rb +1 -1
- data/spec/plugin/placeholder_string_matchers_spec.rb +159 -0
- data/spec/plugin/render_locals_spec.rb +114 -0
- data/spec/plugin/render_spec.rb +83 -8
- data/spec/plugin/streaming_spec.rb +104 -4
- data/spec/plugin/symbol_matchers_spec.rb +1 -1
- data/spec/plugin/view_options_spec.rb +83 -7
- data/spec/plugin/websockets_spec.rb +7 -8
- data/spec/spec_helper.rb +22 -2
- metadata +11 -2
|
@@ -20,7 +20,7 @@ describe "_erubis_escaping plugin" do
|
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
deprecated "should escape inside <%= %> and not inside <%== %>, and handle postfix conditionals" do
|
|
24
24
|
app(:bare) do
|
|
25
25
|
plugin :render, :escape=>true
|
|
26
26
|
|
|
@@ -32,7 +32,7 @@ describe "_erubis_escaping plugin" do
|
|
|
32
32
|
body.must_equal '<> <>'
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
deprecated "should consider classes in :escape_safe_classes as safe" do
|
|
36
36
|
c = Class.new(String)
|
|
37
37
|
c2 = Class.new(String)
|
|
38
38
|
app(:bare) do
|
|
@@ -47,7 +47,7 @@ describe "_erubis_escaping plugin" do
|
|
|
47
47
|
body.must_equal '<> <>'
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
deprecated "should covnert arguments to strings when escaping with safe classes" do
|
|
51
51
|
app(:bare) do
|
|
52
52
|
plugin :render, :escape=>true, :escape_safe_classes=>[]
|
|
53
53
|
|
|
@@ -59,7 +59,7 @@ describe "_erubis_escaping plugin" do
|
|
|
59
59
|
body.must_equal '<> <>'
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
deprecated "should allow use of custom :escaper" do
|
|
63
63
|
escaper = Object.new
|
|
64
64
|
def escaper.escape_xml(s)
|
|
65
65
|
s.gsub("'", "''")
|
|
@@ -75,7 +75,7 @@ describe "_erubis_escaping plugin" do
|
|
|
75
75
|
body.must_equal "ab''1 ab'1"
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
deprecated "should allow for per-branch escaping via set_view options" do
|
|
79
79
|
app(:bare) do
|
|
80
80
|
plugin :render, :escape=>true
|
|
81
81
|
plugin :view_options
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
|
|
2
|
+
|
|
3
|
+
begin
|
|
4
|
+
require 'tilt/erb'
|
|
5
|
+
rescue LoadError
|
|
6
|
+
warn "tilt not installed, skipping branch_locals plugin test"
|
|
7
|
+
else
|
|
8
|
+
|
|
9
|
+
describe "branch_locals plugin" do
|
|
10
|
+
it "should set view and layout locals to use" do
|
|
11
|
+
app(:branch_locals) do
|
|
12
|
+
set_view_locals :title=>'About Roda'
|
|
13
|
+
set_layout_locals :title=>'Home'
|
|
14
|
+
view(:inline=>'<h1><%= title %></h1>', :layout=>{:inline=>"<title>Alternative Layout: <%= title %></title>\n<%= yield %>"})
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
body.strip.must_equal "<title>Alternative Layout: Home</title>\n<h1>About Roda</h1>"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should merge multiple calls to set view and layout locals" do
|
|
21
|
+
app(:branch_locals) do
|
|
22
|
+
set_layout_locals :title=>'About Roda'
|
|
23
|
+
set_view_locals :title=>'Home'
|
|
24
|
+
|
|
25
|
+
set_layout_locals :a=>'A'
|
|
26
|
+
set_view_locals :b=>'B'
|
|
27
|
+
|
|
28
|
+
view(:inline=>'<%= title %>:<%= b %>', :layout=>{:inline=>"<%= title %>:<%= a %>::<%= yield %>"})
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
body.strip.must_equal "About Roda:A::Home:B"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should merge multiple calls in the correct order" do
|
|
35
|
+
app(:branch_locals) do
|
|
36
|
+
set_layout_locals :title=>'Roda'
|
|
37
|
+
set_view_locals :title=>'H'
|
|
38
|
+
|
|
39
|
+
set_layout_locals :a=>'A', :title=>'About Roda'
|
|
40
|
+
set_view_locals :b=>'B', :title=>'Home'
|
|
41
|
+
|
|
42
|
+
view(:inline=>'<%= title %>:<%= b %>', :layout=>{:inline=>"<%= title %>:<%= a %>::<%= yield %>"})
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
body.strip.must_equal "About Roda:A::Home:B"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "should have set_view_locals have more precedence than plugin options, but less than view/render method options" do
|
|
49
|
+
app(:bare) do
|
|
50
|
+
plugin :render, :views=>"./spec/views", :layout_opts=>{:template=>'multiple-layout'}
|
|
51
|
+
plugin :render_locals, :render=>{:title=>'Home', :b=>'B'}, :layout=>{:title=>'About Roda', :a=>'A'}
|
|
52
|
+
plugin :branch_locals
|
|
53
|
+
|
|
54
|
+
route do |r|
|
|
55
|
+
r.is 'c' do
|
|
56
|
+
view(:multiple)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
set_view_locals :b=>'BB'
|
|
60
|
+
set_layout_locals :a=>'AA'
|
|
61
|
+
|
|
62
|
+
r.on 'b' do
|
|
63
|
+
set_view_locals :title=>'About'
|
|
64
|
+
set_layout_locals :title=>'Roda'
|
|
65
|
+
|
|
66
|
+
r.is 'a' do
|
|
67
|
+
view(:multiple)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
view("multiple", :locals=>{:b => "BBB"}, :layout_opts=>{:locals=>{:a=>'AAA'}})
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
r.is 'a' do
|
|
74
|
+
view(:multiple)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
view("multiple", :locals=>{:b => "BBB"}, :layout_opts=>{:locals=>{:a=>'AAA'}})
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
body('/c').strip.must_equal "About Roda:A::Home:B"
|
|
82
|
+
body('/b/a').strip.must_equal "Roda:AA::About:BB"
|
|
83
|
+
body('/b').strip.must_equal "Roda:AAA::About:BBB"
|
|
84
|
+
body('/a').strip.must_equal "About Roda:AA::Home:BB"
|
|
85
|
+
body.strip.must_equal "About Roda:AAA::Home:BBB"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
@@ -52,11 +52,17 @@ describe "content_for plugin with multiple calls to the same key" do
|
|
|
52
52
|
end
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
deprecated "should replace with multiple calls to the same key by default" do
|
|
56
56
|
body.strip.must_equal "bar baz"
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
it "should
|
|
59
|
+
it "should replace with multiple calls to the same key if :append=>false plugin option is used" do
|
|
60
|
+
app.plugin :content_for, :append => false
|
|
61
|
+
body.strip.must_equal "bar baz"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# RODA3: Make default behavior
|
|
65
|
+
it "should append with multiple calls to the same key if :append=>true plugin option is used" do
|
|
60
66
|
app.plugin :content_for, :append => true
|
|
61
67
|
body.strip.must_equal "bar foobaz"
|
|
62
68
|
end
|
data/spec/plugin/halt_spec.rb
CHANGED
|
@@ -102,6 +102,14 @@ describe "halt plugin" do
|
|
|
102
102
|
end
|
|
103
103
|
|
|
104
104
|
it "should raise an error for single argument not integer, String, or Array" do
|
|
105
|
+
app(:halt) do |r|
|
|
106
|
+
r.halt nil
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
proc{req}.must_raise(Roda::RodaError)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
deprecated "should raise an error for single argument not integer, String, or Array" do
|
|
105
113
|
app(:halt) do |r|
|
|
106
114
|
r.halt('a'=>'b')
|
|
107
115
|
end
|
|
@@ -14,7 +14,8 @@ describe "accept matcher" do
|
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
describe "header matcher" do
|
|
17
|
-
|
|
17
|
+
# RODA3: undeprecate, and switch http-accept to accept
|
|
18
|
+
deprecated "should match if header present" do
|
|
18
19
|
app(:header_matchers) do |r|
|
|
19
20
|
r.on :header=>"http-accept" do
|
|
20
21
|
"bar"
|
|
@@ -28,15 +29,17 @@ describe "header matcher" do
|
|
|
28
29
|
|
|
29
30
|
it "should yield the header value" do
|
|
30
31
|
app(:header_matchers) do |r|
|
|
31
|
-
r.on :header=>"
|
|
32
|
+
r.on :header=>"accept" do |v|
|
|
32
33
|
"bar-#{v}"
|
|
33
34
|
end
|
|
34
35
|
end
|
|
35
36
|
|
|
37
|
+
app.opts[:header_matcher_prefix] = true
|
|
36
38
|
body("HTTP_ACCEPT" => "application/xml").must_equal "bar-application/xml"
|
|
37
39
|
status.must_equal 404
|
|
38
40
|
end
|
|
39
41
|
|
|
42
|
+
# RODA3: Remove
|
|
40
43
|
it "should automatically use HTTP prefix for headers if :header_matcher_prefix is set" do
|
|
41
44
|
app(:bare) do
|
|
42
45
|
plugin :header_matchers
|
|
@@ -65,7 +68,8 @@ describe "host matcher" do
|
|
|
65
68
|
status("HTTP_HOST" => "foo.com").must_equal 404
|
|
66
69
|
end
|
|
67
70
|
|
|
68
|
-
|
|
71
|
+
# RODA3: switch deprecated to it
|
|
72
|
+
deprecated "should match a host with a regexp" do
|
|
69
73
|
app(:header_matchers) do |r|
|
|
70
74
|
r.on :host=>/example/ do
|
|
71
75
|
"worked"
|
|
@@ -76,7 +80,7 @@ describe "host matcher" do
|
|
|
76
80
|
status("HTTP_HOST" => "foo.com").must_equal 404
|
|
77
81
|
end
|
|
78
82
|
|
|
79
|
-
it "doesn't yield host" do
|
|
83
|
+
it "doesn't yield host if given a string" do
|
|
80
84
|
app(:header_matchers) do |r|
|
|
81
85
|
r.on :host=>"example.com" do |*args|
|
|
82
86
|
args.size.to_s
|
|
@@ -86,7 +90,7 @@ describe "host matcher" do
|
|
|
86
90
|
body("HTTP_HOST" => "example.com").must_equal '0'
|
|
87
91
|
end
|
|
88
92
|
|
|
89
|
-
|
|
93
|
+
deprecated "doesn't yield host if passed a regexp" do
|
|
90
94
|
app(:header_matchers) do |r|
|
|
91
95
|
r.on :host=>/\A(.*)\.example\.com\z/ do |*m|
|
|
92
96
|
m.empty? ? '0' : m[0]
|
|
@@ -94,10 +98,21 @@ describe "host matcher" do
|
|
|
94
98
|
end
|
|
95
99
|
|
|
96
100
|
body("HTTP_HOST" => "foo.example.com").must_equal '0'
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# RODA3: Remove :host_matcher_captures setting
|
|
104
|
+
it "yields host if passed a regexp and opts[:host_matcher_captures] is set" do
|
|
105
|
+
app(:header_matchers) do |r|
|
|
106
|
+
r.on :host=>/\A(.*)\.example\.com\z/ do |*m|
|
|
107
|
+
m.empty? ? '0' : m[0]
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
97
111
|
app.opts[:host_matcher_captures] = true
|
|
98
112
|
body("HTTP_HOST" => "foo.example.com").must_equal 'foo'
|
|
99
113
|
end
|
|
100
114
|
|
|
115
|
+
# RODA3: Remove
|
|
101
116
|
it "doesn't yields host if passed a string and opts[:host_matcher_captures] is set" do
|
|
102
117
|
app(:header_matchers) do |r|
|
|
103
118
|
r.on :host=>'example.com' do |*m|
|
|
@@ -171,7 +171,7 @@ describe "multi_route plugin" do
|
|
|
171
171
|
end
|
|
172
172
|
|
|
173
173
|
describe "multi_route plugin" do
|
|
174
|
-
|
|
174
|
+
deprecated "r.multi_route works even without routes defined" do
|
|
175
175
|
app(:multi_route) do |r|
|
|
176
176
|
r.multi_route
|
|
177
177
|
'a'
|
|
@@ -55,10 +55,10 @@ describe "named_templates plugin" do
|
|
|
55
55
|
proc{app.template(:b){"a"}}.must_raise
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
-
it "works with the
|
|
58
|
+
it "works with the view_options plugin" do
|
|
59
59
|
app(:bare) do
|
|
60
60
|
plugin :render
|
|
61
|
-
plugin :
|
|
61
|
+
plugin :view_options
|
|
62
62
|
plugin :named_templates
|
|
63
63
|
|
|
64
64
|
template "foo/bar" do
|
|
@@ -31,7 +31,7 @@ describe "params_capturing plugin" do
|
|
|
31
31
|
body('/quux/asdf/890', 'rack.input'=>StringIO.new).must_equal 'y--890-quux-asdf-890-3'
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
deprecated "should add captures to r.params for string matchers" do
|
|
35
35
|
app(:params_capturing) do |r|
|
|
36
36
|
r.on("bar/:foo") do |foo|
|
|
37
37
|
"b-#{foo}-#{r[:foo]}-#{r[:captures].length}"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
|
|
2
2
|
|
|
3
3
|
describe "per_thread_caching plugin" do
|
|
4
|
-
|
|
4
|
+
deprecated "should use a per thread cache instead of a shared cache" do
|
|
5
5
|
app(:bare) do
|
|
6
6
|
plugin :per_thread_caching
|
|
7
7
|
@c = thread_safe_cache
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
|
|
2
|
+
|
|
3
|
+
describe "placeholder_string_matchers plugin" do
|
|
4
|
+
it "should handle string with embedded param" do
|
|
5
|
+
app(:placeholder_string_matchers) do |r|
|
|
6
|
+
r.on "posts/:id" do |id|
|
|
7
|
+
id
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
r.on "responses-:id" do |id|
|
|
11
|
+
id
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
body('/posts/123').must_equal '123'
|
|
16
|
+
status('/post/123').must_equal 404
|
|
17
|
+
body('/responses-123').must_equal '123'
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should handle multiple params in single string" do
|
|
21
|
+
app(:placeholder_string_matchers) do |r|
|
|
22
|
+
r.on "u/:uid/posts/:id" do |uid, id|
|
|
23
|
+
uid + id
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
body("/u/jdoe/posts/123").must_equal 'jdoe123'
|
|
28
|
+
status("/u/jdoe/pots/123").must_equal 404
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should escape regexp metacharaters in string" do
|
|
32
|
+
app(:placeholder_string_matchers) do |r|
|
|
33
|
+
r.on "u/:uid/posts?/:id" do |uid, id|
|
|
34
|
+
uid + id
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
body("/u/jdoe/posts?/123").must_equal 'jdoe123'
|
|
39
|
+
status("/u/jdoe/post/123").must_equal 404
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should handle colons by themselves" do
|
|
43
|
+
app(:placeholder_string_matchers) do |r|
|
|
44
|
+
r.on "u/:/:uid/posts/::id" do |uid, id|
|
|
45
|
+
uid + id
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
body("/u/:/jdoe/posts/:123").must_equal 'jdoe123'
|
|
50
|
+
status("/u/a/jdoe/post/b123").must_equal 404
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "should work with params_capturing plugin to add captures to r.params for string matchers" do
|
|
54
|
+
app(:bare) do
|
|
55
|
+
plugin :placeholder_string_matchers
|
|
56
|
+
plugin :params_capturing
|
|
57
|
+
|
|
58
|
+
route do |r|
|
|
59
|
+
r.on("bar/:foo") do |foo|
|
|
60
|
+
"b-#{foo}-#{r[:foo]}-#{r[:captures].length}"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
r.on("baz/:bar", :foo) do |bar, foo|
|
|
64
|
+
"b-#{bar}-#{foo}-#{r[:bar]}-#{r[:foo]}-#{r[:captures].length}"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
body('/bar/banana', 'rack.input'=>StringIO.new).must_equal 'b-banana-banana-1'
|
|
70
|
+
body('/baz/ban/ana', 'rack.input'=>StringIO.new).must_equal 'b-ban-ana-ban-ana-2'
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "works with symbol_matchers plugin" do
|
|
74
|
+
app(:bare) do
|
|
75
|
+
plugin :placeholder_string_matchers
|
|
76
|
+
plugin :symbol_matchers
|
|
77
|
+
symbol_matcher(:f, /(f+)/)
|
|
78
|
+
|
|
79
|
+
route do |r|
|
|
80
|
+
r.is ":d" do |d|
|
|
81
|
+
"d#{d}"
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
r.is "thing/:thing" do |d|
|
|
85
|
+
"thing#{d}"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
r.is "thing2", ":thing" do |d|
|
|
89
|
+
"thing2#{d}"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
r.is ":f" do |f|
|
|
93
|
+
"f#{f}"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
r.is 'q:rest' do |rest|
|
|
97
|
+
"rest#{rest}"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
r.is ":w" do |w|
|
|
101
|
+
"w#{w}"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
r.is ':d/:w/:f' do |d, w, f|
|
|
105
|
+
"dwf#{d}#{w}#{f}"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
status.must_equal 404
|
|
111
|
+
body("/1").must_equal 'd1'
|
|
112
|
+
body("/11232135").must_equal 'd11232135'
|
|
113
|
+
body("/a").must_equal 'wa'
|
|
114
|
+
body("/1az0").must_equal 'w1az0'
|
|
115
|
+
body("/f").must_equal 'ff'
|
|
116
|
+
body("/ffffffffffffffff").must_equal 'fffffffffffffffff'
|
|
117
|
+
status("/-").must_equal 404
|
|
118
|
+
body("/1/1a/f").must_equal 'dwf11af'
|
|
119
|
+
body("/12/1azy/fffff").must_equal 'dwf121azyfffff'
|
|
120
|
+
status("/1/f/a").must_equal 404
|
|
121
|
+
body("/qa/b/c/d//f/g").must_equal 'resta/b/c/d//f/g'
|
|
122
|
+
body('/q').must_equal 'rest'
|
|
123
|
+
body('/thing/q').must_equal 'thingq'
|
|
124
|
+
body('/thing2/q').must_equal 'thing2q'
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
deprecated "works with symbol_matchers plugin and deprecated matchers" do
|
|
128
|
+
app(:bare) do
|
|
129
|
+
plugin :placeholder_string_matchers
|
|
130
|
+
plugin :symbol_matchers
|
|
131
|
+
symbol_matcher(:f, /(f+)/)
|
|
132
|
+
|
|
133
|
+
route do |r|
|
|
134
|
+
r.is "foo:optd" do |o|
|
|
135
|
+
"foo#{o.inspect}"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
r.is "bar:opt" do |o|
|
|
139
|
+
"bar#{o.inspect}"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
r.is "format:format" do |f|
|
|
143
|
+
"format#{f.inspect}"
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
body("/foo").must_equal 'foonil'
|
|
149
|
+
body("/foo/123").must_equal 'foo"123"'
|
|
150
|
+
status("/foo/bar").must_equal 404
|
|
151
|
+
status("/foo/123/a").must_equal 404
|
|
152
|
+
body("/bar").must_equal 'barnil'
|
|
153
|
+
body("/bar/foo").must_equal 'bar"foo"'
|
|
154
|
+
status("/bar/foo/baz").must_equal 404
|
|
155
|
+
body("/format").must_equal 'formatnil'
|
|
156
|
+
body("/format.json").must_equal 'format"json"'
|
|
157
|
+
status("/format.").must_equal 404
|
|
158
|
+
end
|
|
159
|
+
end
|