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
@@ -11,16 +11,16 @@ module RouteAddedTest
|
|
11
11
|
end
|
12
12
|
|
13
13
|
class RouteAddedHookTest < Test::Unit::TestCase
|
14
|
-
setup
|
14
|
+
setup do
|
15
15
|
RouteAddedTest.routes.clear
|
16
16
|
RouteAddedTest.procs.clear
|
17
|
-
|
17
|
+
end
|
18
18
|
|
19
19
|
it "should be notified of an added route" do
|
20
|
-
mock_app(Class.new(Sinatra::Base))
|
20
|
+
mock_app(Class.new(Sinatra::Base)) do
|
21
21
|
register RouteAddedTest
|
22
22
|
get('/') {}
|
23
|
-
|
23
|
+
end
|
24
24
|
|
25
25
|
assert_equal [["GET", "/"], ["HEAD", "/"]],
|
26
26
|
RouteAddedTest.routes
|
@@ -38,22 +38,22 @@ class RouteAddedHookTest < Test::Unit::TestCase
|
|
38
38
|
end
|
39
39
|
|
40
40
|
it "should only run once per extension" do
|
41
|
-
mock_app(Class.new(Sinatra::Base))
|
41
|
+
mock_app(Class.new(Sinatra::Base)) do
|
42
42
|
register RouteAddedTest
|
43
43
|
register RouteAddedTest
|
44
44
|
get('/') {}
|
45
|
-
|
45
|
+
end
|
46
46
|
|
47
47
|
assert_equal [["GET", "/"], ["HEAD", "/"]],
|
48
48
|
RouteAddedTest.routes
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
it "should pass route blocks as an argument" do
|
52
|
-
mock_app(Class.new(Sinatra::Base))
|
52
|
+
mock_app(Class.new(Sinatra::Base)) do
|
53
53
|
register RouteAddedTest
|
54
54
|
get('/') {}
|
55
|
-
|
55
|
+
end
|
56
56
|
|
57
|
-
assert_kind_of Proc, RouteAddedTest.procs.first
|
57
|
+
assert_kind_of Proc, RouteAddedTest.procs.first
|
58
58
|
end
|
59
59
|
end
|
data/test/routing_test.rb
CHANGED
@@ -70,6 +70,17 @@ class RoutingTest < Test::Unit::TestCase
|
|
70
70
|
assert_equal 'pass', response.headers['X-Cascade']
|
71
71
|
end
|
72
72
|
|
73
|
+
it "404s and does not set X-Cascade header when no route satisfies the request and x_cascade has been disabled" do
|
74
|
+
mock_app {
|
75
|
+
disable :x_cascade
|
76
|
+
get('/foo') { }
|
77
|
+
}
|
78
|
+
get '/bar'
|
79
|
+
assert_equal 404, status
|
80
|
+
assert_equal nil, response.headers['X-Cascade']
|
81
|
+
end
|
82
|
+
|
83
|
+
|
73
84
|
it "allows using unicode" do
|
74
85
|
mock_app do
|
75
86
|
get('/föö') { }
|
@@ -100,6 +111,19 @@ class RoutingTest < Test::Unit::TestCase
|
|
100
111
|
assert_equal "<h1>Not Found</h1>", response.body
|
101
112
|
end
|
102
113
|
|
114
|
+
it "recalculates body length correctly for 404 response" do
|
115
|
+
mock_app {
|
116
|
+
get '/' do
|
117
|
+
@response["Content-Length"] = "30"
|
118
|
+
raise Sinatra::NotFound
|
119
|
+
end
|
120
|
+
}
|
121
|
+
|
122
|
+
get "/"
|
123
|
+
assert_equal "18", response["Content-Length"]
|
124
|
+
assert_equal 404, status
|
125
|
+
end
|
126
|
+
|
103
127
|
it 'matches empty PATH_INFO to "/" if no route is defined for ""' do
|
104
128
|
mock_app do
|
105
129
|
get '/' do
|
@@ -377,6 +401,30 @@ class RoutingTest < Test::Unit::TestCase
|
|
377
401
|
assert_equal 'well, alright', body
|
378
402
|
end
|
379
403
|
|
404
|
+
it "exposes params nested within arrays with indifferent hash" do
|
405
|
+
mock_app {
|
406
|
+
get '/testme' do
|
407
|
+
assert_equal 'baz', params['bar'][0]['foo']
|
408
|
+
assert_equal 'baz', params['bar'][0][:foo]
|
409
|
+
'well, alright'
|
410
|
+
end
|
411
|
+
}
|
412
|
+
get '/testme?bar[][foo]=baz'
|
413
|
+
assert_equal 'well, alright', body
|
414
|
+
end
|
415
|
+
|
416
|
+
it "supports arrays within params" do
|
417
|
+
mock_app {
|
418
|
+
get '/foo' do
|
419
|
+
assert_equal ['A', 'B'], params['bar']
|
420
|
+
'looks good'
|
421
|
+
end
|
422
|
+
}
|
423
|
+
get '/foo?bar[]=A&bar[]=B'
|
424
|
+
assert ok?
|
425
|
+
assert_equal 'looks good', body
|
426
|
+
end
|
427
|
+
|
380
428
|
it "supports deeply nested params" do
|
381
429
|
expected_params = {
|
382
430
|
"emacs" => {
|
@@ -746,6 +794,31 @@ class RoutingTest < Test::Unit::TestCase
|
|
746
794
|
assert !ok?
|
747
795
|
end
|
748
796
|
|
797
|
+
it "filters by current Content-Type" do
|
798
|
+
mock_app do
|
799
|
+
before('/txt') { content_type :txt }
|
800
|
+
get('*', :provides => :txt) { 'txt' }
|
801
|
+
|
802
|
+
before('/html') { content_type :html }
|
803
|
+
get('*', :provides => :html) { 'html' }
|
804
|
+
end
|
805
|
+
|
806
|
+
get '/', {}, { 'HTTP_ACCEPT' => '*/*' }
|
807
|
+
assert ok?
|
808
|
+
assert_equal 'text/plain;charset=utf-8', response.headers['Content-Type']
|
809
|
+
assert_body 'txt'
|
810
|
+
|
811
|
+
get '/txt', {}, { 'HTTP_ACCEPT' => 'text/plain' }
|
812
|
+
assert ok?
|
813
|
+
assert_equal 'text/plain;charset=utf-8', response.headers['Content-Type']
|
814
|
+
assert_body 'txt'
|
815
|
+
|
816
|
+
get '/', {}, { 'HTTP_ACCEPT' => 'text/html' }
|
817
|
+
assert ok?
|
818
|
+
assert_equal 'text/html;charset=utf-8', response.headers['Content-Type']
|
819
|
+
assert_body 'html'
|
820
|
+
end
|
821
|
+
|
749
822
|
it "allows multiple mime types for accept header" do
|
750
823
|
types = ['image/jpeg', 'image/pjpeg']
|
751
824
|
|
@@ -777,7 +850,7 @@ class RoutingTest < Test::Unit::TestCase
|
|
777
850
|
assert_equal 'default', body
|
778
851
|
end
|
779
852
|
|
780
|
-
it 'respects user agent
|
853
|
+
it 'respects user agent preferences for the content type' do
|
781
854
|
mock_app { get('/', :provides => [:png, :html]) { content_type }}
|
782
855
|
get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5,text/html;q=0.8' }
|
783
856
|
assert_body 'text/html;charset=utf-8'
|
@@ -832,6 +905,55 @@ class RoutingTest < Test::Unit::TestCase
|
|
832
905
|
assert_body 'text/html;charset=utf-8'
|
833
906
|
end
|
834
907
|
|
908
|
+
it 'supplies a default quality of 1.0' do
|
909
|
+
mock_app { get('/', :provides => [:png, :html]) { content_type }}
|
910
|
+
get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5, text/*' }
|
911
|
+
assert_body 'text/html;charset=utf-8'
|
912
|
+
end
|
913
|
+
|
914
|
+
it 'orders types with equal quality by parameter count' do
|
915
|
+
mock_app do
|
916
|
+
get('/', :provides => [:png, :jpg]) { content_type }
|
917
|
+
end
|
918
|
+
|
919
|
+
lo_png = 'image/png;q=0.5'
|
920
|
+
hi_png = 'image/png;q=0.5;profile=FOGRA40;gamma=0.8'
|
921
|
+
jpeg = 'image/jpeg;q=0.5;compress=0.25'
|
922
|
+
|
923
|
+
get '/', {}, { 'HTTP_ACCEPT' => "#{lo_png}, #{jpeg}" }
|
924
|
+
assert_body 'image/jpeg'
|
925
|
+
get '/', {}, { 'HTTP_ACCEPT' => "#{hi_png}, #{jpeg}" }
|
926
|
+
assert_body 'image/png'
|
927
|
+
end
|
928
|
+
|
929
|
+
it 'ignores the quality parameter when ordering by parameter count' do
|
930
|
+
mock_app do
|
931
|
+
get('/', :provides => [:png, :jpg]) { content_type }
|
932
|
+
end
|
933
|
+
|
934
|
+
lo_png = 'image/png'
|
935
|
+
hi_png = 'image/png;profile=FOGRA40;gamma=0.8'
|
936
|
+
jpeg = 'image/jpeg;q=1.0;compress=0.25'
|
937
|
+
|
938
|
+
get '/', {}, { 'HTTP_ACCEPT' => "#{jpeg}, #{lo_png}" }
|
939
|
+
assert_body 'image/jpeg'
|
940
|
+
get '/', {}, { 'HTTP_ACCEPT' => "#{jpeg}, #{hi_png}" }
|
941
|
+
assert_body 'image/png'
|
942
|
+
end
|
943
|
+
|
944
|
+
it 'properly handles quoted strings in parameters' do
|
945
|
+
mock_app do
|
946
|
+
get('/', :provides => [:png, :jpg]) { content_type }
|
947
|
+
end
|
948
|
+
|
949
|
+
get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5;profile=",image/jpeg,"' }
|
950
|
+
assert_body 'image/png'
|
951
|
+
get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5,image/jpeg;q=0;x=";q=1.0"' }
|
952
|
+
assert_body 'image/png'
|
953
|
+
get '/', {}, { 'HTTP_ACCEPT' => 'image/png;q=0.5,image/jpeg;q=0;x="\";q=1.0"' }
|
954
|
+
assert_body 'image/png'
|
955
|
+
end
|
956
|
+
|
835
957
|
it 'accepts both text/javascript and application/javascript for js' do
|
836
958
|
mock_app { get('/', :provides => :js) { content_type }}
|
837
959
|
get '/', {}, { 'HTTP_ACCEPT' => 'application/javascript' }
|
data/test/sass_test.rb
CHANGED
@@ -6,11 +6,11 @@ require 'sass'
|
|
6
6
|
|
7
7
|
class SassTest < Test::Unit::TestCase
|
8
8
|
def sass_app(options = {}, &block)
|
9
|
-
mock_app
|
9
|
+
mock_app do
|
10
10
|
set :views, File.dirname(__FILE__) + '/views'
|
11
11
|
set options
|
12
|
-
get
|
13
|
-
|
12
|
+
get('/', &block)
|
13
|
+
end
|
14
14
|
get '/'
|
15
15
|
end
|
16
16
|
|
@@ -36,9 +36,9 @@ class SassTest < Test::Unit::TestCase
|
|
36
36
|
end
|
37
37
|
|
38
38
|
it 'defaults allows setting content type globally' do
|
39
|
-
sass_app(:sass => { :content_type => 'html' })
|
39
|
+
sass_app(:sass => { :content_type => 'html' }) {
|
40
40
|
sass "#sass\n :background-color white\n"
|
41
|
-
|
41
|
+
}
|
42
42
|
assert ok?
|
43
43
|
assert_equal "text/html;charset=utf-8", response['Content-Type']
|
44
44
|
end
|
@@ -56,50 +56,50 @@ class SassTest < Test::Unit::TestCase
|
|
56
56
|
end
|
57
57
|
|
58
58
|
it "raises error if template not found" do
|
59
|
-
mock_app {
|
60
|
-
get('/') { sass :no_such_template }
|
61
|
-
}
|
59
|
+
mock_app { get('/') { sass :no_such_template } }
|
62
60
|
assert_raise(Errno::ENOENT) { get('/') }
|
63
61
|
end
|
64
62
|
|
65
63
|
it "passes SASS options to the Sass engine" do
|
66
|
-
sass_app
|
67
|
-
sass
|
64
|
+
sass_app do
|
65
|
+
sass(
|
66
|
+
"#sass\n :background-color white\n :color black\n",
|
68
67
|
:style => :compact
|
69
|
-
|
68
|
+
)
|
69
|
+
end
|
70
70
|
assert ok?
|
71
|
-
assert_equal
|
71
|
+
assert_equal("#sass { background-color: white; color: black; }\n", body)
|
72
72
|
end
|
73
73
|
|
74
74
|
it "passes default SASS options to the Sass engine" do
|
75
|
-
mock_app
|
75
|
+
mock_app do
|
76
76
|
set :sass, {:style => :compact} # default Sass style is :nested
|
77
|
-
get
|
78
|
-
|
79
|
-
end
|
80
|
-
}
|
77
|
+
get('/') { sass("#sass\n :background-color white\n :color black\n") }
|
78
|
+
end
|
81
79
|
get '/'
|
82
80
|
assert ok?
|
83
81
|
assert_equal "#sass { background-color: white; color: black; }\n", body
|
84
82
|
end
|
85
83
|
|
86
84
|
it "merges the default SASS options with the overrides" do
|
87
|
-
mock_app
|
85
|
+
mock_app do
|
88
86
|
# default Sass attribute_syntax is :normal (with : in front)
|
89
87
|
set :sass, {:style => :compact, :attribute_syntax => :alternate }
|
90
|
-
get
|
91
|
-
|
92
|
-
end
|
93
|
-
get '/raised' do
|
88
|
+
get('/') { sass("#sass\n background-color: white\n color: black\n") }
|
89
|
+
get('/raised') do
|
94
90
|
# retains global attribute_syntax settings
|
95
|
-
sass
|
91
|
+
sass(
|
92
|
+
"#sass\n :background-color white\n :color black\n",
|
96
93
|
:style => :expanded
|
94
|
+
)
|
97
95
|
end
|
98
|
-
get
|
99
|
-
sass
|
96
|
+
get('/expanded_normal') do
|
97
|
+
sass(
|
98
|
+
"#sass\n :background-color white\n :color black\n",
|
100
99
|
:style => :expanded, :attribute_syntax => :normal
|
100
|
+
)
|
101
101
|
end
|
102
|
-
|
102
|
+
end
|
103
103
|
get '/'
|
104
104
|
assert ok?
|
105
105
|
assert_equal "#sass { background-color: white; color: black; }\n", body
|
data/test/scss_test.rb
CHANGED
@@ -6,11 +6,11 @@ require 'sass'
|
|
6
6
|
|
7
7
|
class ScssTest < Test::Unit::TestCase
|
8
8
|
def scss_app(options = {}, &block)
|
9
|
-
mock_app
|
9
|
+
mock_app do
|
10
10
|
set :views, File.dirname(__FILE__) + '/views'
|
11
11
|
set options
|
12
|
-
get
|
13
|
-
|
12
|
+
get('/', &block)
|
13
|
+
end
|
14
14
|
get '/'
|
15
15
|
end
|
16
16
|
|
@@ -36,9 +36,9 @@ class ScssTest < Test::Unit::TestCase
|
|
36
36
|
end
|
37
37
|
|
38
38
|
it 'defaults allows setting content type globally' do
|
39
|
-
scss_app(:scss => { :content_type => 'html' })
|
39
|
+
scss_app(:scss => { :content_type => 'html' }) {
|
40
40
|
scss "#scss {\n background-color: white; }\n"
|
41
|
-
|
41
|
+
}
|
42
42
|
assert ok?
|
43
43
|
assert_equal "text/html;charset=utf-8", response['Content-Type']
|
44
44
|
end
|
@@ -56,28 +56,28 @@ class ScssTest < Test::Unit::TestCase
|
|
56
56
|
end
|
57
57
|
|
58
58
|
it "raises error if template not found" do
|
59
|
-
mock_app {
|
60
|
-
get('/') { scss :no_such_template }
|
61
|
-
}
|
59
|
+
mock_app { get('/') { scss(:no_such_template) } }
|
62
60
|
assert_raise(Errno::ENOENT) { get('/') }
|
63
61
|
end
|
64
62
|
|
65
63
|
it "passes scss options to the scss engine" do
|
66
|
-
scss_app
|
67
|
-
scss
|
64
|
+
scss_app do
|
65
|
+
scss(
|
66
|
+
"#scss {\n background-color: white;\n color: black\n}",
|
68
67
|
:style => :compact
|
69
|
-
|
68
|
+
)
|
69
|
+
end
|
70
70
|
assert ok?
|
71
71
|
assert_equal "#scss { background-color: white; color: black; }\n", body
|
72
72
|
end
|
73
73
|
|
74
74
|
it "passes default scss options to the scss engine" do
|
75
|
-
mock_app
|
75
|
+
mock_app do
|
76
76
|
set :scss, {:style => :compact} # default scss style is :nested
|
77
|
-
get
|
78
|
-
scss
|
79
|
-
|
80
|
-
|
77
|
+
get('/') {
|
78
|
+
scss("#scss {\n background-color: white;\n color: black;\n}")
|
79
|
+
}
|
80
|
+
end
|
81
81
|
get '/'
|
82
82
|
assert ok?
|
83
83
|
assert_equal "#scss { background-color: white; color: black; }\n", body
|
data/test/server_test.rb
CHANGED
data/test/settings_test.rb
CHANGED
@@ -422,9 +422,20 @@ class SettingsTest < Test::Unit::TestCase
|
|
422
422
|
end
|
423
423
|
|
424
424
|
describe 'server' do
|
425
|
-
it '
|
426
|
-
|
427
|
-
|
425
|
+
it 'includes webrick' do
|
426
|
+
assert @base.server.include?('webrick')
|
427
|
+
assert @application.server.include?('webrick')
|
428
|
+
end
|
429
|
+
|
430
|
+
it 'includes puma' do
|
431
|
+
assert @base.server.include?('puma')
|
432
|
+
assert @application.server.include?('puma')
|
433
|
+
end
|
434
|
+
|
435
|
+
it 'includes thin' do
|
436
|
+
next if RUBY_ENGINE == 'jruby'
|
437
|
+
assert @base.server.include?('thin')
|
438
|
+
assert @application.server.include?('thin')
|
428
439
|
end
|
429
440
|
end
|
430
441
|
|
@@ -435,7 +446,7 @@ class SettingsTest < Test::Unit::TestCase
|
|
435
446
|
end
|
436
447
|
|
437
448
|
it 'defaults to the file subclassing' do
|
438
|
-
assert_equal __FILE__, Sinatra.new.app_file
|
449
|
+
assert_equal File.expand_path(__FILE__), Sinatra.new.app_file
|
439
450
|
end
|
440
451
|
end
|
441
452
|
|
@@ -484,6 +495,18 @@ class SettingsTest < Test::Unit::TestCase
|
|
484
495
|
end
|
485
496
|
end
|
486
497
|
|
498
|
+
describe 'public_dir' do
|
499
|
+
it 'is an alias for public_folder' do
|
500
|
+
@base.public_dir = File.dirname(__FILE__)
|
501
|
+
assert_equal File.dirname(__FILE__), @base.public_dir
|
502
|
+
assert_equal @base.public_folder, @base.public_dir
|
503
|
+
|
504
|
+
@application.public_dir = File.dirname(__FILE__)
|
505
|
+
assert_equal File.dirname(__FILE__), @application.public_dir
|
506
|
+
assert_equal @application.public_folder, @application.public_dir
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
487
510
|
describe 'lock' do
|
488
511
|
it 'is disabled by default' do
|
489
512
|
assert ! @base.lock?
|
@@ -534,5 +557,26 @@ class SettingsTest < Test::Unit::TestCase
|
|
534
557
|
assert !MiddlewareTracker.used.include?(Rack::Protection::PathTraversal)
|
535
558
|
end
|
536
559
|
end
|
560
|
+
|
561
|
+
it 'sets up RemoteToken if sessions are enabled' do
|
562
|
+
MiddlewareTracker.track do
|
563
|
+
Sinatra.new { enable :sessions }.new
|
564
|
+
assert_include MiddlewareTracker.used, Rack::Protection::RemoteToken
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
it 'does not set up RemoteToken if sessions are disabled' do
|
569
|
+
MiddlewareTracker.track do
|
570
|
+
Sinatra.new.new
|
571
|
+
assert !MiddlewareTracker.used.include?(Rack::Protection::RemoteToken)
|
572
|
+
end
|
573
|
+
end
|
574
|
+
|
575
|
+
it 'sets up RemoteToken if it is configured to' do
|
576
|
+
MiddlewareTracker.track do
|
577
|
+
Sinatra.new { set :protection, :session => true }.new
|
578
|
+
assert_include MiddlewareTracker.used, Rack::Protection::RemoteToken
|
579
|
+
end
|
580
|
+
end
|
537
581
|
end
|
538
582
|
end
|