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,45 +0,0 @@
1
- require_relative "../spec_helper"
2
-
3
- describe "shared_vars plugin" do
4
- it "adds shared method for sharing variables across multiple apps" do
5
- app(:shared_vars) {|r| shared[:c]}
6
- old_app = app
7
- app(:shared_vars) do |r|
8
- shared[:c] = 'c'
9
- r.run old_app
10
- end
11
-
12
- body.must_equal 'c'
13
- end
14
-
15
- it "adds shared with hash merges the hash into the shared vars" do
16
- app(:shared_vars) do |r|
17
- shared(:c=>'c')
18
- shared[:c]
19
- end
20
-
21
- body.must_equal 'c'
22
- end
23
-
24
- it "calling shared with hash and a block sets shared variables only for that block" do
25
- app(:shared_vars) do |r|
26
- c = nil
27
- d = nil
28
- shared[:c] = 'b'
29
- shared(:c=>'c', :d=>'d') do
30
- c = shared[:c]
31
- d = shared[:d]
32
- end
33
- "#{shared[:c]}:#{shared[:d]}:#{c}:#{d}"
34
- end
35
-
36
- body.must_equal 'b::c:d'
37
- end
38
-
39
- it "calling shared with no arguments and a block raises an error" do
40
- app(:shared_vars) do |r|
41
- shared{}
42
- end
43
- proc{body}.must_raise(Roda::RodaError)
44
- end
45
- end
@@ -1,537 +0,0 @@
1
- require_relative "../spec_helper"
2
-
3
- require 'uri'
4
-
5
- describe "sinatra_helpers plugin" do
6
- def sin_app(&block)
7
- app(:sinatra_helpers, &block)
8
- end
9
-
10
- def status_app(code, &block)
11
- block ||= proc{}
12
- sin_app do |r|
13
- status code
14
- instance_eval(&block).inspect
15
- end
16
- end
17
-
18
- it 'status returns the response status code if not given an argument' do
19
- status_app(207){status}
20
- body.must_equal "207"
21
- end
22
-
23
- it 'status sets the response status code if given an argument' do
24
- status_app 207
25
- status.must_equal 207
26
- end
27
-
28
- it 'not_found? is true only if status == 404' do
29
- status_app(404){not_found?}
30
- body.must_equal 'true'
31
- status_app(405){not_found?}
32
- body.must_equal 'false'
33
- status_app(403){not_found?}
34
- body.must_equal 'false'
35
- end
36
-
37
- it 'informational? is true only for 1xx status' do
38
- status_app(100 + rand(100)){informational?}
39
- body.must_equal 'true'
40
- status_app(200 + rand(400)){informational?}
41
- body.must_equal 'false'
42
- end
43
-
44
- it 'success? is true only for 2xx status' do
45
- status_app(200 + rand(100)){success?}
46
- body.must_equal 'true'
47
- status_app(100 + rand(100)){success?}
48
- body.must_equal 'false'
49
- status_app(300 + rand(300)){success?}
50
- body.must_equal 'false'
51
- end
52
-
53
- it 'redirect? is true only for 3xx status' do
54
- status_app(300 + rand(100)){redirect?}
55
- body.must_equal 'true'
56
- status_app(200 + rand(100)){redirect?}
57
- body.must_equal 'false'
58
- status_app(400 + rand(200)){redirect?}
59
- body.must_equal 'false'
60
- end
61
-
62
- it 'client_error? is true only for 4xx status' do
63
- status_app(400 + rand(100)){client_error?}
64
- body.must_equal 'true'
65
- status_app(200 + rand(200)){client_error?}
66
- body.must_equal 'false'
67
- status_app(500 + rand(100)){client_error?}
68
- body.must_equal 'false'
69
- end
70
-
71
- it 'server_error? is true only for 5xx status' do
72
- status_app(500 + rand(100)){server_error?}
73
- body.must_equal 'true'
74
- status_app(200 + rand(300)){server_error?}
75
- body.must_equal 'false'
76
- end
77
-
78
- describe 'body' do
79
- it 'takes a block for deferred body generation' do
80
- sin_app{body{'Hello World'}; nil}
81
- body.must_equal 'Hello World'
82
- header('Content-Length').must_equal '11'
83
- end
84
-
85
- it 'supports #join' do
86
- sin_app{body{'Hello World'}; nil}
87
- req[2].join.must_equal 'Hello World'
88
- end
89
-
90
- it 'takes a String, Array, or other object responding to #each' do
91
- sin_app{body 'Hello World'; nil}
92
- body.must_equal 'Hello World'
93
- header('Content-Length').must_equal '11'
94
-
95
- sin_app{body ['Hello ', 'World']; nil}
96
- body.must_equal 'Hello World'
97
- header('Content-Length').must_equal '11'
98
-
99
- o = Object.new
100
- def o.each; yield 'Hello World' end
101
- sin_app{body o; nil}
102
- body.must_equal 'Hello World'
103
- header('Content-Length').must_equal '11'
104
- end
105
- end
106
-
107
- describe 'redirect' do
108
- it 'uses a 302 when only a path is given' do
109
- sin_app do
110
- redirect '/foo'
111
- fail 'redirect should halt'
112
- end
113
-
114
- status.must_equal 302
115
- body.must_equal ''
116
- header('Location').must_equal '/foo'
117
- end
118
-
119
- it 'adds script_name if given a path' do
120
- sin_app{redirect "/foo"}
121
- header('Location', '/bar', 'SCRIPT_NAME'=>'/foo').must_equal '/foo'
122
- end
123
-
124
- it 'does not adds script_name if not given a path' do
125
- sin_app{redirect}
126
- header('Location', '/bar', 'SCRIPT_NAME'=>'/foo', 'REQUEST_METHOD'=>'POST').must_equal '/foo/bar'
127
- end
128
-
129
- it 'respects :absolute_redirects option' do
130
- sin_app{redirect}
131
- app.opts[:absolute_redirects] = true
132
- header('Location', '/bar', 'HTTP_HOST'=>'example.org', 'SCRIPT_NAME'=>'/foo', 'REQUEST_METHOD'=>'POST').must_equal 'http://example.org/foo/bar'
133
- end
134
-
135
- it 'respects :prefixed_redirects option' do
136
- sin_app{redirect "/bar"}
137
- app.opts[:prefixed_redirects] = true
138
- header('Location', 'SCRIPT_NAME'=>'/foo').must_equal '/foo/bar'
139
- end
140
-
141
- it 'ignores :prefix_redirects option if not given a path' do
142
- sin_app{redirect}
143
- app.opts[:prefix_redirects] = true
144
- header('Location', "/bar", 'SCRIPT_NAME'=>'/foo', 'REQUEST_METHOD'=>'POST').must_equal '/foo/bar'
145
- end
146
-
147
- it 'uses the code given when specified' do
148
- sin_app{redirect '/foo', 301}
149
- status.must_equal 301
150
- end
151
-
152
- it 'redirects back to request.referer when passed back' do
153
- sin_app{redirect back}
154
- header('Location', 'HTTP_REFERER' => '/foo').must_equal '/foo'
155
- end
156
-
157
- it 'uses 303 for post requests if request is HTTP 1.1, 302 for 1.0' do
158
- sin_app{redirect '/foo'}
159
- status('HTTP_VERSION' => 'HTTP/1.1', 'REQUEST_METHOD'=>'POST').must_equal 303
160
- status('HTTP_VERSION' => 'HTTP/1.0', 'REQUEST_METHOD'=>'POST').must_equal 302
161
- end
162
- end
163
-
164
- describe 'error' do
165
- it 'sets a status code and halts' do
166
- sin_app do
167
- error
168
- fail 'error should halt'
169
- end
170
-
171
- status.must_equal 500
172
- body.must_equal ''
173
- end
174
-
175
- it 'accepts status code' do
176
- sin_app{error 501}
177
- status.must_equal 501
178
- body.must_equal ''
179
- end
180
-
181
- it 'accepts body' do
182
- sin_app{error '501'}
183
- status.must_equal 500
184
- body.must_equal '501'
185
- end
186
-
187
- it 'accepts status code and body' do
188
- sin_app{error 502, '501'}
189
- status.must_equal 502
190
- body.must_equal '501'
191
- end
192
- end
193
-
194
- describe 'not_found' do
195
- it 'halts with a 404 status' do
196
- sin_app do
197
- not_found
198
- fail 'not_found should halt'
199
- end
200
-
201
- status.must_equal 404
202
- body.must_equal ''
203
- end
204
-
205
- it 'accepts optional body' do
206
- sin_app{not_found 'nf'}
207
- status.must_equal 404
208
- body.must_equal 'nf'
209
- end
210
- end
211
-
212
- describe 'headers' do
213
- it 'sets headers on the response object when given a Hash' do
214
- sin_app do
215
- headers 'X-Foo' => 'bar'
216
- 'kthx'
217
- end
218
-
219
- header('X-Foo').must_equal 'bar'
220
- body.must_equal 'kthx'
221
- end
222
-
223
- it 'returns the response headers hash when no hash provided' do
224
- sin_app{headers['X-Foo'] = 'bar'}
225
- header('X-Foo').must_equal 'bar'
226
- end
227
- end
228
-
229
- describe 'mime_type' do
230
- before do
231
- sin_app{|r| mime_type((r.path unless r.path.empty?)).to_s}
232
- end
233
-
234
- it "looks up mime types in Rack's MIME registry" do
235
- Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
236
- body('foo').must_equal 'application/foo'
237
- body('.foo').must_equal 'application/foo'
238
- end
239
-
240
- it 'returns nil when given nil' do
241
- body('PATH_INFO'=>'').must_equal ''
242
- end
243
-
244
- it 'returns nil when media type not registered' do
245
- body('bizzle').must_equal ''
246
- end
247
-
248
- it 'returns the argument when given a media type string' do
249
- body('text/plain').must_equal 'text/plain'
250
- end
251
-
252
- it 'supports mime types registered at the class level' do
253
- app.mime_type :foo, 'application/foo2'
254
- body('foo').must_equal 'application/foo2'
255
- end
256
- end
257
-
258
- describe 'content_type' do
259
- it 'sets the Content-Type header' do
260
- sin_app do
261
- content_type 'text/plain'
262
- 'Hello World'
263
- end
264
-
265
- header('Content-Type').must_equal 'text/plain'
266
- body.must_equal 'Hello World'
267
- end
268
-
269
- it 'takes media type parameters (like charset=)' do
270
- sin_app{content_type 'text/html', :charset => 'latin1'}
271
- header('Content-Type').must_equal 'text/html;charset=latin1'
272
- end
273
-
274
- it "looks up symbols in Rack's mime types dictionary" do
275
- sin_app{content_type :foo}
276
- Rack::Mime::MIME_TYPES['.foo'] = 'application/foo'
277
- header('Content-Type').must_equal 'application/foo'
278
- end
279
-
280
- it 'fails when no mime type is registered for the argument provided' do
281
- sin_app{content_type :bizzle}
282
- proc{body}.must_raise(Roda::RodaError)
283
- end
284
-
285
- it 'handles already present params' do
286
- sin_app{content_type 'foo/bar;level=1', :charset => 'utf-8'}
287
- header('Content-Type').must_equal 'foo/bar;level=1, charset=utf-8'
288
- end
289
-
290
- it 'does not add charset if present' do
291
- sin_app{content_type 'text/plain;charset=utf-16', :charset => 'utf-8'}
292
- header('Content-Type').must_equal 'text/plain;charset=utf-16'
293
- end
294
-
295
- it 'properly encodes parameters with delimiter characters' do
296
- sin_app{|r| content_type 'image/png', :comment => r.path }
297
- header('Content-Type', 'Hello, world!').must_equal 'image/png;comment="Hello, world!"'
298
- header('Content-Type', 'semi;colon').must_equal 'image/png;comment="semi;colon"'
299
- header('Content-Type', '"Whatever."').must_equal 'image/png;comment="\"Whatever.\""'
300
- end
301
- end
302
-
303
- describe 'attachment' do
304
- before do
305
- sin_app{|r| attachment r.path; 'b'}
306
- end
307
-
308
- it 'sets the Content-Disposition header' do
309
- header('Content-Disposition', '/foo/test.xml').must_equal 'attachment; filename="test.xml"'
310
- body.must_equal 'b'
311
- end
312
-
313
- it 'sets the Content-Disposition header even when a filename is not given' do
314
- sin_app{attachment}
315
- header('Content-Disposition', '/foo/test.xml').must_equal 'attachment'
316
- end
317
-
318
- it 'sets the Content-Type header' do
319
- header('Content-Type', 'test.xml').must_equal 'application/xml'
320
- end
321
-
322
- it 'does not modify the default Content-Type without a file extension' do
323
- header('Content-Type', 'README').must_equal 'text/html'
324
- end
325
-
326
- it 'should not modify the Content-Type if it is already set' do
327
- sin_app do
328
- content_type :atom
329
- attachment 'test.xml'
330
- end
331
-
332
- header('Content-Type', 'README').must_equal 'application/atom+xml'
333
- end
334
- end
335
-
336
- describe 'send_file' do
337
- before(:all) do
338
- file = @file = 'spec/assets/css/raw.css'
339
- @content = File.read(@file)
340
- sin_app{send_file file, env['OPTS'] || {}}
341
- end
342
-
343
- it "sends the contents of the file" do
344
- status.must_equal 200
345
- body.must_equal @content
346
- end
347
-
348
- it 'sets the Content-Type response header if a mime-type can be located' do
349
- header('Content-Type').must_equal 'text/css'
350
- end
351
-
352
- it 'sets the Content-Type response header if type option is set to a file extension' do
353
- header('Content-Type', 'OPTS'=>{:type => 'html'}).must_equal 'text/html'
354
- end
355
-
356
- it 'sets the Content-Type response header if type option is set to a mime type' do
357
- header('Content-Type', 'OPTS'=>{:type => 'application/octet-stream'}).must_equal 'application/octet-stream'
358
- end
359
-
360
- it 'sets the Content-Length response header' do
361
- header('Content-Length').must_equal @content.length.to_s
362
- end
363
-
364
- it 'sets the Last-Modified response header' do
365
- header('Last-Modified').must_equal File.mtime(@file).httpdate
366
- end
367
-
368
- it 'allows passing in a different Last-Modified response header with :last_modified' do
369
- time = Time.now
370
- @app.plugin :caching
371
- header('Last-Modified', 'OPTS'=>{:last_modified => time}).must_equal time.httpdate
372
- end
373
-
374
- it "returns a 404 when not found" do
375
- sin_app{send_file 'this-file-does-not-exist.txt'}
376
- status.must_equal 404
377
- end
378
-
379
- it "does not set the Content-Disposition header by default" do
380
- header('Content-Disposition').must_be_nil
381
- end
382
-
383
- it "sets the Content-Disposition header when :disposition set to 'attachment'" do
384
- header('Content-Disposition', 'OPTS'=>{:disposition => 'attachment'}).must_equal 'attachment; filename="raw.css"'
385
- end
386
-
387
- it "does not set add a file name if filename is false" do
388
- header('Content-Disposition', 'OPTS'=>{:disposition => 'inline', :filename=>false}).must_equal 'inline'
389
- end
390
-
391
- it "sets the Content-Disposition header when :disposition set to 'inline'" do
392
- header('Content-Disposition', 'OPTS'=>{:disposition => 'inline'}).must_equal 'inline; filename="raw.css"'
393
- end
394
-
395
- it "sets the Content-Disposition header when :filename provided" do
396
- header('Content-Disposition', 'OPTS'=>{:filename => 'foo.txt'}).must_equal 'attachment; filename="foo.txt"'
397
- end
398
-
399
- it 'allows setting a custom status code' do
400
- status('OPTS'=>{:status=>201}).must_equal 201
401
- end
402
-
403
- it "is able to send files with unknown mime type" do
404
- header('Content-Type', 'OPTS'=>{:type => '.foobar'}).must_equal 'application/octet-stream'
405
- end
406
-
407
- it "does not override Content-Type if already set and no explicit type is given" do
408
- file = @file
409
- sin_app do
410
- content_type :png
411
- send_file file
412
- end
413
- header('Content-Type').must_equal 'image/png'
414
- end
415
-
416
- it "does override Content-Type even if already set, if explicit type is given" do
417
- file = @file
418
- sin_app do
419
- content_type :png
420
- send_file file, :type => :gif
421
- end
422
- header('Content-Type').must_equal 'image/gif'
423
- end
424
- end
425
-
426
- describe 'uri' do
427
- describe "without arguments" do
428
- before do
429
- sin_app{uri}
430
- end
431
-
432
- it 'generates absolute urls' do
433
- body('HTTP_HOST'=>'example.org').must_equal 'http://example.org/'
434
- end
435
-
436
- it 'includes path_info' do
437
- body('/foo', 'HTTP_HOST'=>'example.org').must_equal 'http://example.org/foo'
438
- end
439
-
440
- it 'includes script_name' do
441
- body('/bar', 'HTTP_HOST'=>'example.org', "SCRIPT_NAME" => '/foo').must_equal 'http://example.org/foo/bar'
442
- end
443
-
444
- it 'handles standard HTTP and HTTPS ports' do
445
- body('SERVER_NAME'=>'example.org', 'SERVER_PORT' => '80').must_equal 'http://example.org/'
446
- body('SERVER_NAME'=>'example.org', 'SERVER_PORT' => '443', 'HTTPS'=>'on').must_equal 'https://example.org/'
447
- end
448
-
449
- it 'handles non-standard HTTP port' do
450
- body('SERVER_NAME'=>'example.org', 'SERVER_PORT' => '81').must_equal 'http://example.org:81/'
451
- body('SERVER_NAME'=>'example.org', 'SERVER_PORT' => '443').must_equal 'http://example.org:443/'
452
- end
453
-
454
- it 'handles non-standard HTTPS port' do
455
- body('SERVER_NAME'=>'example.org', 'SERVER_PORT' => '444', 'HTTPS'=>'on').must_equal 'https://example.org:444/'
456
- body('SERVER_NAME'=>'example.org', 'SERVER_PORT' => '80', 'HTTPS'=>'on').must_equal 'https://example.org:80/'
457
- end
458
-
459
- it 'handles reverse proxy' do
460
- body('SERVER_NAME'=>'example.org', 'HTTP_X_FORWARDED_HOST' => 'example.com', 'SERVER_PORT' => '8080').must_equal 'http://example.com/'
461
- end
462
- end
463
-
464
- it 'allows passing an alternative to path_info' do
465
- sin_app{uri '/bar'}
466
- body('HTTP_HOST'=>'example.org').must_equal 'http://example.org/bar'
467
- body('HTTP_HOST'=>'example.org', "SCRIPT_NAME" => '/foo').must_equal 'http://example.org/foo/bar'
468
- end
469
-
470
- it 'handles absolute URIs' do
471
- sin_app{uri 'http://google.com'}
472
- body('HTTP_HOST'=>'example.org').must_equal 'http://google.com'
473
- end
474
-
475
- it 'handles different protocols' do
476
- sin_app{uri 'mailto:jsmith@example.com'}
477
- body('HTTP_HOST'=>'example.org').must_equal 'mailto:jsmith@example.com'
478
- end
479
-
480
- it 'allows turning off host' do
481
- sin_app{uri '/foo', false}
482
- body('HTTP_HOST'=>'example.org').must_equal '/foo'
483
- body('HTTP_HOST'=>'example.org', "SCRIPT_NAME" => '/bar').must_equal '/bar/foo'
484
- end
485
-
486
- it 'allows turning off script_name' do
487
- sin_app{uri '/foo', true, false}
488
- body('HTTP_HOST'=>'example.org').must_equal 'http://example.org/foo'
489
- body('HTTP_HOST'=>'example.org', "SCRIPT_NAME" => '/bar').must_equal 'http://example.org/foo'
490
- end
491
-
492
- it 'is aliased to #url' do
493
- sin_app{url}
494
- body('HTTP_HOST'=>'example.org').must_equal 'http://example.org/'
495
- end
496
-
497
- it 'is aliased to #to' do
498
- sin_app{to}
499
- body('HTTP_HOST'=>'example.org').must_equal 'http://example.org/'
500
- end
501
-
502
- it 'accepts a URI object instead of a String' do
503
- sin_app{uri URI.parse('http://roda.jeremyevans.net')}
504
- body.must_equal 'http://roda.jeremyevans.net'
505
- end
506
- end
507
-
508
- it 'logger logs to rack.logger' do
509
- sin_app{logger.info "foo"; nil}
510
- o = Object.new
511
- def o.method_missing(*a)
512
- (@a ||= []) << a
513
- end
514
- def o.logs
515
- @a
516
- end
517
-
518
- status('rack.logger'=>o).must_equal 404
519
- o.logs.must_equal [[:info, 'foo']]
520
- end
521
-
522
- it 'supports disabling delegation if :delegate=>false option is provided' do
523
- app(:bare) do
524
- plugin :sinatra_helpers, :delegate=>false
525
- route do |r|
526
- r.root{content_type}
527
- r.is("req"){r.ssl?.to_s}
528
- r.is("res"){response.not_found?.inspect}
529
- end
530
- end
531
-
532
- proc{body}.must_raise(NameError)
533
- body('/req').must_equal 'false'
534
- body('/res').must_equal 'nil'
535
- end
536
- end
537
-