sinatra 0.3.3 → 0.9.0

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 (82) hide show
  1. data/AUTHORS +40 -0
  2. data/CHANGES +189 -0
  3. data/README.rdoc +146 -117
  4. data/Rakefile +33 -10
  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 +16 -3
  11. data/compat/filter_test.rb +30 -0
  12. data/compat/haml_test.rb +233 -0
  13. data/compat/helper.rb +30 -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.rb +6 -1484
  40. data/lib/sinatra/base.rb +838 -0
  41. data/lib/sinatra/compat.rb +239 -0
  42. data/{images → lib/sinatra/images}/404.png +0 -0
  43. data/{images → lib/sinatra/images}/500.png +0 -0
  44. data/lib/sinatra/main.rb +48 -0
  45. data/lib/sinatra/test.rb +114 -0
  46. data/lib/sinatra/test/bacon.rb +17 -0
  47. data/lib/sinatra/test/rspec.rb +7 -8
  48. data/lib/sinatra/test/spec.rb +3 -4
  49. data/lib/sinatra/test/unit.rb +3 -5
  50. data/sinatra.gemspec +68 -35
  51. data/test/base_test.rb +68 -0
  52. data/test/builder_test.rb +50 -87
  53. data/test/data/reload_app_file.rb +3 -0
  54. data/test/erb_test.rb +38 -124
  55. data/test/filter_test.rb +27 -22
  56. data/test/haml_test.rb +51 -216
  57. data/test/helper.rb +22 -6
  58. data/test/helpers_test.rb +361 -0
  59. data/test/mapped_error_test.rb +137 -49
  60. data/test/middleware_test.rb +58 -0
  61. data/test/options_test.rb +97 -0
  62. data/test/reload_test.rb +61 -0
  63. data/test/request_test.rb +18 -0
  64. data/test/result_test.rb +88 -0
  65. data/test/routing_test.rb +391 -0
  66. data/test/sass_test.rb +27 -48
  67. data/test/sinatra_test.rb +13 -0
  68. data/test/static_test.rb +57 -0
  69. data/test/templates_test.rb +88 -0
  70. data/test/views/hello.builder +1 -0
  71. data/test/views/hello.erb +1 -0
  72. data/test/views/hello.haml +1 -0
  73. data/test/views/hello.sass +2 -0
  74. data/test/views/hello.test +1 -0
  75. data/test/views/layout2.builder +3 -0
  76. data/test/views/layout2.erb +2 -0
  77. data/test/views/layout2.haml +2 -0
  78. data/test/views/layout2.test +1 -0
  79. metadata +80 -48
  80. data/ChangeLog +0 -96
  81. data/lib/sinatra/test/methods.rb +0 -76
  82. data/test/event_context_test.rb +0 -15
@@ -1,72 +1,160 @@
1
1
  require File.dirname(__FILE__) + '/helper'
2
2
 
3
- class FooError < RuntimeError; end
4
-
5
- context "Mapped errors" do
6
-
7
- setup do
8
- Sinatra.application = nil
9
- Sinatra.application.options.raise_errors = false
3
+ describe 'Exception Mappings' do
4
+ class FooError < RuntimeError
10
5
  end
11
6
 
12
- specify "are rescued and run in context" do
13
-
14
- error FooError do
15
- 'MAPPED ERROR!'
16
- end
17
-
18
- get '/' do
19
- raise FooError
20
- end
21
-
22
- get_it '/'
23
-
24
- should.be.server_error
25
- body.should.equal 'MAPPED ERROR!'
26
-
7
+ it 'invokes handlers registered with ::error when raised' do
8
+ mock_app {
9
+ set :raise_errors, false
10
+ error(FooError) { 'Foo!' }
11
+ get '/' do
12
+ raise FooError
13
+ end
14
+ }
15
+ get '/'
16
+ assert_equal 500, status
17
+ assert_equal 'Foo!', body
27
18
  end
28
19
 
