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.

Files changed (71) hide show
  1. data/CHANGES +96 -22
  2. data/Gemfile +11 -3
  3. data/README.de.md +2590 -0
  4. data/README.es.rdoc +66 -38
  5. data/README.fr.md +2630 -0
  6. data/README.hu.rdoc +3 -2
  7. data/README.jp.rdoc +16 -3
  8. data/README.ko.rdoc +11 -5
  9. data/README.md +2699 -0
  10. data/README.pt-br.rdoc +152 -21
  11. data/README.pt-pt.rdoc +3 -2
  12. data/README.ru.md +2724 -0
  13. data/README.zh.rdoc +3 -3
  14. data/Rakefile +3 -4
  15. data/examples/chat.rb +3 -3
  16. data/lib/sinatra/base.rb +433 -247
  17. data/lib/sinatra/main.rb +4 -2
  18. data/lib/sinatra/showexceptions.rb +6 -1
  19. data/lib/sinatra/version.rb +1 -1
  20. data/test/base_test.rb +21 -9
  21. data/test/builder_test.rb +15 -19
  22. data/test/coffee_test.rb +4 -6
  23. data/test/compile_test.rb +154 -0
  24. data/test/contest.rb +4 -6
  25. data/test/creole_test.rb +5 -5
  26. data/test/delegator_test.rb +1 -3
  27. data/test/erb_test.rb +32 -20
  28. data/test/extensions_test.rb +1 -3
  29. data/test/filter_test.rb +65 -56
  30. data/test/haml_test.rb +34 -26
  31. data/test/helpers_test.rb +331 -221
  32. data/test/integration_helper.rb +8 -0
  33. data/test/integration_test.rb +3 -1
  34. data/test/less_test.rb +10 -8
  35. data/test/liquid_test.rb +22 -4
  36. data/test/mapped_error_test.rb +122 -96
  37. data/test/markaby_test.rb +5 -5
  38. data/test/markdown_test.rb +5 -5
  39. data/test/middleware_test.rb +3 -3
  40. data/test/nokogiri_test.rb +4 -6
  41. data/test/rabl_test.rb +89 -0
  42. data/test/radius_test.rb +4 -4
  43. data/test/rdoc_test.rb +7 -7
  44. data/test/readme_test.rb +14 -30
  45. data/test/request_test.rb +15 -0
  46. data/test/response_test.rb +3 -4
  47. data/test/result_test.rb +11 -33
  48. data/test/route_added_hook_test.rb +10 -10
  49. data/test/routing_test.rb +123 -1
  50. data/test/sass_test.rb +26 -26
  51. data/test/scss_test.rb +16 -16
  52. data/test/server_test.rb +2 -2
  53. data/test/settings_test.rb +48 -4
  54. data/test/sinatra_test.rb +2 -7
  55. data/test/slim_test.rb +37 -23
  56. data/test/static_test.rb +56 -15
  57. data/test/streaming_test.rb +11 -2
  58. data/test/templates_test.rb +117 -45
  59. data/test/textile_test.rb +9 -9
  60. data/test/views/hello.rabl +2 -0
  61. data/test/views/hello.wlang +1 -0
  62. data/test/views/hello.yajl +1 -0
  63. data/test/views/layout2.rabl +3 -0
  64. data/test/views/layout2.wlang +2 -0
  65. data/test/wlang_test.rb +87 -0
  66. data/test/yajl_test.rb +86 -0
  67. metadata +27 -17
  68. data/README.de.rdoc +0 -2097
  69. data/README.fr.rdoc +0 -2036
  70. data/README.rdoc +0 -2017
  71. 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
@@ -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 prefferences for the content type' do
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' }
@@ -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 '/', &block
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' }) do
39
+ sass_app(:sass => { :content_type => 'html' }) {
40
40
  sass "#sass\n :background-color white\n"
41
- end
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 "#sass\n :background-color white\n :color black\n",
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 "#sass { background-color: white; color: black; }\n", body
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 '/' do
78
- sass "#sass\n :background-color white\n :color black\n"
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 '/' do
91
- sass "#sass\n background-color: white\n color: black\n"
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 "#sass\n :background-color white\n :color black\n",
91
+ sass(
92
+ "#sass\n :background-color white\n :color black\n",
96
93
  :style => :expanded
94
+ )
97
95
  end
98
- get '/expanded_normal' do
99
- sass "#sass\n :background-color white\n :color black\n",
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
@@ -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 '/', &block
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' }) do
39
+ scss_app(:scss => { :content_type => 'html' }) {
40
40
  scss "#scss {\n background-color: white; }\n"
41
- end
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 "#scss {\n background-color: white;\n color: black\n}",
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 '/' do
78
- scss "#scss {\n background-color: white;\n color: black;\n}"
79
- end
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
@@ -21,11 +21,11 @@ end
21
21
 
22
22
  class ServerTest < Test::Unit::TestCase
23
23
  setup do
24
- mock_app {
24
+ mock_app do
25
25
  set :server, 'mock'
26
26
  set :bind, 'foo.local'
27
27
  set :port, 9001
28
- }
28
+ end
29
29
  $stderr = StringIO.new
30
30
  end
31
31
 
@@ -422,9 +422,20 @@ class SettingsTest < Test::Unit::TestCase
422
422
  end
423
423
 
424
424
  describe 'server' do
425
- it 'is one of thin, mongrel, webrick' do
426
- assert_equal %w[thin mongrel webrick], @base.server
427
- assert_equal %w[thin mongrel webrick], @application.server
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