sinatra-base 1.0 → 1.4.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 (101) hide show
  1. data/.yardopts +4 -0
  2. data/AUTHORS +15 -0
  3. data/CHANGES +524 -1
  4. data/Gemfile +82 -0
  5. data/LICENSE +1 -1
  6. data/README.de.rdoc +2093 -0
  7. data/README.es.rdoc +2091 -0
  8. data/README.fr.rdoc +2116 -0
  9. data/README.hu.rdoc +607 -0
  10. data/README.jp.rdoc +514 -23
  11. data/README.pt-br.rdoc +647 -0
  12. data/README.pt-pt.rdoc +646 -0
  13. data/README.rdoc +1580 -205
  14. data/README.ru.rdoc +2015 -0
  15. data/README.zh.rdoc +1816 -0
  16. data/Rakefile +110 -44
  17. data/examples/chat.rb +61 -0
  18. data/examples/simple.rb +3 -0
  19. data/examples/stream.ru +26 -0
  20. data/lib/sinatra.rb +0 -3
  21. data/lib/sinatra/base.rb +923 -393
  22. data/lib/sinatra/main.rb +9 -7
  23. data/lib/sinatra/showexceptions.rb +37 -4
  24. data/lib/sinatra/version.rb +3 -0
  25. data/sinatra-base.gemspec +15 -91
  26. data/test/base_test.rb +2 -2
  27. data/test/builder_test.rb +32 -2
  28. data/test/coffee_test.rb +92 -0
  29. data/test/contest.rb +62 -28
  30. data/test/creole_test.rb +65 -0
  31. data/test/delegator_test.rb +162 -0
  32. data/test/encoding_test.rb +20 -0
  33. data/test/erb_test.rb +25 -2
  34. data/test/extensions_test.rb +1 -1
  35. data/test/filter_test.rb +226 -8
  36. data/test/haml_test.rb +8 -2
  37. data/test/helper.rb +47 -0
  38. data/test/helpers_test.rb +1287 -80
  39. data/test/integration/app.rb +62 -0
  40. data/test/integration_helper.rb +208 -0
  41. data/test/integration_test.rb +82 -0
  42. data/test/less_test.rb +36 -6
  43. data/test/liquid_test.rb +59 -0
  44. data/test/mapped_error_test.rb +84 -7
  45. data/test/markaby_test.rb +80 -0
  46. data/test/markdown_test.rb +81 -0
  47. data/test/middleware_test.rb +1 -1
  48. data/test/nokogiri_test.rb +69 -0
  49. data/test/rack_test.rb +45 -0
  50. data/test/radius_test.rb +59 -0
  51. data/test/rdoc_test.rb +66 -0
  52. data/test/readme_test.rb +136 -0
  53. data/test/request_test.rb +13 -1
  54. data/test/response_test.rb +21 -2
  55. data/test/result_test.rb +5 -5
  56. data/test/route_added_hook_test.rb +1 -1
  57. data/test/routing_test.rb +328 -13
  58. data/test/sass_test.rb +48 -18
  59. data/test/scss_test.rb +88 -0
  60. data/test/server_test.rb +4 -3
  61. data/test/settings_test.rb +191 -21
  62. data/test/sinatra_test.rb +5 -1
  63. data/test/slim_test.rb +88 -0
  64. data/test/static_test.rb +89 -5
  65. data/test/streaming_test.rb +140 -0
  66. data/test/templates_test.rb +143 -4
  67. data/test/textile_test.rb +65 -0
  68. data/test/views/a/in_a.str +1 -0
  69. data/test/views/ascii.erb +2 -0
  70. data/test/views/b/in_b.str +1 -0
  71. data/test/views/calc.html.erb +1 -0
  72. data/test/views/explicitly_nested.str +1 -0
  73. data/test/views/hello.coffee +1 -0
  74. data/test/views/hello.creole +1 -0
  75. data/test/views/hello.liquid +1 -0
  76. data/test/views/hello.mab +1 -0
  77. data/test/views/hello.md +1 -0
  78. data/test/views/hello.nokogiri +1 -0
  79. data/test/views/hello.radius +1 -0
  80. data/test/views/hello.rdoc +1 -0
  81. data/test/views/hello.sass +1 -1
  82. data/test/views/hello.scss +3 -0
  83. data/test/views/hello.slim +1 -0
  84. data/test/views/hello.str +1 -0
  85. data/test/views/hello.textile +1 -0
  86. data/test/views/hello.yajl +1 -0
  87. data/test/views/layout2.liquid +2 -0
  88. data/test/views/layout2.mab +2 -0
  89. data/test/views/layout2.nokogiri +3 -0
  90. data/test/views/layout2.radius +2 -0
  91. data/test/views/layout2.slim +3 -0
  92. data/test/views/layout2.str +2 -0
  93. data/test/views/nested.str +1 -0
  94. data/test/views/utf8.erb +2 -0
  95. data/test/yajl_test.rb +80 -0
  96. metadata +126 -91
  97. data/lib/sinatra/tilt.rb +0 -746
  98. data/test/erubis_test.rb +0 -82
  99. data/test/views/error.erubis +0 -3
  100. data/test/views/hello.erubis +0 -1
  101. data/test/views/layout2.erubis +0 -2
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/helper'
1
+ require File.expand_path('../helper', __FILE__)
2
2
 