29
- specify "renders empty if no each method on result" do
20
+ it 'uses the Exception handler if no matching handler found' do
21
+ mock_app {
22
+ set :raise_errors, false
23
+ error(Exception) { 'Exception!' }
24
+ get '/' do
25
+ raise FooError
26
+ end
27
+ }
28
+ get '/'
29
+ assert_equal 500, status
30
+ assert_equal 'Exception!', body
31
+ end
30
32
 
31
- error FooError do
32
- nil
33
- end
33
+ it "sets env['sinatra.error'] to the rescued exception" do
34
+ mock_app {
35
+ set :raise_errors, false
36
+ error(FooError) {
37
+ assert env.include?('sinatra.error')
38
+ assert env['sinatra.error'].kind_of?(FooError)
39
+ 'looks good'
40
+ }
41
+ get '/' do
42
+ raise FooError
43
+ end
44
+ }
45
+ get '/'
46
+ assert_equal 'looks good', body
47
+ end
34
48
 
35
- get '/' do
36
- raise FooError
37
- end
49
+ it 'dumps errors to rack.errors when dump_errors is enabled' do
50
+ mock_app {
51
+ set :raise_errors, false
52
+ set :dump_errors, true
53
+ get('/') { raise FooError, 'BOOM!' }
54
+ }
38
55
 
39
- get_it '/'
56
+ get '/'
57
+ assert_equal 500, status
58
+ assert @response.errors =~ /FooError - BOOM!:/
59
+ end
40
60
 
41
- should.be.server_error
42
- body.should.be.empty
61
+ it "raises without calling the handler when the raise_errors options is set" do
62
+ mock_app {
63
+ set :raise_errors, true
64
+ error(FooError) { "she's not there." }
65
+ get '/' do
66
+ raise FooError
67
+ end
68
+ }
69
+ assert_raise(FooError) { get '/' }
70
+ end
43
71
 
72
+ it "never raises Sinatra::NotFound beyond the application" do
73
+ mock_app {
74
+ set :raise_errors, true
75
+ get '/' do
76
+ raise Sinatra::NotFound
77
+ end
78
+ }
79
+ assert_nothing_raised { get '/' }
80
+ assert_equal 404, status
44
81
  end
45
82
 
46
- specify "doesn't override status if set" do
83
+ class FooNotFound < Sinatra::NotFound
84
+ end
47
85
 
48
- error FooError do
49
- status(200)
50
- end
86
+ it "cascades for subclasses of Sinatra::NotFound" do
87
+ mock_app {
88
+ set :raise_errors, true
89
+ error(FooNotFound) { "foo! not found." }
90
+ get '/' do
91
+ raise FooNotFound
92
+ end
93
+ }
94
+ assert_nothing_raised { get '/' }
95
+ assert_equal 404, status
96
+ assert_equal 'foo! not found.', body
97
+ end
51
98
 
52
- get '/' do
53
- raise FooError
54
- end
99
+ it 'has a not_found method for backwards compatibility' do
100
+ mock_app {
101
+ not_found do
102
+ "Lost, are we?"
103
+ end
104
+ }
55
105
 
56
- get_it '/'
106
+ get '/test'
107
+ assert_equal 404, status
108
+ assert_equal "Lost, are we?", body
109
+ end
110
+ end
57
111
 
58
- should.be.ok
112
+ describe 'Custom Error Pages' do
113
+ it 'allows numeric status code mappings to be registered with ::error' do
114
+ mock_app {
115
+ set :raise_errors, false
116
+ error(500) { 'Foo!' }
117
+ get '/' do
118
+ [500, {}, 'Internal Foo Error']
119
+ end
120
+ }
121
+ get '/'
122
+ assert_equal 500, status
123
+ assert_equal 'Foo!', body
124
+ end
59
125
 
