rtomayko-sinatra 0.3.3 → 0.8.9

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 (81) hide show
  1. data/AUTHORS +40 -0
  2. data/CHANGES +167 -0
  3. data/README.rdoc +104 -98
  4. data/Rakefile +27 -9
  5. data/{test → compat}/app_test.rb +11 -10
  6. data/{test → compat}/application_test.rb +10 -5
  7. data/compat/builder_test.rb +101 -0
  8. data/{test → compat}/custom_error_test.rb +0 -0
  9. data/compat/erb_test.rb +136 -0
  10. data/{test → compat}/events_test.rb +12 -2
  11. data/compat/filter_test.rb +30 -0
  12. data/compat/haml_test.rb +233 -0
  13. data/compat/helper.rb +21 -0
  14. data/compat/mapped_error_test.rb +72 -0
  15. data/{test → compat}/pipeline_test.rb +9 -4
  16. data/{test → compat}/public/foo.xml +0 -0
  17. data/compat/sass_test.rb +57 -0
  18. data/{test → compat}/sessions_test.rb +0 -0
  19. data/{test → compat}/streaming_test.rb +4 -1
  20. data/{test → compat}/sym_params_test.rb +0 -0
  21. data/{test → compat}/template_test.rb +0 -0
  22. data/{test → compat}/use_in_file_templates_test.rb +0 -0
  23. data/{test → compat}/views/foo.builder +0 -0
  24. data/{test → compat}/views/foo.erb +0 -0
  25. data/{test → compat}/views/foo.haml +0 -0
  26. data/{test → compat}/views/foo.sass +0 -0
  27. data/{test → compat}/views/foo_layout.erb +0 -0
  28. data/{test → compat}/views/foo_layout.haml +0 -0
  29. data/{test → compat}/views/layout_test/foo.builder +0 -0
  30. data/{test → compat}/views/layout_test/foo.erb +0 -0
  31. data/{test → compat}/views/layout_test/foo.haml +0 -0
  32. data/{test → compat}/views/layout_test/foo.sass +0 -0
  33. data/{test → compat}/views/layout_test/layout.builder +0 -0
  34. data/{test → compat}/views/layout_test/layout.erb +0 -0
  35. data/{test → compat}/views/layout_test/layout.haml +0 -0
  36. data/{test → compat}/views/layout_test/layout.sass +0 -0
  37. data/{test → compat}/views/no_layout/no_layout.builder +0 -0
  38. data/{test → compat}/views/no_layout/no_layout.haml +0 -0
  39. data/lib/sinatra/base.rb +818 -0
  40. data/lib/sinatra/compat.rb +239 -0
  41. data/{images → lib/sinatra/images}/404.png +0 -0
  42. data/{images → lib/sinatra/images}/500.png +0 -0
  43. data/lib/sinatra/main.rb +48 -0
  44. data/lib/sinatra/test/rspec.rb +1 -9
  45. data/lib/sinatra/test/spec.rb +1 -9
  46. data/lib/sinatra/test/unit.rb +3 -5
  47. data/lib/sinatra/test.rb +112 -0
  48. data/lib/sinatra.rb +3 -1486
  49. data/sinatra.gemspec +66 -36
  50. data/test/base_test.rb +72 -0
  51. data/test/builder_test.rb +56 -89
  52. data/test/data/reload_app_file.rb +3 -0
  53. data/test/erb_test.rb +44 -125
  54. data/test/filter_test.rb +29 -20
  55. data/test/haml_test.rb +57 -218
  56. data/test/helpers_test.rb +368 -0
  57. data/test/mapped_error_test.rb +141 -49
  58. data/test/middleware_test.rb +63 -0
  59. data/test/options_test.rb +103 -0
  60. data/test/reload_test.rb +65 -0
  61. data/test/request_test.rb +11 -0
  62. data/test/result_test.rb +92 -0
  63. data/test/routing_test.rb +338 -0
  64. data/test/sass_test.rb +33 -50
  65. data/test/sinatra_test.rb +15 -0
  66. data/test/static_test.rb +60 -0
  67. data/test/templates_test.rb +92 -0
  68. data/test/views/hello.builder +1 -0
  69. data/test/views/hello.erb +1 -0
  70. data/test/views/hello.haml +1 -0
  71. data/test/views/hello.sass +2 -0
  72. data/test/views/hello.test +1 -0
  73. data/test/views/layout2.builder +3 -0
  74. data/test/views/layout2.erb +2 -0
  75. data/test/views/layout2.haml +2 -0
  76. data/test/views/layout2.test +1 -0
  77. metadata +78 -48
  78. data/ChangeLog +0 -96
  79. data/lib/sinatra/test/methods.rb +0 -76
  80. data/test/event_context_test.rb +0 -15
  81. data/test/helper.rb +0 -9
