roda 3.28.0 → 3.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.
Files changed (188) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +10 -0
  3. data/README.rdoc +10 -0
  4. data/doc/release_notes/3.29.0.txt +15 -0
  5. data/lib/roda.rb +1 -0
  6. data/lib/roda/plugins/caching.rb +2 -0
  7. data/lib/roda/plugins/common_logger.rb +1 -1
  8. data/lib/roda/plugins/exception_page.rb +7 -1
  9. data/lib/roda/plugins/indifferent_params.rb +2 -0
  10. data/lib/roda/version.rb +1 -1
  11. metadata +4 -214
  12. data/Rakefile +0 -108
  13. data/doc/release_notes/1.0.0.txt +0 -329
  14. data/doc/release_notes/1.1.0.txt +0 -226
  15. data/doc/release_notes/1.2.0.txt +0 -406
  16. data/doc/release_notes/1.3.0.txt +0 -109
  17. data/doc/release_notes/2.0.0.txt +0 -75
  18. data/doc/release_notes/2.1.0.txt +0 -124
  19. data/doc/release_notes/2.10.0.txt +0 -27
  20. data/doc/release_notes/2.11.0.txt +0 -70
  21. data/doc/release_notes/2.12.0.txt +0 -40
  22. data/doc/release_notes/2.13.0.txt +0 -10
  23. data/doc/release_notes/2.14.0.txt +0 -44
  24. data/doc/release_notes/2.15.0.txt +0 -53
  25. data/doc/release_notes/2.16.0.txt +0 -48
  26. data/doc/release_notes/2.17.0.txt +0 -62
  27. data/doc/release_notes/2.18.0.txt +0 -69
  28. data/doc/release_notes/2.19.0.txt +0 -30
  29. data/doc/release_notes/2.2.0.txt +0 -97
  30. data/doc/release_notes/2.20.0.txt +0 -5
  31. data/doc/release_notes/2.21.0.txt +0 -17
  32. data/doc/release_notes/2.22.0.txt +0 -41
  33. data/doc/release_notes/2.23.0.txt +0 -29
  34. data/doc/release_notes/2.24.0.txt +0 -65
  35. data/doc/release_notes/2.25.0.txt +0 -14
  36. data/doc/release_notes/2.26.0.txt +0 -13
  37. data/doc/release_notes/2.27.0.txt +0 -56
  38. data/doc/release_notes/2.28.0.txt +0 -17
  39. data/doc/release_notes/2.29.0.txt +0 -156
  40. data/doc/release_notes/2.3.0.txt +0 -109
  41. data/doc/release_notes/2.4.0.txt +0 -55
  42. data/doc/release_notes/2.5.0.txt +0 -23
  43. data/doc/release_notes/2.5.1.txt +0 -4
  44. data/doc/release_notes/2.6.0.txt +0 -21
  45. data/doc/release_notes/2.7.0.txt +0 -75
  46. data/doc/release_notes/2.8.0.txt +0 -44
  47. data/doc/release_notes/2.9.0.txt +0 -6
  48. data/spec/all.rb +0 -1
  49. data/spec/assets/css/app.scss +0 -1
  50. data/spec/assets/css/no_access.css +0 -1
  51. data/spec/assets/css/raw.css +0 -1
  52. data/spec/assets/js/head/app.js +0 -1
  53. data/spec/composition_spec.rb +0 -31
  54. data/spec/define_roda_method_spec.rb +0 -274
  55. data/spec/env_spec.rb +0 -11
  56. data/spec/freeze_spec.rb +0 -37
  57. data/spec/integration_spec.rb +0 -209
  58. data/spec/matchers_spec.rb +0 -832
  59. data/spec/opts_spec.rb +0 -42
  60. data/spec/plugin/_after_hook_spec.rb +0 -19
  61. data/spec/plugin/all_verbs_spec.rb +0 -29
  62. data/spec/plugin/assets_preloading_spec.rb +0 -98
  63. data/spec/plugin/assets_spec.rb +0 -745
  64. data/spec/plugin/backtracking_array_spec.rb +0 -42
  65. data/spec/plugin/branch_locals_spec.rb +0 -106
  66. data/spec/plugin/caching_spec.rb +0 -337
  67. data/spec/plugin/chunked_spec.rb +0 -201
  68. data/spec/plugin/class_level_routing_spec.rb +0 -164
  69. data/spec/plugin/class_matchers_spec.rb +0 -40
  70. data/spec/plugin/common_logger_spec.rb +0 -85
  71. data/spec/plugin/content_for_spec.rb +0 -162
  72. data/spec/plugin/content_security_policy_spec.rb +0 -175
  73. data/spec/plugin/cookies_spec.rb +0 -51
  74. data/spec/plugin/csrf_spec.rb +0 -111
  75. data/spec/plugin/default_headers_spec.rb +0 -82
  76. data/spec/plugin/default_status_spec.rb +0 -95
  77. data/spec/plugin/delay_build_spec.rb +0 -23
  78. data/spec/plugin/delegate_spec.rb +0 -23
  79. data/spec/plugin/delete_empty_headers_spec.rb +0 -27
  80. data/spec/plugin/direct_call_spec.rb +0 -28
  81. data/spec/plugin/disallow_file_uploads_spec.rb +0 -25
  82. data/spec/plugin/drop_body_spec.rb +0 -24
  83. data/spec/plugin/early_hints_spec.rb +0 -19
  84. data/spec/plugin/empty_root_spec.rb +0 -14
  85. data/spec/plugin/environments_spec.rb +0 -42
  86. data/spec/plugin/error_email_spec.rb +0 -97
  87. data/spec/plugin/error_handler_spec.rb +0 -216
  88. data/spec/plugin/error_mail_spec.rb +0 -93
  89. data/spec/plugin/exception_page_spec.rb +0 -168
  90. data/spec/plugin/flash_spec.rb +0 -121
  91. data/spec/plugin/h_spec.rb +0 -11
  92. data/spec/plugin/halt_spec.rb +0 -119
  93. data/spec/plugin/hash_matcher_spec.rb +0 -27
  94. data/spec/plugin/hash_routes_spec.rb +0 -535
  95. data/spec/plugin/head_spec.rb +0 -52
  96. data/spec/plugin/header_matchers_spec.rb +0 -98
  97. data/spec/plugin/heartbeat_spec.rb +0 -74
  98. data/spec/plugin/hooks_spec.rb +0 -152
  99. data/spec/plugin/indifferent_params_spec.rb +0 -14
  100. data/spec/plugin/json_parser_spec.rb +0 -141
  101. data/spec/plugin/json_spec.rb +0 -83
  102. data/spec/plugin/mail_processor_spec.rb +0 -451
  103. data/spec/plugin/mailer_spec.rb +0 -282
  104. data/spec/plugin/match_affix_spec.rb +0 -43
  105. data/spec/plugin/match_hook_spec.rb +0 -79
  106. data/spec/plugin/middleware_spec.rb +0 -237
  107. data/spec/plugin/middleware_stack_spec.rb +0 -81
  108. data/spec/plugin/module_include_spec.rb +0 -48
  109. data/spec/plugin/multi_route_spec.rb +0 -268
  110. data/spec/plugin/multi_run_spec.rb +0 -87
  111. data/spec/plugin/multi_view_spec.rb +0 -50
  112. data/spec/plugin/multibyte_string_matcher_spec.rb +0 -44
  113. data/spec/plugin/named_templates_spec.rb +0 -96
  114. data/spec/plugin/not_allowed_spec.rb +0 -69
  115. data/spec/plugin/not_found_spec.rb +0 -128
  116. data/spec/plugin/optimized_string_matchers_spec.rb +0 -43
  117. data/spec/plugin/padrino_render_spec.rb +0 -34
  118. data/spec/plugin/param_matchers_spec.rb +0 -69
  119. data/spec/plugin/params_capturing_spec.rb +0 -33
  120. data/spec/plugin/partials_spec.rb +0 -43
  121. data/spec/plugin/pass_spec.rb +0 -29
  122. data/spec/plugin/path_matchers_spec.rb +0 -42
  123. data/spec/plugin/path_rewriter_spec.rb +0 -45
  124. data/spec/plugin/path_spec.rb +0 -222
  125. data/spec/plugin/placeholder_string_matchers_spec.rb +0 -126
  126. data/spec/plugin/precompile_templates_spec.rb +0 -61
  127. data/spec/plugin/public_spec.rb +0 -85
  128. data/spec/plugin/render_each_spec.rb +0 -82
  129. data/spec/plugin/render_locals_spec.rb +0 -114
  130. data/spec/plugin/render_spec.rb +0 -912
  131. data/spec/plugin/request_aref_spec.rb +0 -51
  132. data/spec/plugin/request_headers_spec.rb +0 -39
  133. data/spec/plugin/response_request_spec.rb +0 -43
  134. data/spec/plugin/route_block_args_spec.rb +0 -86
  135. data/spec/plugin/route_csrf_spec.rb +0 -305
  136. data/spec/plugin/run_append_slash_spec.rb +0 -77
  137. data/spec/plugin/run_handler_spec.rb +0 -53
  138. data/spec/plugin/sessions_spec.rb +0 -452
  139. data/spec/plugin/shared_vars_spec.rb +0 -45
  140. data/spec/plugin/sinatra_helpers_spec.rb +0 -537
  141. data/spec/plugin/slash_path_empty_spec.rb +0 -22
  142. data/spec/plugin/static_routing_spec.rb +0 -192
  143. data/spec/plugin/static_spec.rb +0 -30
  144. data/spec/plugin/status_303_spec.rb +0 -28
  145. data/spec/plugin/status_handler_spec.rb +0 -158
  146. data/spec/plugin/streaming_spec.rb +0 -246
  147. data/spec/plugin/strip_path_prefix_spec.rb +0 -24
  148. data/spec/plugin/symbol_matchers_spec.rb +0 -51
  149. data/spec/plugin/symbol_status_spec.rb +0 -25
  150. data/spec/plugin/symbol_views_spec.rb +0 -32
  151. data/spec/plugin/timestamp_public_spec.rb +0 -85
  152. data/spec/plugin/type_routing_spec.rb +0 -348
  153. data/spec/plugin/typecast_params_spec.rb +0 -1370
  154. data/spec/plugin/unescape_path_spec.rb +0 -22
  155. data/spec/plugin/view_options_spec.rb +0 -170
  156. data/spec/plugin_spec.rb +0 -71
  157. data/spec/redirect_spec.rb +0 -41
  158. data/spec/request_spec.rb +0 -97
  159. data/spec/response_spec.rb +0 -199
  160. data/spec/route_spec.rb +0 -39
  161. data/spec/session_middleware_spec.rb +0 -129
  162. data/spec/session_spec.rb +0 -37
  163. data/spec/spec_helper.rb +0 -137
  164. data/spec/version_spec.rb +0 -14
  165. data/spec/views/_test.erb +0 -1
  166. data/spec/views/a.erb +0 -1
  167. data/spec/views/a.rdoc +0 -2
  168. data/spec/views/about.erb +0 -1
  169. data/spec/views/about.str +0 -1
  170. data/spec/views/about/_test.css.gz +0 -0
  171. data/spec/views/about/_test.erb +0 -1
  172. data/spec/views/about/_test.erb.gz +0 -0
  173. data/spec/views/about/comp_test.erb +0 -1
  174. data/spec/views/b.erb +0 -1
  175. data/spec/views/c.erb +0 -1
  176. data/spec/views/comp_layout.erb +0 -1
  177. data/spec/views/comp_test.erb +0 -1
  178. data/spec/views/content-yield.erb +0 -1
  179. data/spec/views/each.str +0 -1
  180. data/spec/views/home.erb +0 -2
  181. data/spec/views/home.str +0 -2
  182. data/spec/views/iv.erb +0 -1
  183. data/spec/views/layout-alternative.erb +0 -2
  184. data/spec/views/layout-yield.erb +0 -3
  185. data/spec/views/layout.erb +0 -2
  186. data/spec/views/layout.str +0 -2
  187. data/spec/views/multiple-layout.erb +0 -1
  188. data/spec/views/multiple.erb +0 -1