126
+ it 'allows ranges of status code mappings to be registered with :error' do
127
+ mock_app {
128
+ set :raise_errors, false
129
+ error(500..550) { "Error: #{response.status}" }
130
+ get '/' do
131
+ [507, {}, 'A very special error']
132
+ end
133
+ }
134
+ get '/'
135
+ assert_equal 507, status
136
+ assert_equal 'Error: 507', body
60
137
  end
61
138
 
62
- specify "raises errors when the raise_errors option is set" do
63
- Sinatra.application.options.raise_errors = true
64
- error FooError do
65
- end
66
- get '/' do
67
- raise FooError
68
- end
69
- assert_raises(FooError) { get_it('/') }
139
+ class FooError < RuntimeError
70
140
  end
71
141
 
142
+ it 'runs after exception mappings and overwrites body' do
143
+ mock_app {
144
+ set :raise_errors, false
145
+ error FooError do
146
+ response.status = 502
147
+ 'from exception mapping'
148
+ end
149
+ error(500) { 'from 500 handler' }
150
+ error(502) { 'from custom error page' }
151
+
152
+ get '/' do
153
+ raise FooError
154
+ end
155
+ }
156
+ get '/'
157
+ assert_equal 502, status
158
+ assert_equal 'from custom error page', body
159
+ end
72
160
  end
