sinatra 1.3.6 → 1.4.0.a
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sinatra might be problematic. Click here for more details.
- data/CHANGES +96 -22
- data/Gemfile +11 -3
- data/README.de.md +2590 -0
- data/README.es.rdoc +66 -38
- data/README.fr.md +2630 -0
- data/README.hu.rdoc +3 -2
- data/README.jp.rdoc +16 -3
- data/README.ko.rdoc +11 -5
- data/README.md +2699 -0
- data/README.pt-br.rdoc +152 -21
- data/README.pt-pt.rdoc +3 -2
- data/README.ru.md +2724 -0
- data/README.zh.rdoc +3 -3
- data/Rakefile +3 -4
- data/examples/chat.rb +3 -3
- data/lib/sinatra/base.rb +433 -247
- data/lib/sinatra/main.rb +4 -2
- data/lib/sinatra/showexceptions.rb +6 -1
- data/lib/sinatra/version.rb +1 -1
- data/test/base_test.rb +21 -9
- data/test/builder_test.rb +15 -19
- data/test/coffee_test.rb +4 -6
- data/test/compile_test.rb +154 -0
- data/test/contest.rb +4 -6
- data/test/creole_test.rb +5 -5
- data/test/delegator_test.rb +1 -3
- data/test/erb_test.rb +32 -20
- data/test/extensions_test.rb +1 -3
- data/test/filter_test.rb +65 -56
- data/test/haml_test.rb +34 -26
- data/test/helpers_test.rb +331 -221
- data/test/integration_helper.rb +8 -0
- data/test/integration_test.rb +3 -1
- data/test/less_test.rb +10 -8
- data/test/liquid_test.rb +22 -4
- data/test/mapped_error_test.rb +122 -96
- data/test/markaby_test.rb +5 -5
- data/test/markdown_test.rb +5 -5
- data/test/middleware_test.rb +3 -3
- data/test/nokogiri_test.rb +4 -6
- data/test/rabl_test.rb +89 -0
- data/test/radius_test.rb +4 -4
- data/test/rdoc_test.rb +7 -7
- data/test/readme_test.rb +14 -30
- data/test/request_test.rb +15 -0
- data/test/response_test.rb +3 -4
- data/test/result_test.rb +11 -33
- data/test/route_added_hook_test.rb +10 -10
- data/test/routing_test.rb +123 -1
- data/test/sass_test.rb +26 -26
- data/test/scss_test.rb +16 -16
- data/test/server_test.rb +2 -2
- data/test/settings_test.rb +48 -4
- data/test/sinatra_test.rb +2 -7
- data/test/slim_test.rb +37 -23
- data/test/static_test.rb +56 -15
- data/test/streaming_test.rb +11 -2
- data/test/templates_test.rb +117 -45
- data/test/textile_test.rb +9 -9
- data/test/views/hello.rabl +2 -0
- data/test/views/hello.wlang +1 -0
- data/test/views/hello.yajl +1 -0
- data/test/views/layout2.rabl +3 -0
- data/test/views/layout2.wlang +2 -0
- data/test/wlang_test.rb +87 -0
- data/test/yajl_test.rb +86 -0
- metadata +27 -17
- data/README.de.rdoc +0 -2097
- data/README.fr.rdoc +0 -2036
- data/README.rdoc +0 -2017
- data/README.ru.rdoc +0 -1785
data/test/integration_helper.rb
CHANGED
@@ -126,6 +126,14 @@ module IntegrationHelper
|
|
126
126
|
name.to_s == "thin"
|
127
127
|
end
|
128
128
|
|
129
|
+
def puma?
|
130
|
+
name.to_s == "puma"
|
131
|
+
end
|
132
|
+
|
133
|
+
def trinidad?
|
134
|
+
name.to_s == "trinidad"
|
135
|
+
end
|
136
|
+
|
129
137
|
def warnings
|
130
138
|
log.scan(%r[(?:\(eval|lib/sinatra).*warning:.*$])
|
131
139
|
end
|
data/test/integration_test.rb
CHANGED
@@ -10,8 +10,10 @@ class IntegrationTest < Test::Unit::TestCase
|
|
10
10
|
attr_accessor :server
|
11
11
|
|
12
12
|
it('sets the app_file') { assert_equal server.app_file, server.get("/app_file") }
|
13
|
+
it('only extends main') { assert_equal "true", server.get("/mainonly") }
|
13
14
|
|
14
15
|
it 'logs once in development mode' do
|
16
|
+
next if server.puma? or RUBY_ENGINE == 'jruby'
|
15
17
|
random = "%064x" % Kernel.rand(2**256-1)
|
16
18
|
server.get "/ping?x=#{random}"
|
17
19
|
count = server.log.scan("GET /ping?x=#{random}").count
|
@@ -19,7 +21,7 @@ class IntegrationTest < Test::Unit::TestCase
|
|
19
21
|
end
|
20
22
|
|
21
23
|
it 'streams' do
|
22
|
-
next if server.webrick?
|
24
|
+
next if server.webrick? or server.trinidad?
|
23
25
|
times, chunks = [Time.now], []
|
24
26
|
server.get_stream do |chunk|
|
25
27
|
next if chunk.empty?
|
data/test/less_test.rb
CHANGED
@@ -5,22 +5,26 @@ require 'less'
|
|
5
5
|
|
6
6
|
class LessTest < Test::Unit::TestCase
|
7
7
|
def less_app(options = {}, &block)
|
8
|
-
mock_app
|
8
|
+
mock_app do
|
9
9
|
set :views, File.dirname(__FILE__) + '/views'
|
10
10
|
set options
|
11
|
-
get
|
12
|
-
|
11
|
+
get('/', &block)
|
12
|
+
end
|
13
13
|
get '/'
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'renders inline Less strings' do
|
17
|
-
less_app {
|
17
|
+
less_app {
|
18
|
+
less "@white_color: #fff; #main { background-color: @white_color }"
|
19
|
+
}
|
18
20
|
assert ok?
|
19
21
|
assert_equal "#main{background-color:#ffffff;}", body.gsub(/\s/, "")
|
20
22
|
end
|
21
23
|
|
22
24
|
it 'defaults content type to css' do
|
23
|
-
less_app {
|
25
|
+
less_app {
|
26
|
+
less "@white_color: #fff; #main { background-color: @white_color }"
|
27
|
+
}
|
24
28
|
assert ok?
|
25
29
|
assert_equal "text/css;charset=utf-8", response['Content-Type']
|
26
30
|
end
|
@@ -55,9 +59,7 @@ class LessTest < Test::Unit::TestCase
|
|
55
59
|
end
|
56
60
|
|
57
61
|
it "raises error if template not found" do
|
58
|
-
mock_app {
|
59
|
-
get('/') { less :no_such_template }
|
60
|
-
}
|
62
|
+
mock_app { get('/') { less :no_such_template } }
|
61
63
|
assert_raise(Errno::ENOENT) { get('/') }
|
62
64
|
end
|
63
65
|
end
|
data/test/liquid_test.rb
CHANGED
@@ -7,7 +7,7 @@ class LiquidTest < Test::Unit::TestCase
|
|
7
7
|
def liquid_app(&block)
|
8
8
|
mock_app do
|
9
9
|
set :views, File.dirname(__FILE__) + '/views'
|
10
|
-
get
|
10
|
+
get('/', &block)
|
11
11
|
end
|
12
12
|
get '/'
|
13
13
|
end
|
@@ -44,14 +44,32 @@ class LiquidTest < Test::Unit::TestCase
|
|
44
44
|
mock_app { get('/') { liquid :no_such_template } }
|
45
45
|
assert_raise(Errno::ENOENT) { get('/') }
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
it "allows passing locals" do
|
49
|
-
liquid_app
|
49
|
+
liquid_app {
|
50
50
|
liquid '{{ value }}', :locals => { :value => 'foo' }
|
51
|
-
|
51
|
+
}
|
52
52
|
assert ok?
|
53
53
|
assert_equal 'foo', body
|
54
54
|
end
|
55
|
+
|
56
|
+
it "can rendere truly nested layouts by accepting a layout and a block with the contents" do
|
57
|
+
mock_app do
|
58
|
+
template(:main_outer_layout) { "<h1>Title</h1>\n{{ yield }}" }
|
59
|
+
template(:an_inner_layout) { "<h2>Subtitle</h2>\n{{ yield }}" }
|
60
|
+
template(:a_page) { "<p>Contents.</p>\n" }
|
61
|
+
get('/') do
|
62
|
+
liquid :main_outer_layout, :layout => false do
|
63
|
+
liquid :an_inner_layout do
|
64
|
+
liquid :a_page
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
get '/'
|
70
|
+
assert ok?
|
71
|
+
assert_body "<h1>Title</h1>\n<h2>Subtitle</h2>\n<p>Contents.</p>\n"
|
72
|
+
end
|
55
73
|
end
|
56
74
|
|
57
75
|
rescue LoadError
|
data/test/mapped_error_test.rb
CHANGED
@@ -7,9 +7,20 @@ class FooNotFound < Sinatra::NotFound
|
|
7
7
|
end
|
8
8
|
|
9
9
|
class FooSpecialError < RuntimeError
|
10
|
-
def
|
10
|
+
def http_status; 501 end
|
11
11
|
end
|
12
12
|
|
13
|
+
class FooStatusOutOfRangeError < RuntimeError
|
14
|
+
def code; 4000 end
|
15
|
+
end
|
16
|
+
|
17
|
+
class FooWithCode < RuntimeError
|
18
|
+
def code; 419 end
|
19
|
+
end
|
20
|
+
|
21
|
+
class FirstError < RuntimeError; end
|
22
|
+
class SecondError < RuntimeError; end
|
23
|
+
|
13
24
|
class MappedErrorTest < Test::Unit::TestCase
|
14
25
|
def test_default
|
15
26
|
assert true
|
@@ -17,13 +28,11 @@ class MappedErrorTest < Test::Unit::TestCase
|
|
17
28
|
|
18
29
|
describe 'Exception Mappings' do
|
19
30
|
it 'invokes handlers registered with ::error when raised' do
|
20
|
-
mock_app
|
31
|
+
mock_app do
|
21
32
|
set :raise_errors, false
|
22
33
|
error(FooError) { 'Foo!' }
|
23
|
-
get
|
24
|
-
|
25
|
-
end
|
26
|
-
}
|
34
|
+
get('/') { raise FooError }
|
35
|
+
end
|
27
36
|
get '/'
|
28
37
|
assert_equal 500, status
|
29
38
|
assert_equal 'Foo!', body
|
@@ -39,13 +48,11 @@ class MappedErrorTest < Test::Unit::TestCase
|
|
39
48
|
end
|
40
49
|
|
41
50
|
it 'uses the Exception handler if no matching handler found' do
|
42
|
-
mock_app
|
51
|
+
mock_app do
|
43
52
|
set :raise_errors, false
|
44
53
|
error(Exception) { 'Exception!' }
|
45
|
-
get
|
46
|
-
|
47
|
-
end
|
48
|
-
}
|
54
|
+
get('/') { raise FooError }
|
55
|
+
end
|
49
56
|
|
50
57
|
get '/'
|
51
58
|
assert_equal 500, status
|
@@ -53,13 +60,11 @@ class MappedErrorTest < Test::Unit::TestCase
|
|
53
60
|
end
|
54
61
|
|
55
62
|
it 'walks down inheritance chain for errors' do
|
56
|
-
mock_app
|
63
|
+
mock_app do
|
57
64
|
set :raise_errors, false
|
58
65
|
error(RuntimeError) { 'Exception!' }
|
59
|
-
get
|
60
|
-
|
61
|
-
end
|
62
|
-
}
|
66
|
+
get('/') { raise FooError }
|
67
|
+
end
|
63
68
|
|
64
69
|
get '/'
|
65
70
|
assert_equal 500, status
|
@@ -67,15 +72,13 @@ class MappedErrorTest < Test::Unit::TestCase
|
|
67
72
|
end
|
68
73
|
|
69
74
|
it 'favors subclass handler over superclass handler if available' do
|
70
|
-
mock_app
|
75
|
+
mock_app do
|
71
76
|
set :raise_errors, false
|
72
77
|
error(Exception) { 'Exception!' }
|
73
78
|
error(FooError) { 'FooError!' }
|
74
79
|
error(RuntimeError) { 'Exception!' }
|
75
|
-
get
|
76
|
-
|
77
|
-
end
|
78
|
-
}
|
80
|
+
get('/') { raise FooError }
|
81
|
+
end
|
79
82
|
|
80
83
|
get '/'
|
81
84
|
assert_equal 500, status
|
@@ -83,68 +86,58 @@ class MappedErrorTest < Test::Unit::TestCase
|
|
83
86
|
end
|
84
87
|
|
85
88
|
it "sets env['sinatra.error'] to the rescued exception" do
|
86
|
-
mock_app
|
89
|
+
mock_app do
|
87
90
|
set :raise_errors, false
|
88
|
-
error(FooError)
|
91
|
+
error(FooError) do
|
89
92
|
assert env.include?('sinatra.error')
|
90
93
|
assert env['sinatra.error'].kind_of?(FooError)
|
91
94
|
'looks good'
|
92
|
-
}
|
93
|
-
get '/' do
|
94
|
-
raise FooError
|
95
95
|
end
|
96
|
-
|
96
|
+
get('/') { raise FooError }
|
97
|
+
end
|
97
98
|
get '/'
|
98
99
|
assert_equal 'looks good', body
|
99
100
|
end
|
100
101
|
|
101
102
|
it "raises errors from the app when raise_errors set and no handler defined" do
|
102
|
-
mock_app
|
103
|
+
mock_app do
|
103
104
|
set :raise_errors, true
|
104
|
-
get
|
105
|
-
|
106
|
-
end
|
107
|
-
}
|
105
|
+
get('/') { raise FooError }
|
106
|
+
end
|
108
107
|
assert_raise(FooError) { get '/' }
|
109
108
|
end
|
110
109
|
|
111
110
|
it "calls error handlers before raising errors even when raise_errors is set" do
|
112
|
-
mock_app
|
111
|
+
mock_app do
|
113
112
|
set :raise_errors, true
|
114
113
|
error(FooError) { "she's there." }
|
115
|
-
get
|
116
|
-
|
117
|
-
end
|
118
|
-
}
|
114
|
+
get('/') { raise FooError }
|
115
|
+
end
|
119
116
|
assert_nothing_raised { get '/' }
|
120
117
|
assert_equal 500, status
|
121
118
|
end
|
122
119
|
|
123
120
|
it "never raises Sinatra::NotFound beyond the application" do
|
124
|
-
mock_app(Sinatra::Application)
|
121
|
+
mock_app(Sinatra::Application) do
|
122
|
+
get('/') { raise Sinatra::NotFound }
|
123
|
+
end
|
125
124
|
assert_nothing_raised { get '/' }
|
126
125
|
assert_equal 404, status
|
127
126
|
end
|
128
127
|
|
129
128
|
it "cascades for subclasses of Sinatra::NotFound" do
|
130
|
-
mock_app
|
129
|
+
mock_app do
|
131
130
|
set :raise_errors, true
|
132
131
|
error(FooNotFound) { "foo! not found." }
|
133
|
-
get
|
134
|
-
|
135
|
-
end
|
136
|
-
}
|
132
|
+
get('/') { raise FooNotFound }
|
133
|
+
end
|
137
134
|
assert_nothing_raised { get '/' }
|
138
135
|
assert_equal 404, status
|
139
136
|
assert_equal 'foo! not found.', body
|
140
137
|
end
|
141
138
|
|
142
139
|
it 'has a not_found method for backwards compatibility' do
|
143
|
-
mock_app {
|
144
|
-
not_found do
|
145
|
-
"Lost, are we?"
|
146
|
-
end
|
147
|
-
}
|
140
|
+
mock_app { not_found { "Lost, are we?" } }
|
148
141
|
|
149
142
|
get '/test'
|
150
143
|
assert_equal 404, status
|
@@ -155,12 +148,10 @@ class MappedErrorTest < Test::Unit::TestCase
|
|
155
148
|
base = Class.new(Sinatra::Base)
|
156
149
|
base.error(FooError) { 'base class' }
|
157
150
|
|
158
|
-
mock_app(base)
|
151
|
+
mock_app(base) do
|
159
152
|
set :raise_errors, false
|
160
|
-
get
|
161
|
-
|
162
|
-
end
|
163
|
-
}
|
153
|
+
get('/') { raise FooError }
|
154
|
+
end
|
164
155
|
|
165
156
|
get '/'
|
166
157
|
assert_equal 'base class', body
|
@@ -170,19 +161,17 @@ class MappedErrorTest < Test::Unit::TestCase
|
|
170
161
|
base = Class.new(Sinatra::Base)
|
171
162
|
base.error(FooError) { 'base class' }
|
172
163
|
|
173
|
-
mock_app(base)
|
164
|
+
mock_app(base) do
|
174
165
|
set :raise_errors, false
|
175
166
|
error(FooError) { 'subclass' }
|
176
|
-
get
|
177
|
-
|
178
|
-
end
|
179
|
-
}
|
167
|
+
get('/') { raise FooError }
|
168
|
+
end
|
180
169
|
|
181
170
|
get '/'
|
182
171
|
assert_equal 'subclass', body
|
183
172
|
end
|
184
173
|
|
185
|
-
it 'honors Exception#
|
174
|
+
it 'honors Exception#http_status if present' do
|
186
175
|
mock_app do
|
187
176
|
set :raise_errors, false
|
188
177
|
error(501) { 'Foo!' }
|
@@ -192,68 +181,105 @@ class MappedErrorTest < Test::Unit::TestCase
|
|
192
181
|
assert_equal 501, status
|
193
182
|
assert_equal 'Foo!', body
|
194
183
|
end
|
184
|
+
|
185
|
+
it 'does not use Exception#code by default' do
|
186
|
+
mock_app do
|
187
|
+
set :raise_errors, false
|
188
|
+
get('/') { raise FooWithCode }
|
189
|
+
end
|
190
|
+
get '/'
|
191
|
+
assert_equal 500, status
|
192
|
+
end
|
193
|
+
|
194
|
+
it 'uses Exception#code if use_code is enabled' do
|
195
|
+
mock_app do
|
196
|
+
set :raise_errors, false
|
197
|
+
set :use_code, true
|
198
|
+
get('/') { raise FooWithCode }
|
199
|
+
end
|
200
|
+
get '/'
|
201
|
+
assert_equal 419, status
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'does not rely on Exception#code for invalid codes' do
|
205
|
+
mock_app do
|
206
|
+
set :raise_errors, false
|
207
|
+
set :use_code, true
|
208
|
+
get('/') { raise FooStatusOutOfRangeError }
|
209
|
+
end
|
210
|
+
get '/'
|
211
|
+
assert_equal 500, status
|
212
|
+
end
|
213
|
+
|
214
|
+
it "allows a stack of exception_handlers" do
|
215
|
+
mock_app do
|
216
|
+
set :raise_errors, false
|
217
|
+
error(FirstError) { 'First!' }
|
218
|
+
error(SecondError) { 'Second!' }
|
219
|
+
get('/'){ raise SecondError }
|
220
|
+
end
|
221
|
+
get '/'
|
222
|
+
assert_equal 500, status
|
223
|
+
assert_equal 'Second!', body
|
224
|
+
end
|
225
|
+
|
226
|
+
it "allows an exception handler to pass control to the next exception handler" do
|
227
|
+
mock_app do
|
228
|
+
set :raise_errors, false
|
229
|
+
error(500, FirstError) { 'First!' }
|
230
|
+
error(500, SecondError) { pass }
|
231
|
+
get('/') { raise 500 }
|
232
|
+
end
|
233
|
+
get '/'
|
234
|
+
assert_equal 500, status
|
235
|
+
assert_equal 'First!', body
|
236
|
+
end
|
237
|
+
|
238
|
+
it "allows an exception handler to handle the exception" do
|
239
|
+
mock_app do
|
240
|
+
set :raise_errors, false
|
241
|
+
error(500, FirstError) { 'First!' }
|
242
|
+
error(500, SecondError) { 'Second!' }
|
243
|
+
get('/') { raise 500 }
|
244
|
+
end
|
245
|
+
get '/'
|
246
|
+
assert_equal 500, status
|
247
|
+
assert_equal 'Second!', body
|
248
|
+
end
|
195
249
|
end
|
196
250
|
|
197
251
|
describe 'Custom Error Pages' do
|
198
252
|
it 'allows numeric status code mappings to be registered with ::error' do
|
199
|
-
mock_app
|
253
|
+
mock_app do
|
200
254
|
set :raise_errors, false
|
201
255
|
error(500) { 'Foo!' }
|
202
|
-
get
|
203
|
-
|
204
|
-
end
|
205
|
-
}
|
256
|
+
get('/') { [500, {}, 'Internal Foo Error'] }
|
257
|
+
end
|
206
258
|
get '/'
|
207
259
|
assert_equal 500, status
|
208
260
|
assert_equal 'Foo!', body
|
209
261
|
end
|
210
262
|
|
211
263
|
it 'allows ranges of status code mappings to be registered with :error' do
|
212
|
-
mock_app
|
264
|
+
mock_app do
|
213
265
|
set :raise_errors, false
|
214
266
|
error(500..550) { "Error: #{response.status}" }
|
215
|
-
get
|
216
|
-
|
217
|
-
end
|
218
|
-
}
|
267
|
+
get('/') { [507, {}, 'A very special error'] }
|
268
|
+
end
|
219
269
|
get '/'
|
220
270
|
assert_equal 507, status
|
221
271
|
assert_equal 'Error: 507', body
|
222
272
|
end
|
223
273
|
|
224
274
|
it 'allows passing more than one range' do
|
225
|
-
mock_app
|
275
|
+
mock_app do
|
226
276
|
set :raise_errors, false
|
227
277
|
error(409..411, 503..509) { "Error: #{response.status}" }
|
228
|
-
get
|
229
|
-
|
230
|
-
end
|
231
|
-
}
|
278
|
+
get('/') { [507, {}, 'A very special error'] }
|
279
|
+
end
|
232
280
|
get '/'
|
233
281
|
assert_equal 507, status
|
234
282
|
assert_equal 'Error: 507', body
|
235
283
|
end
|
236
|
-
|
237
|
-
class FooError < RuntimeError
|
238
|
-
end
|
239
|
-
|
240
|
-
it 'runs after exception mappings and overwrites body' do
|
241
|
-
mock_app {
|
242
|
-
set :raise_errors, false
|
243
|
-
error FooError do
|
244
|
-
response.status = 502
|
245
|
-
'from exception mapping'
|
246
|
-
end
|
247
|
-
error(500) { 'from 500 handler' }
|
248
|
-
error(502) { 'from custom error page' }
|
249
|
-
|
250
|
-
get '/' do
|
251
|
-
raise FooError
|
252
|
-
end
|
253
|
-
}
|
254
|
-
get '/'
|
255
|
-
assert_equal 502, status
|
256
|
-
assert_equal 'from custom error page', body
|
257
|
-
end
|
258
284
|
end
|
259
285
|
end
|