@@ -0,0 +1,338 @@
1
+ require 'test/spec'
2
+ require 'sinatra/base'
3
+ require 'sinatra/test'
4
+
5
+ describe "Routing" do
6
+ include Sinatra::Test
7
+
8
+ %w[get put post delete head].each do |verb|
9
+ it "defines #{verb.upcase} request handlers with #{verb}" do
10
+ mock_app {
11
+ send verb, '/hello' do
12
+ 'Hello World'
13
+ end
14
+ }
15
+
16
+ request = Rack::MockRequest.new(@app)
17
+ response = request.request(verb.upcase, '/hello', {})
18
+ response.should.be.ok
19
+ response.body.should.equal 'Hello World'
20
+ end
21
+ end
22
+
23
+ it "404s when no route satisfies the request" do
24
+ mock_app {
25
+ get('/foo') { }
26
+ }
27
+ get '/bar'
28
+ status.should.equal 404
29
+ end
30
+
31
+ it "exposes params with indifferent hash" do
32
+ mock_app {
33
+ get '/:foo' do
34
+ params['foo'].should.equal 'bar'
35
+ params[:foo].should.equal 'bar'
36
+ 'well, alright'
37
+ end
38
+ }
39
+ get '/bar'
40
+ body.should.equal 'well, alright'
41
+ end
42
+
43
+ it "merges named params and query string params in params" do
44
+ mock_app {
45
+ get '/:foo' do
46
+ params['foo'].should.equal 'bar'
47
+ params['baz'].should.equal 'biz'
48
+ end
49
+ }
50
+ get '/bar?baz=biz'
51
+ should.be.ok
52
+ end
53
+
54
+ it "supports named params like /hello/:person" do
55
+ mock_app {
56
+ get '/hello/:person' do
57
+ "Hello #{params['person']}"
58
+ end
59
+ }
60
+ get '/hello/Frank'
61
+ body.should.equal 'Hello Frank'
62
+ end
63
+
64
+ it "supports optional named params like /?:foo?/?:bar?" do
65
+ mock_app {
66
+ get '/?:foo?/?:bar?' do
67
+ "foo=#{params[:foo]};bar=#{params[:bar]}"
68
+ end
69
+ }
70
+
71
+ get '/hello/world'
72
+ should.be.ok
73
+ body.should.equal "foo=hello;bar=world"
74
+
75
+ get '/hello'
76
+ should.be.ok
77
+ body.should.equal "foo=hello;bar="
78
+
79
+ get '/'
80
+ should.be.ok
81
+ body.should.equal "foo=;bar="
82
+ end
83
+
84
+ it "supports single splat params like /*" do
85
+ mock_app {
86
+ get '/*' do
87
+ params['splat'].should.be.kind_of Array
88
+ params['splat'].join "\n"
89
+ end
90
+ }
91
+
92
+ get '/foo'
93
+ body.should.equal "foo"
94
+
95
+ get '/foo/bar/baz'
96
+ body.should.equal "foo/bar/baz"
97
+ end
98
+
99
+ it "supports mixing multiple splat params like /*/foo/*/*" do
100
+ mock_app {
101
+ get '/*/foo/*/*' do
102
+ params['splat'].should.be.kind_of Array
103
+ params['splat'].join "\n"
104
+ end
105
+ }
106
+
107
+ get '/bar/foo/bling/baz/boom'
108
+ body.should.equal "bar\nbling\nbaz/boom"
109
+
110
+ get '/bar/foo/baz'
111
+ should.be.not_found
112
+ end
113
+
114
+ it "supports mixing named and splat params like /:foo/*" do
115
+ mock_app {
116
+ get '/:foo/*' do
117
+ params['foo'].should.equal 'foo'
118
+ params['splat'].should.equal ['bar/baz']
119
+ end
120
+ }
121
+
122
+ get '/foo/bar/baz'
123
+ should.be.ok
124
+ end
125
+
126
+ it "supports paths that include spaces" do
127
+ mock_app {
128
+ get '/path with spaces' do
129
+ 'looks good'
130
+ end
131
+ }
132
+
133
+ get '/path%20with%20spaces'
134
+ should.be.ok
135
+ body.should.equal 'looks good'
136
+ end
137
+
138
+ it "URL decodes named parameters and splats" do
139
+ mock_app {
140
+ get '/:foo/*' do
141
+ params['foo'].should.equal 'hello world'
142
+ params['splat'].should.equal ['how are you']
143
+ nil
144
+ end
145
+ }
146
+
147
+ get '/hello%20world/how%20are%20you'
148
+ should.be.ok
149
+ end
150
+
151
+ it 'supports regular expressions' do
152
+ mock_app {
153
+ get(/^\/foo...\/bar$/) do
154
+ 'Hello World'
155
+ end
156
+ }
157
+
158
+ get '/foooom/bar'
159
+ should.be.ok
160
+ body.should.equal 'Hello World'
161
+ end
162
+
163
+ it 'makes regular expression captures available in params[:captures]' do
164
+ mock_app {
165
+ get(/^\/fo(.*)\/ba(.*)/) do
166
+ params[:captures].should.equal ['orooomma', 'f']
167
+ 'right on'
168
+ end
169
+ }
170
+
171
+ get '/foorooomma/baf'
172
+ should.be.ok
173
+ body.should.equal 'right on'
174
+ end
175
+
176
+ it "returns response immediately on halt" do
177
+ mock_app {
178
+ get '/' do
179
+ halt 'Hello World'
180
+ 'Boo-hoo World'
181
+ end
182
+ }
183
+
184
+ get '/'
185
+ should.be.ok
186
+ body.should.equal 'Hello World'
187
+ end
188
+
189
+ it "transitions to the next matching route on pass" do
190
+ mock_app {
191
+ get '/:foo' do
192
+ pass
193
+ 'Hello Foo'
194
+ end
195
+
196
+ get '/*' do
197
+ params.should.not.include 'foo'
198
+ 'Hello World'
199
+ end
200
+ }
201
+
202
+ get '/bar'
203
+ should.be.ok
204
+ body.should.equal 'Hello World'
205
+ end
206
+
207
+ it "transitions to 404 when passed and no subsequent route matches" do
208
+ mock_app {
209
+ get '/:foo' do
210
+ pass
211
+ 'Hello Foo'
212
+ end
213
+ }
214
+
215
+ get '/bar'
216
+ should.be.not_found
217
+ end
218
+
219
+ it "passes when matching condition returns false" do
220
+ mock_app {
221
+ condition { params[:foo] == 'bar' }
222
+ get '/:foo' do
223
+ 'Hello World'
224
+ end
225
+ }
226
+
227
+ get '/bar'
228
+ should.be.ok
229
+ body.should.equal 'Hello World'
230
+
231
+ get '/foo'
232
+ should.be.not_found
233
+ end
234
+
235
+ it "does not pass when matching condition returns nil" do
236
+ mock_app {
237
+ condition { nil }
238
+ get '/:foo' do
239
+ 'Hello World'
240
+ end
241
+ }
242
+
243
+ get '/bar'
244
+ should.be.ok
245
+ body.should.equal 'Hello World'
246
+ end
247
+
248
+ it "passes to next route when condition calls pass explicitly" do
249
+ mock_app {
250
+ condition { pass unless params[:foo] == 'bar' }
251
+ get '/:foo' do
252
+ 'Hello World'
253
+ end
254
+ }
255
+
256
+ get '/bar'
257
+ should.be.ok
258
+ body.should.equal 'Hello World'
259
+
260
+ get '/foo'
261
+ should.be.not_found
262
+ end
263
+
264
+ it "passes to the next route when host_name does not match" do
265
+ mock_app {
266
+ host_name 'example.com'
267
+ get '/foo' do
268
+ 'Hello World'
269
+ end
270
+ }
271
+ get '/foo'
272
+ should.be.not_found
273
+
274
+ get '/foo', :env => { 'HTTP_HOST' => 'example.com' }
275
+ status.should.equal 200
276
+ body.should.equal 'Hello World'
277
+ end
278
+
279
+ it "passes to the next route when user_agent does not match" do
280
+ mock_app {
281
+ user_agent(/Foo/)
282
+ get '/foo' do
283
+ 'Hello World'
284
+ end
285
+ }
286
+ get '/foo'
287
+ should.be.not_found
288
+
289
+ get '/foo', :env => { 'HTTP_USER_AGENT' => 'Foo Bar' }
290
+ status.should.equal 200
291
+ body.should.equal 'Hello World'
292
+ end
293
+
294
+ it "makes captures in user agent pattern available in params[:agent]" do
295
+ mock_app {
296
+ user_agent(/Foo (.*)/)
297
+ get '/foo' do
298
+ 'Hello ' + params[:agent].first
299
+ end
300
+ }
301
+ get '/foo', :env => { 'HTTP_USER_AGENT' => 'Foo Bar' }
302
+ status.should.equal 200
303
+ body.should.equal 'Hello Bar'
304
+ end
305
+
306
+ it "filters by accept header" do
307
+ mock_app {
308
+ get '/', :provides => :xml do
309
+ request.env['HTTP_ACCEPT']
310
+ end
311
+ }
312
+
313
+ get '/', :env => { :accept => 'application/xml' }
314
+ should.be.ok
315
+ body.should.equal 'application/xml'
316
+ response.headers['Content-Type'].should.equal 'application/xml'
317
+
318
+ get '/', :env => { :accept => 'text/html' }
319
+ should.not.be.ok
320
+ end
321
+
322
+ it "allows multiple mime types for accept header" do
323
+ types = ['image/jpeg', 'image/pjpeg']
324
+
325
+ mock_app {
326
+ get '/', :provides => types do
327
+ request.env['HTTP_ACCEPT']
328
+ end
329
+ }
330
+
331
+ types.each do |type|
332
+ get '/', :env => { :accept => type }
333
+ should.be.ok
334
+ body.should.equal type
335
+ response.headers['Content-Type'].should.equal type
336
+ end
337
+ end
338
+ end
data/test/sass_test.rb CHANGED
@@ -1,57 +1,40 @@
1
- require File.dirname(__FILE__) + '/helper'
2
-
3
- context "Sass" do
4
-
5
- setup do
6
- Sinatra.application = nil
1
+ require 'test/spec'
2
+ require 'sinatra/base'
3
+ require 'sinatra/test'
4
+
5
+ describe "Sass Templates" do
6
+ include Sinatra::Test
7
+
8
+ def sass_app(&block)
9
+ mock_app {
10
+ set :views, File.dirname(__FILE__) + '/views'
11
+ get '/', &block
12
+ }
13
+ get '/'
7
14
  end