@@ -1,11 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe "Roda#env" do
4
- it "should return the environment" do
5
- app do |r|
6
- env['PATH_INFO']
7
- end
8
-
9
- body("/foo").must_equal "/foo"
10
- end
11
- end
@@ -1,37 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe "Roda.freeze" do
4
- before do
5
- app{'a'}.freeze
6
- end
7
-
8
- it "should result in a working application" do
9
- body.must_equal 'a'
10
- end
11
-
12
- it "should not break if called more than once" do
13
- app.freeze
14
- body.must_equal 'a'
15
- end
16
-
17
- it "should make opts not be modifiable after calling finalize!" do
18
- proc{app.opts[:foo] = 'bar'}.must_raise
19
- end
20
-
21
- it "should make use and route raise errors" do
22
- proc{app.use Class.new}.must_raise
23
- proc{app.route{}}.must_raise
24
- end
25
-
26
- it "should make plugin raise errors" do
27
- proc{app.plugin Module.new}.must_raise
28
- end
29
-
30
- it "should make subclassing raise errors" do
31
- proc{Class.new(app)}.must_raise
32
- end
33
-
34
- it "should freeze app" do
35
- app.frozen?.must_equal true
36
- end
37
- end
@@ -1,209 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe "integration" do
4
- before do
5
- @c = Class.new do
6
- def initialize(app, first, second, &block)
7
- @app, @first, @second, @block = app, first, second, block
8
- end
9
-
10
- def call(env)
11
- env["m.first"] = @first
12
- env["m.second"] = @second
13
- env["m.block"] = @block.call
14
-
15
- @app.call(env)
16
- end
17
- end
18
-
19
- end
20
-
21
- it "should setup middleware using use" do
22
- c = @c
23
- app(:bare) do
24
- use c, "First", "Second" do
25
- "Block"
26
- end
27
-
28
- route do |r|
29
- r.get "hello" do
30
- "D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
31
- end
32
- end
33
- end
34
-
35
- body('/hello').must_equal 'D First Second Block'
36
- end
37
-
38
- it "should clear middleware when clear_middleware! is called" do
39
- c = @c
40
- app(:bare) do
41
- use c, "First", "Second" do
42
- "Block"
43
- end
44
-
45
- route do |r|
46
- r.get "hello" do
47
- "D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
48
- end
49
- end
50
-
51
- clear_middleware!
52
- end
53
-
54
- body('/hello').must_equal 'D '
55
- end
56
-
57
- it "should freeze middleware if opts[:freeze_middleware] is true" do
58
- c = Class.new do
59
- def initialize(app) @app = app end
60
- def call(env) @a = 1; @app.call(env) end
61
- end
62
-
63
- app do
64
- "D"
65
- end
66
-
67
- body.must_equal 'D'
68
-
69
- app.use c
70
- body.must_equal 'D'
71
-
72
- app.clear_middleware!
73
- app.opts[:freeze_middleware] = true
74
- app.use c
75
- proc{body}.must_raise RuntimeError, TypeError
76
- end
77
-
78
- it "should support adding middleware using use after route block setup" do
79
- c = @c
80
- app(:bare) do
81
- route do |r|
82
- r.get "hello" do
83
- "D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
84
- end
85
- end
86
-
87
- use c, "First", "Second" do
88
- "Block"
89
- end
90
- end
91
-
92
- body('/hello').must_equal 'D First Second Block'
93
- end
94
-
95
- it "should inherit middleware in subclass" do
96
- c = @c
97
- @app = Class.new(app(:bare){use(c, '1', '2'){"3"}})
98
- @app.route do |r|
99
- r.get "hello" do
100
- "D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
101
- end
102
- end
103
-
104
- body('/hello').must_equal 'D 1 2 3'
105
- end
106
-
107
- it "should not inherit middleware in subclass if inhert_middleware = false" do
108
- c = @c
109
- app(:bare){use(c, '1', '2'){"3"}}
110
- @app.inherit_middleware = false
111
- @app = Class.new(@app)
112
- @app.route do |r|
113
- r.get "hello" do
114
- "D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
115
- end
116
- end
117
-
118
- body('/hello').must_equal 'D '
119
- end
120
-
121
- it "should inherit route in subclass" do
122
- c = @c
123
- app(:bare) do
124
- use(c, '1', '2'){"3"}
125
- route do |r|
126
- r.get "hello" do
127
- "D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
128
- end
129
- end
130
- end
131
- @app = Class.new(app)
132
-
133
- body('/hello').must_equal 'D 1 2 3'
134
- end
135
-
136
- it "should use instance of subclass when inheriting routes" do
137
- c = @c
138
- obj = nil
139
- app(:bare) do
140
- use(c, '1', '2'){"3"}
141
- route do |r|
142
- r.get "hello" do
143
- obj = self
144
- "D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
145
- end
146
- end
147
- end
148
- @app = Class.new(app)
149
-
150
- body('/hello').must_equal 'D 1 2 3'
151
- obj.must_be_kind_of(@app)
152
- end
153
-
154
- it "should handle middleware added to subclass using superclass route" do
155
- c = @c
156
- app(:bare) do
157
- route do |r|
158
- r.get "hello" do
159
- "D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
160
- end
161
- end
162
- end
163
- @app = Class.new(app)
164
- @app.use(c, '1', '2'){"3"}
165
-
166
- body('/hello').must_equal 'D 1 2 3'
167
- end
168
-
169
- it "should not have future middleware additions to superclass affect subclass" do
170
- c = @c
171
- a = app
172
- @app = Class.new(a)
173
- @app.route do |r|
174
- r.get "hello" do
175
- "D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
176
- end
177
- end
178
- a.use(c, '1', '2'){"3"}
179
-
180
- body('/hello').must_equal 'D '
181
- end
182
-
183
- it "should not have future middleware additions to subclass affect superclass" do
184
- c = @c
185
- a = app do |r|
186
- r.get "hello" do
187
- "D #{r.env['m.first']} #{r.env['m.second']} #{r.env['m.block']}"
188
- end
189
- end
190
- @app = Class.new(a)
191
- @app.use(c, '1', '2'){"3"}
192
- @app = a
193
-
194
- body('/hello').must_equal 'D '
195
- end
196
-
197
- it "should have app return the rack application to call" do
198
- app(:bare){}.app.must_be_kind_of(Proc)
199
- app.route{|r|}
200
- app.app.must_be_kind_of(Proc)
201
- c = Class.new{def initialize(app) @app = app end; def call(env) @app.call(env) end}
202
- app.use c
203
- app.app.must_be_kind_of(c)
204
- end
205
-
206
- it "should have route_block return the route block" do
207
- app{|r| 1}.route_block.call(nil).must_equal 1
208
- end
209
- end
@@ -1,832 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe "capturing" do
4
- it "doesn't yield the verb for verb matcher" do
5
- app do |r|
6
- r.get do |*args|
7
- args.size.to_s
8
- end
9
- end
10
-
11
- body.must_equal '0'
12
- end
13
-
14
- it "doesn't yield the path for string matcher" do
15
- app do |r|
16
- r.get "home" do |*args|
17
- args.size.to_s
18
- end
19
- end
20
-
21
- body('/home').must_equal '0'
22
- end
23
-
24
- it "yields the segment for symbol matcher" do
25
- app do |r|
26
- r.get "user", :id do |id|
27
- id
28
- end
29
- end
30
-
31
- body("/user/johndoe").must_equal 'johndoe'
32
- end
33
-
34
- it "yields an integer segment as a string when using symbol matcher" do
35
- app do |r|
36
- r.get "user", :id do |id|
37
- id
38
- end
39
- end
40
-
41
- body("/user/101").must_equal '101'
42
- end
43
-
44
- it "yields a segment per nested block for symbol matcher" do
45
- app do |r|
46
- r.on :one do |one|
47
- r.on :two do |two|
48
- r.on :three do |three|
49
- one + two + three
50
- end
51
- end
52
- end
53
- end
54
-
55
- body("/one/two/three").must_equal "onetwothree"
56
- end
57
-
58
- it "yields a segment per argument for symbol matcher" do
59
- app do |r|
60
- r.on :one, :two, :three do |one, two, three|
61
- one + two + three
62
- end
63
- end
64
-
65
- body("/one/two/three").must_equal "onetwothree"
66
- end
67
-
68
- it "yields regex captures as separate arguments" do
69
- app do |r|
70
- r.get %r{posts/(\d+)-(.*)} do |id, slug|
71
- id + slug
72
- end
73
- end
74
-
75
- body("/posts/123-postal-service").must_equal "123postal-service"
76
- end
77
-
78
- it "yields an integer segment as an integer when using Integer matcher " do
79
- app do |r|
80
- r.get "user", Integer do |id|
81
- "#{id}-#{id.is_a?(Integer)}"
82
- end
83
- "b"
84
- end
85
-
86
- body("/user/101").must_equal '101-true'
87
- body("/user/a").must_equal 'b'
88
- end
89
-
90
- it "yields the segment for String class matcher" do
91
- app do |r|
92
- r.get "user", String do |id|
93
- id
94
- end
95
- end
96
-
97
- body("/user/johndoe").must_equal 'johndoe'
98
- end
99
-
100
- it "raises error for unsupported class matcher" do
101
- app do |r|
102
- r.get Hash do |id|
103
- id
104
- end
105
- end
106
-
107
- proc{status}.must_raise Roda::RodaError
108
- end
109
- end
110
-
111
- describe "r.is" do
112
- it "ensures the patch is matched fully" do
113
- app do |r|
114
- r.is "" do
115
- "+1"
116
- end
117
- end
118
-
119
- body.must_equal '+1'
120
- status('//').must_equal 404
121
- end
122
-
123
- it "handles no arguments" do
124
- app do |r|
125
- r.on "" do
126
- r.is do
127
- "+1"
128
- end
129
- end
130
- end
131
-
132
- body.must_equal '+1'
133
- status('//').must_equal 404
134
- end
135
-
136
- it "matches strings" do
137
- app do |r|
138
- r.is "123" do
139
- "+1"
140
- end
141
- end
142
-
143
- body("/123").must_equal '+1'
144
- status("/123/").must_equal 404
145
- end
146
-
147
- it "matches regexps" do
148
- app do |r|
149
- r.is(/(\w+)/) do |id|
150
- id
151
- end
152
- end
153
-
154
- body("/123").must_equal '123'
155
- status("/123/").must_equal 404
156
- end
157
-
158
- it "matches regexps" do
159
- app do |r|
160
- r.on(/foo/) do |id|
161
- 'a'
162
- end
163
- end
164
-
165
- body("/foo").must_equal 'a'
166
- body("/foo/").must_equal 'a'
167
- status("/food").must_equal 404
168
- end
169
-
170
- it "matches segments" do
171
- app do |r|
172
- r.is :id do |id|
173
- id
174
- end
175
- end
176
-
177
- body("/123").must_equal '123'
178
- status("/123/").must_equal 404
179
- end
180
- end
181
-
182
- describe "matchers" do
183
- it "should not handle string with embedded param if :verbatim_string_matcher option is set" do
184
- app do |r|
185
- r.on "posts/:id" do
186
- '1'
187
- end
188
-
189
- r.on "responses-:id" do
190
- '2'
191
- end
192
- end
193
-
194
- status('/post/123').must_equal 404
195
- status('/posts/123').must_equal 404
196
- body('/posts/:id').must_equal '1'
197
- status('/responses-123').must_equal 404
198
- body('/responses-:id').must_equal '2'
199
- end
200
-
201
- it "should handle regexes and nesting" do
202
- app do |r|
203
- r.on(/u\/(\w+)/) do |uid|
204
- r.on(/posts\/(\d+)/) do |id|
205
- uid + id
206
- end
207
- end
208
- end
209
-
210
- body("/u/jdoe/posts/123").must_equal 'jdoe123'
211
- status("/u/jdoe/pots/123").must_equal 404
212
- end
213
-
214
- it "should handle regex nesting colon param style" do
215
- app do |r|
216
- r.on(/u:(\w+)/) do |uid|
217
- r.on(/posts:(\d+)/) do |id|
218
- uid + id
219
- end
220
- end
221
- end
222
-
223
- body("/u:jdoe/posts:123").must_equal 'jdoe123'
224
- status("/u:jdoe/poss:123").must_equal 404
225
- end
226
-
227
- it "symbol matching" do
228
- app do |r|
229
- r.on "user", :id do |uid|
230
- r.on "posts", :pid do |id|
231
- uid + id
232
- end
233
- end
234
- end
235
-
236
- body("/user/jdoe/posts/123").must_equal 'jdoe123'
237
- status("/user/jdoe/pots/123").must_equal 404
238
- end
239
-
240
- it "paths and numbers" do
241
- app do |r|
242
- r.on "about" do
243
- r.on :one, :two do |one, two|
244
- one + two
245
- end
246
- end
247
- end
248
-
249
- body("/about/1/2").must_equal '12'
250
- status("/about/1").must_equal 404
251
- end
252
-
253
- it "paths and decimals" do
254
- app do |r|
255
- r.on "about" do
256
- r.on(/(\d+)/) do |one|
257
- one
258
- end
259
- end
260
- end
261
-
262
- body("/about/1").must_equal '1'
263
- status("/about/1.2").must_equal 404
264
- end
265
-
266
- it "should allow arrays to match any value" do
267
- app do |r|
268
- r.on [/(\d+)/, /\d+(bar)?/] do |id|
269
- id
270
- end
271
- end
272
-
273
- body('/123').must_equal '123'
274
- body('/123bar').must_equal 'bar'
275
- status('/123bard').must_equal 404
276
- end
277
-
278
- it "should allow arrays to match optional segments with splats" do
279
- app do |r|
280
- r.on :foo, [:bar, true] do |*m|
281
- m.inspect
282
- end
283
- end
284
-
285
- body('/123').must_equal '["123"]'
286
- body('/123/456').must_equal '["123", "456"]'
287
- end
288
-
289
- it "should allow arrays to match optional segments with separate arguments" do
290
- app do |r|
291
- r.on :foo, [:bar, true] do |f, b|
292
- [f, b].inspect
293
- end
294
- end
295
-
296
- body('/123').must_equal '["123", nil]'
297
- body('/123/456').must_equal '["123", "456"]'
298
- end
299
-
300
- it "should allow regexp to match optional segments with separate arguments" do
301
- app do |r|
302
- r.on(/(\d+)(?:\/(\d+))?/) do |f, b|
303
- [f, b].inspect
304
- end
305
- end
306
-
307
- body('/123').must_equal '["123", nil]'
308
- body('/123/456').must_equal '["123", "456"]'
309
- end
310
-
311
- it "should have array capture match string if match" do
312
- app do |r|
313
- r.on %w'p q' do |id|
314
- id
315
- end
316
- end
317
-
318
- body('/p').must_equal 'p'
319
- body('/q').must_equal 'q'
320
- status('/r').must_equal 404
321
- end
322
- end
323
-
324
- describe "r.on" do
325
- it "executes on no arguments" do
326
- app do |r|
327
- r.on do
328
- "+1"
329
- end
330
- end
331
-
332
- body.must_equal '+1'
333
- end
334
-
335
- it "executes on true" do
336
- app do |r|
337
- r.on true do
338
- "+1"
339
- end
340
- end
341
-
342
- body.must_equal '+1'
343
- end
344
-
345
- it "does not execute on false" do
346
- app do |r|
347
- r.on false do
348
- "+1"
349
- end
350
- end
351
-
352
- status.must_equal 404
353
- end
354
-
355
- it "does not execute on nil" do
356
- app do |r|
357
- r.on nil do
358
- "+1"
359
- end
360
- end
361
-
362
- status.must_equal 404
363
- end
364
-
365
- it "raises on arbitrary object" do
366
- app(:bare) do
367
- route do |r|
368
- r.on Object.new do
369
- "+1"
370
- end
371
- end
372
- end
373
-
374
- proc{body}.must_raise Roda::RodaError
375
- end
376
-
377
- it "executes on non-false" do
378
- app do |r|
379
- r.on "123" do
380
- "+1"
381
- end
382
- end
383
-
384
- body("/123").must_equal '+1'
385
- end
386
-
387
- it "does not modify SCRIPT_NAME/PATH_INFO during routing" do
388
- app(:pass) do |r|
389
- r.on "foo" do
390
- r.is "bar" do
391
- "bar|#{env['SCRIPT_NAME']}|#{env['PATH_INFO']}"
392
- end
393
- r.is "baz" do
394
- r.pass
395
- end
396
- "foo|#{env['SCRIPT_NAME']}|#{env['PATH_INFO']}"
397
- end
398
- "#{env['SCRIPT_NAME']}|#{env['PATH_INFO']}"
399
- end
400
-
401
- body.must_equal '|/'
402
- body('SCRIPT_NAME'=>'/a').must_equal '/a|/'
403
- body('/foo').must_equal 'foo||/foo'
404
- body('/foo', 'SCRIPT_NAME'=>'/a').must_equal 'foo|/a|/foo'
405
- body('/foo/bar').must_equal 'bar||/foo/bar'
406
- body('/foo/bar', 'SCRIPT_NAME'=>'/a').must_equal 'bar|/a|/foo/bar'
407
- body('/foo/baz').must_equal 'foo||/foo/baz'
408
- body('/foo/baz', 'SCRIPT_NAME'=>'/a').must_equal 'foo|/a|/foo/baz'
409
- end
410
-
411
- it "should have path/matched_path/remaining_path work correctly" do
412
- app do |r|
413
- r.on "foo" do
414
- "#{r.path}:#{r.matched_path}:#{r.remaining_path}"
415
- end
416
- end
417
-
418
- body("/foo/bar").must_equal "/foo/bar:/foo:/bar"
419
- end
420
-
421
- it "ensures remaining_path is reverted if modified in failing matcher" do
422
- app do |r|
423
- r.on lambda { @remaining_path = "/blah"; false } do
424
- "Unreachable"
425
- end
426
-
427
- r.on do
428
- r.matched_path + ':' + r.remaining_path
429
- end
430
- end
431
-
432
- body("/hello").must_equal ':/hello'
433
- end
434
-
435
- it "modifies matched_path/remaining_path during routing" do
436
- app do |r|
437
- r.on 'login', 'foo' do
438
- "Unreachable"
439
- end
440
-
441
- r.on 'hello' do
442
- r.matched_path + ':' + r.remaining_path
443
- end
444
- end
445
-
446
- body("/hello/you").must_equal '/hello:/you'
447
- end
448
-
449
- it "doesn't modify SCRIPT_NAME/PATH_INFO during routing" do
450
- app do |r|
451
- r.on 'login', 'foo' do
452
- "Unreachable"
453
- end
454
-
455
- r.on 'hello' do
456
- r.env["SCRIPT_NAME"] + ':' + r.env["PATH_INFO"]
457
- end
458
- end
459
-
460
- body("/hello/you").must_equal ':/hello/you'
461
- end
462
-
463
- it "doesn't mutate SCRIPT_NAME or PATH_INFO after request is returned" do
464
- app do |r|
465
- r.on 'login', 'foo' do
466
- "Unreachable"
467
- end
468
-
469
- r.on do
470
- r.env["SCRIPT_NAME"] + ':' + r.env["PATH_INFO"]
471
- end
472
- end
473
-
474
- pi, sn = '/login', ''
475
- env = {"REQUEST_METHOD" => "GET", "PATH_INFO" => pi, "SCRIPT_NAME" => sn}
476
- app.call(env)[2].join.must_equal ":/login"
477
- env["PATH_INFO"].must_equal pi
478
- env["SCRIPT_NAME"].must_equal sn
479
- end
480
-
481
- it "skips consecutive matches" do
482
- app do |r|
483
- r.on do
484
- "foo"
485
- end
486
-
487
- r.on do
488
- "bar"
489
- end
490
- end
491
-
492
- body.must_equal "foo"
493
- end
494
-
495
- it "finds first match available" do
496
- app do |r|
497
- r.on false do
498
- "foo"
499
- end
500
-
501
- r.on do
502
- "bar"
503
- end
504
- end
505
-
506
- body.must_equal "bar"
507
- end
508
-
509
- it "reverts a half-met matcher" do
510
- app do |r|
511
- r.on "post", false do
512
- "Should be unmet"
513
- end
514
-
515
- r.on do
516
- r.env["SCRIPT_NAME"] + ':' + r.env["PATH_INFO"]
517
- end
518
- end
519
-
520
- body("/hello").must_equal ':/hello'
521
- end
522
-
523
- it "doesn't write to body if body already written to" do
524
- app do |r|
525
- r.on do
526
- response.write "a"
527
- "b"
528
- end
529
- end
530
-
531
- body.must_equal 'a'
532
- end
533
- end
534
-
535
- describe "path matchers" do
536
- it "one level path" do
537
- app do |r|
538
- r.on "about" do
539
- "About"
540
- end
541
- end
542
-
543
- body('/about').must_equal "About"
544
- status("/abot").must_equal 404
545
- end
546
-
547
- it "two level nested paths" do
548
- app do |r|
549
- r.on "about" do
550
- r.on "1" do
551
- "+1"
552
- end
553
-
554
- r.on "2" do
555
- "+2"
556
- end
557
- end
558
- end
559
-
560
- body('/about/1').must_equal "+1"
561
- body('/about/2').must_equal "+2"
562
- status('/about/3').must_equal 404
563
- end
564
-
565
- it "two level inlined paths" do
566
- app do |r|
567
- r.on "a/b" do
568
- "ab"
569
- end
570
- end
571
-
572
- body('/a/b').must_equal "ab"
573
- status('/a/d').must_equal 404
574
- end
575
-
576
- it "a path with some regex captures" do
577
- app do |r|
578
- r.on(/user(\d+)/) do |uid|
579
- uid
580
- end
581
- end
582
-
583
- body('/user123').must_equal "123"
584
- status('/useradf').must_equal 404
585
- end
586
-
587
- it "matching the root with a string" do
588
- app do |r|
589
- r.is "" do
590
- "Home"
591
- end
592
- end
593
-
594
- body.must_equal 'Home'
595
- status("//").must_equal 404
596
- status("/foo").must_equal 404
597
- end
598
-
599
- it "matching the root with the root method" do
600
- app do |r|
601
- r.root do
602
- "Home"
603
- end
604
- end
605
-
606
- body.must_equal 'Home'
607
- status('REQUEST_METHOD'=>'POST').must_equal 404
608
- status("//").must_equal 404
609
- status("/foo").must_equal 404
610
- end
611
- end
612
-
613
- describe "root/empty segment matching" do
614
- it "matching an empty segment" do
615
- app do |r|
616
- r.on "" do
617
- r.path
618
- end
619
- end
620
-
621
- body.must_equal '/'
622
- status("/foo").must_equal 404
623
- end
624
-
625
- it "nested empty segments" do
626
- app do |r|
627
- r.on "" do
628
- r.on "" do
629
- r.on "1" do
630
- r.path
631
- end
632
- end
633
- end
634
- end
635
-
636
- body("///1").must_equal '///1'
637
- status("/1").must_equal 404
638
- status("//1").must_equal 404
639
- end
640
-
641
- it "/events/? scenario" do
642
- a = app do |r|
643
- r.on "" do
644
- "Hooray"
645
- end
646
-
647
- r.is do
648
- "Foo"
649
- end
650
- end
651
-
652
- app(:new) do |r|
653
- r.on "events" do
654
- r.run a
655
- end
656
- end
657
-
658
- body("/events").must_equal 'Foo'
659
- body("/events/").must_equal 'Hooray'
660
- status("/events/foo").must_equal 404
661
- end
662
- end
663
-
664
- describe "segment handling" do
665
- before do
666
- app do |r|
667
- r.on "post" do
668
- r.on :id do |id|
669
- id
670
- end
671
- end
672
- end
673
- end
674
-
675
- it "matches numeric ids" do
676
- body('/post/1').must_equal '1'
677
- end
678
-
679
- it "matches decimal numbers" do
680
- body('/post/1.1').must_equal '1.1'
681
- end
682
-
683
- it "matches slugs" do
684
- body('/post/my-blog-post-about-cuba').must_equal 'my-blog-post-about-cuba'
685
- end
686
-
687
- it "matches only the first segment available" do
688
- body('/post/one/two/three').must_equal 'one'
689
- end
690
- end
691
-
692
- describe "request verb methods" do
693
- it "executes if verb matches" do
694
- app do |r|
695
- r.get do
696
- "g"
697
- end
698
- r.post do
699
- "p"
700
- end
701
- end
702
-
703
- body.must_equal 'g'
704
- body('REQUEST_METHOD'=>'POST').must_equal 'p'
705
- end
706
-
707
- it "requires exact match if given arguments" do
708
- app do |r|
709
- r.get "" do
710
- "g"
711
- end
712
- r.post "" do
713
- "p"
714
- end
715
- end
716
-
717
- body.must_equal 'g'
718
- body('REQUEST_METHOD'=>'POST').must_equal 'p'
719
- status("/a").must_equal 404
720
- status("/a", 'REQUEST_METHOD'=>'POST').must_equal 404
721
- end
722
-
723
- it "does not require exact match if given arguments" do
724
- app do |r|
725
- r.get do
726
- r.is "" do
727
- "g"
728
- end
729
-
730
- "get"
731
- end
732
- r.post do
733
- r.is "" do
734
- "p"
735
- end
736
-
737
- "post"
738
- end
739
- end
740
-
741
- body.must_equal 'g'
742
- body('REQUEST_METHOD'=>'POST').must_equal 'p'
743
- body("/a").must_equal 'get'
744
- body("/a", 'REQUEST_METHOD'=>'POST').must_equal 'post'
745
- end
746
- end
747
-
748
- describe "all matcher" do
749
- it "should match only all all arguments match" do
750
- app do |r|
751
- r.is :all=>['foo', :y] do |file|
752
- file
753
- end
754
- end
755
-
756
- body("/foo/bar").must_equal 'bar'
757
- status.must_equal 404
758
- status("/foo").must_equal 404
759
- status("/foo/").must_equal 404
760
- status("/foo/bar/baz").must_equal 404
761
- end
762
- end
763
-
764
- describe "method matcher" do
765
- it "should match given request types" do
766
- app do |r|
767
- r.is "", :method=>:get do
768
- "foo"
769
- end
770
- r.is "", :method=>[:patch, :post] do
771
- "bar"
772
- end
773
- end
774
-
775
- body("REQUEST_METHOD"=>"GET").must_equal 'foo'
776
- body("REQUEST_METHOD"=>"PATCH").must_equal 'bar'
777
- body("REQUEST_METHOD"=>"POST").must_equal 'bar'
778
- status("REQUEST_METHOD"=>"DELETE").must_equal 404
779
- end
780
- end
781
-
782
- describe "route block that returns string" do
783
- it "should be treated as if an on block returned string" do
784
- app do |r|
785
- "+1"
786
- end
787
-
788
- body.must_equal '+1'
789
- end
790
- end
791
-
792
- describe "app with :unsupported_block_result => :raise option" do
793
- def app_value(v)
794
- app(:bare) do
795
- opts[:unsupported_block_result] = :raise
796
- route do |r|
797
- r.is 'a' do v end
798
- v
799
- end
800
- end
801
- end
802
-
803
- it "should handle String as body" do
804
- app_value '1'
805
- status.must_equal 200
806
- body.must_equal '1'
807
- status('/a').must_equal 200
808
- body('/a').must_equal '1'
809
- end
810
-
811
- it "should handle nil and false as not found" do
812
- app_value nil
813
- status.must_equal 404
814
- body.must_equal ''
815
- status('/a').must_equal 404
816
- body('/a').must_equal ''
817
- end
818
-
819
- it "should handle false as not found" do
820
- app_value false
821
- status.must_equal 404
822
- body.must_equal ''
823
- status('/a').must_equal 404
824
- body('/a').must_equal ''
825
- end
826
-
827
- it "should raise RodaError for other types" do
828
- app_value Object.new
829
- proc{body}.must_raise Roda::RodaError
830
- proc{body('/a')}.must_raise Roda::RodaError
831
- end
832
- end