3
3
  class FooError < RuntimeError
4
4
  end
@@ -6,6 +6,15 @@ end
6
6
  class FooNotFound < Sinatra::NotFound
7
7
  end
8
8
 
9
+ class FooSpecialError < RuntimeError
10
+ def http_status; 501 end
11
+ end
12
+
13
+ class FooStatusOutOfRangeError < RuntimeError
14
+ def code; 4000 end
15
+ end
16
+
17
+
9
18
  class MappedErrorTest < Test::Unit::TestCase
10
19
  def test_default
11
20
  assert true
@@ -25,6 +34,15 @@ class MappedErrorTest < Test::Unit::TestCase
25
34
  assert_equal 'Foo!', body
26
35
  end
27
36
 
37
+ it 'passes the exception object to the error handler' do
38
+ mock_app do
39
+ set :raise_errors, false
40
+ error(FooError) { |e| assert_equal(FooError, e.class) }
41
+ get('/') { raise FooError }
42
+ end
43
+ get('/')
44
+ end
45
+
28
46
  it 'uses the Exception handler if no matching handler found' do
29
47
  mock_app {
30
48
  set :raise_errors, false
@@ -39,6 +57,36 @@ class MappedErrorTest < Test::Unit::TestCase
39
57
  assert_equal 'Exception!', body
40
58
  end
41
59
 
60
+ it 'walks down inheritance chain for errors' do
61
+ mock_app {
62
+ set :raise_errors, false
63
+ error(RuntimeError) { 'Exception!' }
64
+ get '/' do
65
+ raise FooError
66
+ end
67
+ }
68
+
69
+ get '/'
70
+ assert_equal 500, status
71
+ assert_equal 'Exception!', body
72
+ end
73
+
74
+ it 'favors subclass handler over superclass handler if available' do
75
+ mock_app {
76
+ set :raise_errors, false
77
+ error(Exception) { 'Exception!' }
78
+ error(FooError) { 'FooError!' }
79
+ error(RuntimeError) { 'Exception!' }
80
+ get '/' do
81
+ raise FooError
82
+ end
83
+ }
84
+
85
+ get '/'
86
+ assert_equal 500, status
87
+ assert_equal 'FooError!', body
88
+ end
89
+
42
90
  it "sets env['sinatra.error'] to the rescued exception" do
43
91
  mock_app {
44
92
  set :raise_errors, false
@@ -78,12 +126,7 @@ class MappedErrorTest < Test::Unit::TestCase
78
126
  end
79
127
 
80
128
  it "never raises Sinatra::NotFound beyond the application" do
81
- mock_app {
82
- set :raise_errors, true
83
- get '/' do
84
- raise Sinatra::NotFound
85
- end
86
- }
129
+ mock_app(Sinatra::Application) { get('/') { raise Sinatra::NotFound }}
87
130
  assert_nothing_raised { get '/' }
88
131
  assert_equal 404, status
89
132
  end
@@ -143,6 +186,27 @@ class MappedErrorTest < Test::Unit::TestCase
143
186
  get '/'
144
187
  assert_equal 'subclass', body
145
188
  end
189
+
190
+ it 'honors Exception#http_status if present' do
191
+ mock_app do
192
+ set :raise_errors, false
193
+ error(501) { 'Foo!' }
194
+ get('/') { raise FooSpecialError }
195
+ end
196
+ get '/'
197
+ assert_equal 501, status
198
+ assert_equal 'Foo!', body
199
+ end
200
+
201
+ it 'does not rely on Exception#code for invalid codes' do
202
+ mock_app do
203
+ set :raise_errors, false
204
+ get('/') { raise FooStatusOutOfRangeError }
205
+ end
206
+ get '/'
207
+ assert_equal 500, status
208
+ end
209
+
146
210
  end
147
211
 
148
212
  describe 'Custom Error Pages' do
@@ -172,6 +236,19 @@ class MappedErrorTest < Test::Unit::TestCase
172
236
  assert_equal 'Error: 507', body
173
237
  end
174
238
 
239
+ it 'allows passing more than one range' do
240
+ mock_app {
241
+ set :raise_errors, false
242
+ error(409..411, 503..509) { "Error: #{response.status}" }
243
+ get '/' do
244
+ [507, {}, 'A very special error']
245
+ end
246
+ }
247
+ get '/'
248
+ assert_equal 507, status
249
+ assert_equal 'Error: 507', body
250
+ end
251
+
175
252
  class FooError < RuntimeError
176
253
  end
177
254
 
@@ -0,0 +1,80 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ begin
4
+ require 'markaby'
5
+
6
+ class MarkabyTest < Test::Unit::TestCase
7
+ def markaby_app(&block)
8
+ mock_app do
9
+ set :views, File.dirname(__FILE__) + '/views'
10
+ get '/', &block
11
+ end
12
+ get '/'
13
+ end
14
+
15
+ it 'renders inline markaby strings' do
16
+ markaby_app { markaby 'h1 "Hiya"' }
17
+ assert ok?
18
+ assert_equal "<h1>Hiya</h1>", body
19
+ end
20
+
21
+ it 'renders .markaby files in views path' do
22
+ markaby_app { markaby :hello }
23
+ assert ok?
24
+ assert_equal "<h1>Hello From Markaby</h1>", body
25
+ end
26
+
27
+ it "renders with inline layouts" do
28
+ mock_app do
29
+ layout { 'h1 { text "THIS. IS. "; yield }' }
30
+ get('/') { markaby 'em "SPARTA"' }
31
+ end
32
+ get '/'
33
+ assert ok?
34
+ assert_equal "<h1>THIS. IS. <em>SPARTA</em></h1>", body
35
+ end
36
+
37
+ it "renders with file layouts" do
38
+ markaby_app { markaby 'text "Hello World"', :layout => :layout2 }
39
+ assert ok?
40
+ assert_equal "<h1>Markaby Layout!</h1><p>Hello World</p>", body
41
+ end
42
+
43
+ it 'renders inline markaby blocks' do
44
+ markaby_app { markaby { h1 'Hiya' } }
45
+ assert ok?
46
+ assert_equal "<h1>Hiya</h1>", body
47
+ end
48
+
49
+ it 'renders inline markaby blocks with inline layouts' do
50
+ markaby_app do
51
+ settings.layout { 'h1 { text "THIS. IS. "; yield }' }
52
+ markaby { em 'SPARTA' }
53
+ end
54
+ assert ok?
55
+ assert_equal "<h1>THIS. IS. <em>SPARTA</em></h1>", body
56
+ end
57
+
58
+ it 'renders inline markaby blocks with file layouts' do
59
+ markaby_app { markaby(:layout => :layout2) { text "Hello World" } }
60
+ assert ok?
61
+ assert_equal "<h1>Markaby Layout!</h1><p>Hello World</p>", body
62
+ end
63
+
64
+ it "raises error if template not found" do
65
+ mock_app { get('/') { markaby :no_such_template } }
66
+ assert_raise(Errno::ENOENT) { get('/') }
67
+ end
68
+
69
+ it "allows passing locals" do
70
+ markaby_app do
71
+ markaby 'text value', :locals => { :value => 'foo' }
72
+ end
73
+ assert ok?
74
+ assert_equal 'foo', body
75
+ end
76
+ end
77
+
78
+ rescue LoadError
79
+ warn "#{$!.to_s}: skipping markaby tests"
80
+ end
@@ -0,0 +1,81 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ MarkdownTest = proc do
4
+ def markdown_app(&block)
5
+ mock_app do
6
+ set :views, File.dirname(__FILE__) + '/views'
7
+ get '/', &block
8
+ end
9
+ get '/'
10
+ end
11
+
12
+ def setup
13
+ Tilt.prefer engine, 'markdown', 'mkd', 'md'
14
+ super
15
+ end
16
+
17
+ it 'uses the correct engine' do
18
+ assert_equal engine, Tilt[:md]
19
+ assert_equal engine, Tilt[:mkd]
20
+ assert_equal engine, Tilt[:markdown]
21
+ end
22
+
23
+ it 'renders inline markdown strings' do
24
+ markdown_app { markdown '# Hiya' }
25
+ assert ok?
26
+ assert_like "<h1>Hiya</h1>\n", body
27
+ end
28
+
29
+ it 'renders .markdown files in views path' do
30
+ markdown_app { markdown :hello }
31
+ assert ok?
32
+ assert_like "<h1>Hello From Markdown</h1>", body
33
+ end
34
+
35
+ it "raises error if template not found" do
36
+ mock_app { get('/') { markdown :no_such_template } }
37
+ assert_raise(Errno::ENOENT) { get('/') }
38
+ end
39
+
40
+ it "renders with inline layouts" do
41
+ mock_app do
42
+ layout { 'THIS. IS. #{yield.upcase}!' }
43
+ get('/') { markdown 'Sparta', :layout_engine => :str }
44
+ end
45
+ get '/'
46
+ assert ok?
47
+ assert_like 'THIS. IS. <P>SPARTA</P>!', body
48
+ end
49
+
50
+ it "renders with file layouts" do
51
+ markdown_app { markdown 'Hello World', :layout => :layout2, :layout_engine => :erb }
52
+ assert ok?
53
+ assert_body "ERB Layout!\n<p>Hello World</p>"
54
+ end
55
+
56
+ it "can be used in a nested fashion for partials and whatnot" do
57
+ mock_app do
58
+ template(:inner) { "hi" }
59
+ template(:outer) { "<outer><%= markdown :inner %></outer>" }
60
+ get '/' do
61
+ erb :outer
62
+ end
63
+ end
64
+
65
+ get '/'
66
+ assert ok?
67
+ assert_like '<outer><p>hi</p></outer>', body
68
+ end
69
+ end
70
+
71
+ # Will generate RDiscountTest, KramdownTest, etc.
72
+ Tilt.mappings['md'].each do |t|
73
+ begin
74
+ t.new { "" }
75
+ klass = Class.new(Test::Unit::TestCase) { define_method(:engine) { t }}
76
+ klass.class_eval(&MarkdownTest)
77
+ Object.const_set t.name[/[^:]+(?=Template$)/] << "Test", klass
78
+ rescue LoadError
79
+ warn "#{$!}: skipping markdown tests with #{t}"
80
+ end
81
+ end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/helper'
1
+ require File.expand_path('../helper', __FILE__)
2
2
 
3
3
  class MiddlewareTest < Test::Unit::TestCase
4
4
  setup do
@@ -0,0 +1,69 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ begin
4
+ require 'nokogiri'
5
+
6
+ class NokogiriTest < Test::Unit::TestCase
7
+ def nokogiri_app(&block)
8
+ mock_app do
9
+ set :views, File.dirname(__FILE__) + '/views'
10
+ get '/', &block
11
+ end
12
+ get '/'
13
+ end
14
+
15
+ it 'renders inline Nokogiri strings' do
16
+ nokogiri_app { nokogiri 'xml' }
17
+ assert ok?
18
+ assert_body %(<?xml version="1.0"?>\n)
19
+ end
20
+
21
+ it 'renders inline blocks' do
22
+ nokogiri_app do
23
+ @name = "Frank & Mary"
24
+ nokogiri do |xml|
25
+ xml.couple @name
26
+ end
27
+ end
28
+ assert ok?
29
+ assert_body %(<?xml version="1.0"?>\n<couple>Frank &amp; Mary</couple>\n)
30
+ end
31
+
32
+ it 'renders .nokogiri files in views path' do
33
+ nokogiri_app do
34
+ @name = "Blue"
35
+ nokogiri :hello
36
+ end
37
+ assert ok?
38
+ assert_body "<?xml version=\"1.0\"?>\n<exclaim>You're my boy, Blue!</exclaim>\n"
39
+ end
40
+
41
+ it "renders with inline layouts" do
42
+ next if Tilt::VERSION <= "1.1"
43
+ mock_app do
44
+ layout { %(xml.layout { xml << yield }) }
45
+ get('/') { nokogiri %(xml.em 'Hello World') }
46
+ end
47
+ get '/'
48
+ assert ok?
49
+ assert_body %(<?xml version="1.0"?>\n<layout>\n <em>Hello World</em>\n</layout>\n)
50
+ end
51
+
52
+ it "renders with file layouts" do
53
+ next if Tilt::VERSION <= "1.1"
54
+ nokogiri_app do
55
+ nokogiri %(xml.em 'Hello World'), :layout => :layout2
56
+ end
57
+ assert ok?
58
+ assert_body %(<?xml version="1.0"?>\n<layout>\n <em>Hello World</em>\n</layout>\n)
59
+ end
60
+
61
+ it "raises error if template not found" do
62
+ mock_app { get('/') { nokogiri :no_such_template } }
63
+ assert_raise(Errno::ENOENT) { get('/') }
64
+ end
65
+ end
66
+
67
+ rescue LoadError
68
+ warn "#{$!.to_s}: skipping nokogiri tests"
69
+ end
@@ -0,0 +1,45 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+ require 'rack'
3
+
4
+ class RackTest < Test::Unit::TestCase
5
+ setup do
6
+ @foo = Sinatra.new { get('/foo') { 'foo' }}
7
+ @bar = Sinatra.new { get('/bar') { 'bar' }}
8
+ end
9
+
10
+ def build(*middleware)
11
+ endpoint = middleware.pop
12
+ @app = Rack::Builder.app do
13
+ middleware.each { |m| use m }
14
+ run endpoint
15
+ end
16
+ end
17
+
18
+ def check(*middleware)
19
+ build(*middleware)
20
+ assert get('/foo').ok?
21
+ assert_body 'foo'
22
+ assert get('/bar').ok?
23
+ assert_body 'bar'
24
+ end
25
+
26
+ it 'works as middleware in front of Rack::Lock, with lock enabled' do
27
+ @foo.enable :lock
28
+ check(@foo, Rack::Lock, @bar)
29
+ end
30
+
31
+ it 'works as middleware behind Rack::Lock, with lock enabled' do
32
+ @foo.enable :lock
33
+ check(Rack::Lock, @foo, @bar)
34
+ end
35
+
36
+ it 'works as middleware in front of Rack::Lock, with lock disabled' do
37
+ @foo.disable :lock
38
+ check(@foo, Rack::Lock, @bar)
39
+ end
40
+
41
+ it 'works as middleware behind Rack::Lock, with lock disabled' do
42
+ @foo.disable :lock
43
+ check(Rack::Lock, @foo, @bar)
44
+ end
45
+ end
@@ -0,0 +1,59 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ begin
4
+ require 'radius'
5
+
6
+ class RadiusTest < Test::Unit::TestCase
7
+ def radius_app(&block)
8
+ mock_app do
9
+ set :views, File.dirname(__FILE__) + '/views'
10
+ get '/', &block
11
+ end
12
+ get '/'
13
+ end
14
+
15
+ it 'renders inline radius strings' do
16
+ radius_app { radius '<h1>Hiya</h1>' }
17
+ assert ok?
18
+ assert_equal "<h1>Hiya</h1>", body
19
+ end
20
+
21
+ it 'renders .radius files in views path' do
22
+ radius_app { radius :hello }
23
+ assert ok?
24
+ assert_equal "<h1>Hello From Radius</h1>\n", body
25
+ end
26
+
27
+ it "renders with inline layouts" do
28
+ mock_app do
29
+ layout { "<h1>THIS. IS. <r:yield /></h1>" }
30
+ get('/') { radius '<EM>SPARTA</EM>' }
31
+ end
32
+ get '/'
33
+ assert ok?
34
+ assert_equal "<h1>THIS. IS. <EM>SPARTA</EM></h1>", body
35
+ end
36
+
37
+ it "renders with file layouts" do
38
+ radius_app { radius 'Hello World', :layout => :layout2 }
39
+ assert ok?
40
+ assert_equal "<h1>Radius Layout!</h1>\n<p>Hello World</p>\n", body
41
+ end
42
+
43
+ it "raises error if template not found" do
44
+ mock_app { get('/') { radius :no_such_template } }
45
+ assert_raise(Errno::ENOENT) { get('/') }
46
+ end
47
+
48
+ it "allows passing locals" do
49
+ radius_app do
50
+ radius '<r:value />', :locals => { :value => 'foo' }
51
+ end
52
+ assert ok?
53
+ assert_equal 'foo', body
54
+ end
55
+ end
56
+
57
+ rescue LoadError
58
+ warn "#{$!.to_s}: skipping radius tests"
59
+ end