roda 2.28.0 → 2.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +46 -0
  3. data/README.rdoc +25 -7
  4. data/doc/release_notes/2.29.0.txt +156 -0
  5. data/lib/roda.rb +25 -3
  6. data/lib/roda/plugins/_erubis_escaping.rb +2 -0
  7. data/lib/roda/plugins/_symbol_regexp_matchers.rb +22 -0
  8. data/lib/roda/plugins/assets.rb +3 -2
  9. data/lib/roda/plugins/branch_locals.rb +74 -0
  10. data/lib/roda/plugins/caching.rb +15 -7
  11. data/lib/roda/plugins/chunked.rb +10 -7
  12. data/lib/roda/plugins/content_for.rb +4 -1
  13. data/lib/roda/plugins/drop_body.rb +3 -2
  14. data/lib/roda/plugins/error_email.rb +3 -2
  15. data/lib/roda/plugins/error_mail.rb +3 -2
  16. data/lib/roda/plugins/head.rb +2 -1
  17. data/lib/roda/plugins/header_matchers.rb +3 -0
  18. data/lib/roda/plugins/heartbeat.rb +3 -2
  19. data/lib/roda/plugins/json.rb +5 -3
  20. data/lib/roda/plugins/json_parser.rb +3 -2
  21. data/lib/roda/plugins/mailer.rb +3 -3
  22. data/lib/roda/plugins/match_affix.rb +6 -0
  23. data/lib/roda/plugins/multi_route.rb +3 -1
  24. data/lib/roda/plugins/padrino_render.rb +3 -2
  25. data/lib/roda/plugins/params_capturing.rb +3 -3
  26. data/lib/roda/plugins/partials.rb +3 -3
  27. data/lib/roda/plugins/path.rb +4 -2
  28. data/lib/roda/plugins/path_rewriter.rb +2 -2
  29. data/lib/roda/plugins/per_thread_caching.rb +2 -0
  30. data/lib/roda/plugins/placeholder_string_matchers.rb +42 -0
  31. data/lib/roda/plugins/precompile_templates.rb +3 -2
  32. data/lib/roda/plugins/render.rb +86 -37
  33. data/lib/roda/plugins/render_each.rb +2 -1
  34. data/lib/roda/plugins/render_locals.rb +102 -0
  35. data/lib/roda/plugins/run_append_slash.rb +2 -1
  36. data/lib/roda/plugins/run_handler.rb +2 -1
  37. data/lib/roda/plugins/sinatra_helpers.rb +4 -4
  38. data/lib/roda/plugins/static_path_info.rb +2 -0
  39. data/lib/roda/plugins/static_routing.rb +1 -1
  40. data/lib/roda/plugins/streaming.rb +9 -4
  41. data/lib/roda/plugins/symbol_matchers.rb +23 -20
  42. data/lib/roda/plugins/view_options.rb +63 -28
  43. data/lib/roda/plugins/view_subdirs.rb +1 -0
  44. data/lib/roda/plugins/websockets.rb +2 -0
  45. data/lib/roda/version.rb +1 -1
  46. data/spec/composition_spec.rb +2 -2
  47. data/spec/matchers_spec.rb +6 -5
  48. data/spec/plugin/_erubis_escaping_spec.rb +5 -5
  49. data/spec/plugin/backtracking_array_spec.rb +0 -2
  50. data/spec/plugin/branch_locals_spec.rb +88 -0
  51. data/spec/plugin/content_for_spec.rb +8 -2
  52. data/spec/plugin/halt_spec.rb +8 -0
  53. data/spec/plugin/header_matchers_spec.rb +20 -5
  54. data/spec/plugin/multi_route_spec.rb +1 -1
  55. data/spec/plugin/named_templates_spec.rb +2 -2
  56. data/spec/plugin/params_capturing_spec.rb +1 -1
  57. data/spec/plugin/per_thread_caching_spec.rb +1 -1
  58. data/spec/plugin/placeholder_string_matchers_spec.rb +159 -0
  59. data/spec/plugin/render_locals_spec.rb +114 -0
  60. data/spec/plugin/render_spec.rb +83 -8
  61. data/spec/plugin/streaming_spec.rb +104 -4
  62. data/spec/plugin/symbol_matchers_spec.rb +1 -1
  63. data/spec/plugin/view_options_spec.rb +83 -7
  64. data/spec/plugin/websockets_spec.rb +7 -8
  65. data/spec/spec_helper.rb +22 -2
  66. metadata +11 -2
@@ -20,7 +20,7 @@ describe "_erubis_escaping plugin" do
20
20
  end
21
21
  end
22
22
 
23
- it "should escape inside <%= %> and not inside <%== %>, and handle postfix conditionals" do
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 '&lt;&gt; <>'
33
33
  end
34
34
 
35
- it "should consider classes in :escape_safe_classes as safe" do
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 '&lt;&gt; <>'
48
48
  end
49
49
 
50
- it "should covnert arguments to strings when escaping with safe classes" do
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 '&lt;&gt; <>'
60
60
  end
61
61
 
62
- it "should allow use of custom :escaper" do
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
- it "should allow for per-branch escaping via set_view options" do
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
@@ -38,7 +38,5 @@ describe "backtracking_array plugin" do
38
38
  end
39
39
 
40
40
  tests.call
41
- app.plugin(:static_path_info)
42
- tests.call
43
41
  end
44
42
  end
@@ -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
- it "should replace with multiple calls to the same key by default" do
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 append with multiple calls to the same key if :append plugin option is used" do
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
@@ -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
- it "should match if header present" do
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=>"http-accept" do |v|
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
- it "should match a host with a regexp" do
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
- it "yields host if passed a regexp and opts[:host_matcher_captures] is set" do
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
- it "r.multi_route works even without routes defined" do
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 view_subdirs plugin" do
58
+ it "works with the view_options plugin" do
59
59
  app(:bare) do
60
60
  plugin :render
61
- plugin :view_subdirs
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
- it "should add captures to r.params for string matchers" do
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
- it "should use a per thread cache instead of a shared cache" do
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