8
15
 
9
- context "Templates (in general)" do
10
-
11
- setup do
12
- Sinatra.application = nil
13
- end
14
-
15
- specify "are read from files if Symbols" do
16
-
17
- get '/from_file' do
18
- sass :foo, :views_directory => File.dirname(__FILE__) + "/views"
19
- end
20
-
21
- get_it '/from_file'
22
- should.be.ok
23
- body.should.equal "#sass {\n background_color: #FFF; }\n"
24
-
25
- end
26
-
27
- specify "raise an error if template not found" do
28
- get '/' do
29
- sass :not_found
30
- end
31
-
32
- lambda { get_it '/' }.should.raise(Errno::ENOENT)
33
- end
34
-
35
- specify "ignore default layout file with .sass extension" do
36
- get '/' do
37
- sass :foo, :views_directory => File.dirname(__FILE__) + "/views/layout_test"
38
- end
39
-
40
- get_it '/'
41
- should.be.ok
42
- body.should.equal "#sass {\n background_color: #FFF; }\n"
43
- end
44
-
45
- specify "ignore explicitly specified layout file" do
46
- get '/' do
47
- sass :foo, :layout => :layout, :views_directory => File.dirname(__FILE__) + "/views/layout_test"
48
- end
16
+ it 'renders inline Sass strings' do
17
+ sass_app { sass "#sass\n :background-color #FFF\n" }
18
+ should.be.ok
19
+ body.should.equal "#sass {\n background-color: #FFF; }\n"
20
+ end
49
21
 