@@ -0,0 +1,58 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ describe "Middleware" do
4
+ before do
5
+ @app = mock_app(Sinatra::Default) {
6
+ get '/*' do
7
+ response.headers['X-Tests'] = env['test.ran'].join(', ')
8
+ env['PATH_INFO']
9
+ end
10
+ }
11
+ end
12
+
13
+ class MockMiddleware < Struct.new(:app)
14
+ def call(env)
15
+ (env['test.ran'] ||= []) << self.class.to_s
16
+ app.call(env)
17
+ end
18
+ end
19
+
20
+ class UpcaseMiddleware < MockMiddleware
21
+ def call(env)
22
+ env['PATH_INFO'] = env['PATH_INFO'].upcase
23
+ super
24
+ end
25
+ end
26
+
27
+ it "is added with Sinatra::Application.use" do
28
+ @app.use UpcaseMiddleware
29
+ get '/hello-world'
30
+ assert ok?
31
+ assert_equal '/HELLO-WORLD', body
32
+ end
33
+
34
+ class DowncaseMiddleware < MockMiddleware
35
+ def call(env)
36
+ env['PATH_INFO'] = env['PATH_INFO'].downcase
37
+ super
38
+ end
39
+ end
40
+
41
+ specify "runs in the order defined" do
42
+ @app.use UpcaseMiddleware
43
+ @app.use DowncaseMiddleware
44
+ get '/Foo'
45
+ assert_equal "/foo", body
46
+ assert_equal "UpcaseMiddleware, DowncaseMiddleware", response['X-Tests']
47
+ end
48
+
49
+ specify "resets the prebuilt pipeline when new middleware is added" do
50
+ @app.use UpcaseMiddleware
51
+ get '/Foo'
52
+ assert_equal "/FOO", body
53
+ @app.use DowncaseMiddleware
54
+ get '/Foo'
55
+ assert_equal '/foo', body
56
+ assert_equal "UpcaseMiddleware, DowncaseMiddleware", response['X-Tests']
57
+ end
58
+ end
@@ -0,0 +1,97 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ describe 'Options' do
4
+ before { @app = Class.new(Sinatra::Base) }
5
+
6
+ it 'sets options to literal values' do
7
+ @app.set(:foo, 'bar')
8
+ assert @app.respond_to?(:foo)
9
+ assert_equal 'bar', @app.foo
10
+ end
11
+
12
+ it 'sets options to Procs' do
13
+ @app.set(:foo, Proc.new { 'baz' })
14
+ assert @app.respond_to?(:foo)
15
+ assert_equal 'baz', @app.foo
16
+ end
17
+
18
+ it "sets multiple options with a Hash" do
19
+ @app.set :foo => 1234,
20
+ :bar => 'Hello World',
21
+ :baz => Proc.new { 'bizzle' }
22
+ assert_equal 1234, @app.foo
23
+ assert_equal 'Hello World', @app.bar
24
+ assert_equal 'bizzle', @app.baz
25
+ end
26
+
27
+ it 'inherits option methods when subclassed' do
28
+ @app.set :foo, 'bar'
29
+ @app.set :biz, Proc.new { 'baz' }
30
+
31
+ sub = Class.new(@app)
32
+ assert sub.respond_to?(:foo)
33
+ assert_equal 'bar', sub.foo
34
+ assert sub.respond_to?(:biz)
35
+ assert_equal 'baz', sub.biz
36
+ end
37
+
38
+ it 'overrides options in subclass' do
39
+ @app.set :foo, 'bar'
40
+ @app.set :biz, Proc.new { 'baz' }
41
+ sub = Class.new(@app)
42
+ sub.set :foo, 'bling'
43
+ assert_equal 'bling', sub.foo
44
+ assert_equal 'bar', @app.foo
45
+ end
46
+
47
+ it 'creates setter methods when first defined' do
48
+ @app.set :foo, 'bar'
49
+ assert @app.respond_to?('foo=')
50
+ @app.foo = 'biz'
51
+ assert_equal 'biz', @app.foo
52
+ end
53
+
54
+ it 'creates predicate methods when first defined' do
55
+ @app.set :foo, 'hello world'
56
+ assert @app.respond_to?(:foo?)
57
+ assert @app.foo?
58
+ @app.set :foo, nil
59
+ assert !@app.foo?
60
+ end
61
+
62
+ it 'uses existing setter methods if detected' do
63
+ class << @app
64
+ def foo
65
+ @foo
66
+ end
67
+ def foo=(value)
68
+ @foo = 'oops'
69
+ end
70
+ end
71
+
72
+ @app.set :foo, 'bam'
73
+ assert_equal 'oops', @app.foo
74
+ end
75
+
76
+ it "sets multiple options to true with #enable" do
77
+ @app.enable :sessions, :foo, :bar
78
+ assert @app.sessions
79
+ assert @app.foo
80
+ assert @app.bar
81
+ end
82
+
83
+ it "sets multiple options to false with #disable" do
84
+ @app.disable :sessions, :foo, :bar
85
+ assert !@app.sessions
86
+ assert !@app.foo
87
+ assert !@app.bar
88
+ end
89
+
90
+ it 'enables MethodOverride middleware when :methodoverride is enabled' do
91
+ @app.set :methodoverride, true
92
+ @app.put('/') { 'okay' }
93
+ post '/', {'_method'=>'PUT'}, {}
94
+ assert_equal 200, status
95
+ assert_equal 'okay', body
96
+ end
97
+ end
@@ -0,0 +1,61 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ $reload_count = 0
4
+ $reload_app = nil
5
+
6
+ describe "Reloading" do
7
+ before {
8
+ @app = mock_app(Sinatra::Default)
9
+ $reload_app = @app
10
+ }
11
+
12
+ after {
13
+ $reload_app = nil
14
+ }
15
+
16
+ it 'is enabled by default when in development and the app_file is set' do
17
+ @app.set :app_file, __FILE__
18
+ @app.set :environment, :development
19
+ assert_same true, @app.reload
20
+ assert_same true, @app.reload?
21
+ end
22
+
23
+ it 'is disabled by default when running in non-development environment' do
24
+ @app.set :app_file, __FILE__
25
+ @app.set :environment, :test
26
+ assert !@app.reload
27
+ assert_same false, @app.reload?
28
+ end
29
+
30
+ it 'is disabled by default when no app_file is available' do
31
+ @app.set :app_file, nil
32
+ @app.set :environment, :development
33
+ assert !@app.reload
34
+ assert_same false, @app.reload?
35
+ end
36
+
37
+ it 'can be turned off explicitly' do
38
+ @app.set :app_file, __FILE__
39
+ @app.set :environment, :development
40
+ assert_same true, @app.reload
41
+ @app.set :reload, false
42
+ assert_same false, @app.reload
43
+ assert_same false, @app.reload?
44
+ end
45
+
46
+ it 'reloads the app_file each time a request is made' do
47
+ @app.set :app_file, File.dirname(__FILE__) + '/data/reload_app_file.rb'
48
+ @app.set :reload, true
49
+ @app.get('/') { 'Hello World' }
50
+
51
+ get '/'
52
+ assert_equal 200, status
53
+ assert_equal 'Hello from reload file', body
54
+ assert_equal 1, $reload_count
55
+
56
+ get '/'
57
+ assert_equal 200, status
58
+ assert_equal 'Hello from reload file', body
59
+ assert_equal 2, $reload_count
60
+ end
61
+ end
@@ -0,0 +1,18 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ describe 'Sinatra::Request' do
4
+ it 'responds to #user_agent' do
5
+ request = Sinatra::Request.new({'HTTP_USER_AGENT' => 'Test'})
6
+ assert request.respond_to?(:user_agent)
7
+ assert_equal 'Test', request.user_agent
8
+ end
9
+
10
+ it 'parses POST params when Content-Type is form-dataish' do
11
+ request = Sinatra::Request.new(
12
+ 'REQUEST_METHOD' => 'PUT',
13
+ 'CONTENT_TYPE' => 'application/x-www-form-urlencoded',
14
+ 'rack.input' => StringIO.new('foo=bar')
15
+ )
16
+ assert_equal 'bar', request.params['foo']
17
+ end
18
+ end
@@ -0,0 +1,88 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ describe 'Result Handling' do
4
+ it "sets response.body when result is a String" do
5
+ mock_app {
6
+ get '/' do
7
+ 'Hello World'
8
+ end
9
+ }
10
+
11
+ get '/'
12
+ assert ok?
13
+ assert_equal 'Hello World', body
14
+ end
15
+
16
+ it "sets response.body when result is an Array of Strings" do
17
+ mock_app {
18
+ get '/' do
19
+ ['Hello', 'World']
20
+ end
21
+ }
22
+
23
+ get '/'
24
+ assert ok?
25
+ assert_equal 'HelloWorld', body
26
+ end
27
+
28
+ it "sets response.body when result responds to #each" do
29
+ mock_app {
30
+ get '/' do
31
+ res = lambda { 'Hello World' }
32
+ def res.each ; yield call ; end
33
+ res
34
+ end
35
+ }
36
+
37
+ get '/'
38
+ assert ok?
39
+ assert_equal 'Hello World', body
40
+ end
41
+
42
+ it "sets response.body to [] when result is nil" do
43
+ mock_app {
44
+ get '/' do
45
+ nil
46
+ end
47
+ }
48
+
49
+ get '/'
50
+ assert ok?
51
+ assert_equal '', body
52
+ end
53
+
54
+ it "sets status, headers, and body when result is a Rack response tuple" do
55
+ mock_app {
56
+ get '/' do
57
+ [205, {'Content-Type' => 'foo/bar'}, 'Hello World']
58
+ end
59
+ }
60
+
61
+ get '/'
62
+ assert_equal 205, status
63
+ assert_equal 'foo/bar', response['Content-Type']
64
+ assert_equal 'Hello World', body
65
+ end
66
+
67
+ it "sets status and body when result is a two-tuple" do
68
+ mock_app {
69
+ get '/' do
70
+ [409, 'formula of']
71
+ end
72
+ }
73
+
74
+ get '/'
75
+ assert_equal 409, status
76
+ assert_equal 'formula of', body
77
+ end
78
+
79
+ it "sets status when result is a Fixnum status code" do
80
+ mock_app {
81
+ get('/') { 205 }
82
+ }
83
+
84
+ get '/'
85
+ assert_equal 205, status
86
+ assert_equal '', body
87
+ end
88
+ end