50
- get_it '/'
51
- should.be.ok
52
- body.should.equal "#sass {\n background_color: #FFF; }\n"
53
- end
22
+ it 'renders .sass files in views path' do
23
+ sass_app { sass :hello }
24
+ should.be.ok
25
+ body.should.equal "#sass {\n background-color: #FFF; }\n"
26
+ end
54
27
 
28
+ it 'ignores the layout option' do
29
+ sass_app { sass :hello, :layout => :layout2 }
30
+ should.be.ok
31
+ body.should.equal "#sass {\n background-color: #FFF; }\n"
55
32
  end
56
33
 
34
+ it "raises error if template not found" do
35
+ mock_app {
36
+ get('/') { sass :no_such_template }
37
+ }
38
+ lambda { get('/') }.should.raise(Errno::ENOENT)
39
+ end
57
40
  end
@@ -0,0 +1,15 @@
1
+ require 'test/spec'
2
+ require 'sinatra/base'
3
+ require 'sinatra/test'
4
+
5
+ describe 'Sinatra' do
6
+ it 'creates a new Sinatra::Base subclass on new' do
7
+ app =
8
+ Sinatra.new do
9
+ get '/' do
10
+ 'Hello World'
11
+ end
12
+ end
13
+ app.superclass.should.be Sinatra::Base
14
+ end
15
+ end
@@ -0,0 +1,60 @@
1
+ require 'test/spec'
2
+ require 'sinatra/base'
3
+ require 'sinatra/test'
4
+
5
+ describe 'Static' do
6
+ include Sinatra::Test
7
+ F = ::File
8
+
9
+ before do
10
+ @app = mock_app {
11
+ set :static, true
12
+ set :public, F.dirname(__FILE__)
13
+ }
14
+ end
15
+
16
+ it 'serves GET requests for files in the public directory' do
17
+ get "/#{F.basename(__FILE__)}"
18
+ should.be.ok
19
+ body.should.equal File.read(__FILE__)
20
+ response['Content-Length'].should.equal File.size(__FILE__).to_s
21
+ response.headers.should.include 'Last-Modified'
22
+ end
23
+
24
+ it 'serves HEAD requests for files in the public directory' do
25
+ head "/#{F.basename(__FILE__)}"
26
+ should.be.ok
27
+ body.should.be.empty
28
+ response['Content-Length'].should.equal File.size(__FILE__).to_s
29
+ response.headers.should.include 'Last-Modified'
30
+ end
31
+
32
+ it 'serves files in preference to custom routes' do
33
+ @app.get("/#{F.basename(__FILE__)}") { 'Hello World' }
34
+ get "/#{F.basename(__FILE__)}"
35
+ should.be.ok
36
+ body.should.not.equal 'Hello World'
37
+ end
38
+
39
+ it 'does not serve directories' do
40
+ get "/"
41
+ should.be.not_found
42
+ end
43
+
44
+ it 'passes to the next handler when the static option is disabled' do
45
+ @app.set :static, false
46
+ get "/#{F.basename(__FILE__)}"
47
+ should.be.not_found
48
+ end
49
+
50
+ it 'passes to the next handler when the public option is nil' do
51
+ @app.set :public, nil
52
+ get "/#{F.basename(__FILE__)}"
53
+ should.be.not_found
54
+ end
55
+
56
+ it '404s when a file is not found' do
57
+ get "/foobarbaz.txt"
58
+ should.be.not_found
59
+ end
60
+ end
@@ -0,0 +1,92 @@
1
+ require 'test/spec'
2
+ require 'sinatra/base'
3
+ require 'sinatra/test'
4
+
5
+ describe 'Templating' do
6
+ include Sinatra::Test
7
+
8
+ def render_app(&block)
9
+ mock_app {
10
+ def render_test(template, data, options, &block)
11
+ inner = block ? block.call : ''
12
+ data + inner
13
+ end
14
+ set :views, File.dirname(__FILE__) + '/views'
15
+ get '/', &block
16
+ template(:layout3) { "Layout 3!\n" }
17
+ }
18
+ get '/'
19
+ end
20
+
21
+ def with_default_layout
22
+ layout = File.dirname(__FILE__) + '/views/layout.test'
23
+ File.open(layout, 'wb') { |io| io.write "Layout!\n" }
24
+ yield
25
+ ensure
26
+ File.unlink(layout) rescue nil
27
+ end
28
+
29
+ it 'renders String templates directly' do
30
+ render_app { render :test, 'Hello World' }
31
+ should.be.ok
32
+ body.should.equal 'Hello World'
33
+ end
34
+
35
+ it 'renders Proc templates using the call result' do
36
+ render_app { render :test, Proc.new {'Hello World'} }
37
+ should.be.ok
38
+ body.should.equal 'Hello World'
39
+ end
40
+
41
+ it 'looks up Symbol templates in views directory' do
42
+ render_app { render :test, :hello }
43
+ should.be.ok
44
+ body.should.equal "Hello World!\n"
45
+ end
46
+
47
+ it 'uses the default layout template if not explicitly overridden' do
48
+ with_default_layout do
49
+ render_app { render :test, :hello }
50
+ should.be.ok
51
+ body.should.equal "Layout!\nHello World!\n"
52
+ end
53
+ end
54
+
55
+ it 'uses the default layout template if not really overriden' do
56
+ with_default_layout do
57
+ render_app { render :test, :hello, :layout => true }
58
+ should.be.ok
59
+ body.should.equal "Layout!\nHello World!\n"
60
+ end
61
+ end
62
+
63
+ it 'uses the layout template specified' do
64
+ render_app { render :test, :hello, :layout => :layout2 }
65
+ should.be.ok
66
+ body.should.equal "Layout 2!\nHello World!\n"
67
+ end
68
+
69
+ it 'uses layout templates defined with the #template method' do
70
+ render_app { render :test, :hello, :layout => :layout3 }
71
+ should.be.ok
72
+ body.should.equal "Layout 3!\nHello World!\n"
73
+ end
74
+
75
+ it 'loads templates from source file with use_in_file_templates!' do
76
+ mock_app {
77
+ use_in_file_templates!
78
+ }
79
+ @app.templates[:foo].should.equal "this is foo\n\n"
80
+ @app.templates[:layout].should.equal "X\n= yield\nX\n"
81
+ end
82
+ end
83
+
84
+ __END__
85
+
86
+ @@ foo
87
+ this is foo
88
+
89
+ @@ layout
90
+ X
91
+ = yield
92
+ X
@@ -0,0 +1 @@
1
+ xml.exclaim "You're my boy, #{@name}!"
@@ -0,0 +1 @@
1
+ Hello <%= 'World' %>
@@ -0,0 +1 @@
1
+ %h1 Hello From Haml
@@ -0,0 +1,2 @@
1
+ #sass
2
+ :background-color #FFF
@@ -0,0 +1 @@
1
+ Hello World!
@@ -0,0 +1,3 @@
1
+ xml.layout do
2
+ xml << yield
3
+ end
@@ -0,0 +1,2 @@
1
+ ERB Layout!
2
+ <%= yield %>
@@ -0,0 +1,2 @@
1
+ %h1 HAML Layout!
2
+ %p= yield
@@ -0,0 +1 @@
1
+ Layout 2!