sinatra-base 1.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 (58) hide show
  1. data/AUTHORS +43 -0
  2. data/CHANGES +511 -0
  3. data/LICENSE +22 -0
  4. data/README.jp.rdoc +552 -0
  5. data/README.rdoc +636 -0
  6. data/Rakefile +116 -0
  7. data/lib/sinatra.rb +7 -0
  8. data/lib/sinatra/base.rb +1167 -0
  9. data/lib/sinatra/images/404.png +0 -0
  10. data/lib/sinatra/images/500.png +0 -0
  11. data/lib/sinatra/main.rb +28 -0
  12. data/lib/sinatra/showexceptions.rb +307 -0
  13. data/lib/sinatra/tilt.rb +746 -0
  14. data/sinatra-base.gemspec +94 -0
  15. data/test/base_test.rb +160 -0
  16. data/test/builder_test.rb +65 -0
  17. data/test/contest.rb +64 -0
  18. data/test/erb_test.rb +81 -0
  19. data/test/erubis_test.rb +82 -0
  20. data/test/extensions_test.rb +100 -0
  21. data/test/filter_test.rb +221 -0
  22. data/test/haml_test.rb +95 -0
  23. data/test/helper.rb +76 -0
  24. data/test/helpers_test.rb +582 -0
  25. data/test/less_test.rb +37 -0
  26. data/test/mapped_error_test.rb +197 -0
  27. data/test/middleware_test.rb +68 -0
  28. data/test/public/favicon.ico +0 -0
  29. data/test/request_test.rb +33 -0
  30. data/test/response_test.rb +42 -0
  31. data/test/result_test.rb +98 -0
  32. data/test/route_added_hook_test.rb +59 -0
  33. data/test/routing_test.rb +860 -0
  34. data/test/sass_test.rb +85 -0
  35. data/test/server_test.rb +47 -0
  36. data/test/settings_test.rb +368 -0
  37. data/test/sinatra_test.rb +13 -0
  38. data/test/static_test.rb +93 -0
  39. data/test/templates_test.rb +159 -0
  40. data/test/views/error.builder +3 -0
  41. data/test/views/error.erb +3 -0
  42. data/test/views/error.erubis +3 -0
  43. data/test/views/error.haml +3 -0
  44. data/test/views/error.sass +2 -0
  45. data/test/views/foo/hello.test +1 -0
  46. data/test/views/hello.builder +1 -0
  47. data/test/views/hello.erb +1 -0
  48. data/test/views/hello.erubis +1 -0
  49. data/test/views/hello.haml +1 -0
  50. data/test/views/hello.less +5 -0
  51. data/test/views/hello.sass +2 -0
  52. data/test/views/hello.test +1 -0
  53. data/test/views/layout2.builder +3 -0
  54. data/test/views/layout2.erb +2 -0
  55. data/test/views/layout2.erubis +2 -0
  56. data/test/views/layout2.haml +2 -0
  57. data/test/views/layout2.test +1 -0
  58. metadata +257 -0
@@ -0,0 +1,37 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+ require 'less'
3
+
4
+ class LessTest < Test::Unit::TestCase
5
+ def less_app(&block)
6
+ mock_app {
7
+ set :views, File.dirname(__FILE__) + '/views'
8
+ get '/', &block
9
+ }
10
+ get '/'
11
+ end
12
+
13
+ it 'renders inline Less strings' do
14
+ less_app { less "@white_color: #fff; #main { background-color: @white_color }"}
15
+ assert ok?
16
+ assert_equal "#main { background-color: #ffffff; }\n", body
17
+ end
18
+
19
+ it 'renders .less files in views path' do
20
+ less_app { less :hello }
21
+ assert ok?
22
+ assert_equal "#main { background-color: #ffffff; }\n", body
23
+ end
24
+
25
+ it 'ignores the layout option' do
26
+ less_app { less :hello, :layout => :layout2 }
27
+ assert ok?
28
+ assert_equal "#main { background-color: #ffffff; }\n", body
29
+ end
30
+
31
+ it "raises error if template not found" do
32
+ mock_app {
33
+ get('/') { less :no_such_template }
34
+ }
35
+ assert_raise(Errno::ENOENT) { get('/') }
36
+ end
37
+ end
@@ -0,0 +1,197 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class FooError < RuntimeError
4
+ end
5
+
6
+ class FooNotFound < Sinatra::NotFound
7
+ end
8
+
9
+ class MappedErrorTest < Test::Unit::TestCase
10
+ def test_default
11
+ assert true
12
+ end
13
+
14
+ describe 'Exception Mappings' do
15
+ it 'invokes handlers registered with ::error when raised' do
16
+ mock_app {
17
+ set :raise_errors, false
18
+ error(FooError) { 'Foo!' }
19
+ get '/' do
20
+ raise FooError
21
+ end
22
+ }
23
+ get '/'
24
+ assert_equal 500, status
25
+ assert_equal 'Foo!', body
26
+ end
27
+
28
+ it 'uses the Exception handler if no matching handler found' do
29
+ mock_app {
30
+ set :raise_errors, false
31
+ error(Exception) { 'Exception!' }
32
+ get '/' do
33
+ raise FooError
34
+ end
35
+ }
36
+
37
+ get '/'
38
+ assert_equal 500, status
39
+ assert_equal 'Exception!', body
40
+ end
41
+
42
+ it "sets env['sinatra.error'] to the rescued exception" do
43
+ mock_app {
44
+ set :raise_errors, false
45
+ error(FooError) {
46
+ assert env.include?('sinatra.error')
47
+ assert env['sinatra.error'].kind_of?(FooError)
48
+ 'looks good'
49
+ }
50
+ get '/' do
51
+ raise FooError
52
+ end
53
+ }
54
+ get '/'
55
+ assert_equal 'looks good', body
56
+ end
57
+
58
+ it "raises errors from the app when raise_errors set and no handler defined" do
59
+ mock_app {
60
+ set :raise_errors, true
61
+ get '/' do
62
+ raise FooError
63
+ end
64
+ }
65
+ assert_raise(FooError) { get '/' }
66
+ end
67
+
68
+ it "calls error handlers before raising errors even when raise_errors is set" do
69
+ mock_app {
70
+ set :raise_errors, true
71
+ error(FooError) { "she's there." }
72
+ get '/' do
73
+ raise FooError
74
+ end
75
+ }
76
+ assert_nothing_raised { get '/' }
77
+ assert_equal 500, status
78
+ end
79
+
80
+ 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
+ }
87
+ assert_nothing_raised { get '/' }
88
+ assert_equal 404, status
89
+ end
90
+
91
+ it "cascades for subclasses of Sinatra::NotFound" do
92
+ mock_app {
93
+ set :raise_errors, true
94
+ error(FooNotFound) { "foo! not found." }
95
+ get '/' do
96
+ raise FooNotFound
97
+ end
98
+ }
99
+ assert_nothing_raised { get '/' }
100
+ assert_equal 404, status
101
+ assert_equal 'foo! not found.', body
102
+ end
103
+
104
+ it 'has a not_found method for backwards compatibility' do
105
+ mock_app {
106
+ not_found do
107
+ "Lost, are we?"
108
+ end
109
+ }
110
+
111
+ get '/test'
112
+ assert_equal 404, status
113
+ assert_equal "Lost, are we?", body
114
+ end
115
+
116
+ it 'inherits error mappings from base class' do
117
+ base = Class.new(Sinatra::Base)
118
+ base.error(FooError) { 'base class' }
119
+
120
+ mock_app(base) {
121
+ set :raise_errors, false
122
+ get '/' do
123
+ raise FooError
124
+ end
125
+ }
126
+
127
+ get '/'
128
+ assert_equal 'base class', body
129
+ end
130
+
131
+ it 'overrides error mappings in base class' do
132
+ base = Class.new(Sinatra::Base)
133
+ base.error(FooError) { 'base class' }
134
+
135
+ mock_app(base) {
136
+ set :raise_errors, false
137
+ error(FooError) { 'subclass' }
138
+ get '/' do
139
+ raise FooError
140
+ end
141
+ }
142
+
143
+ get '/'
144
+ assert_equal 'subclass', body
145
+ end
146
+ end
147
+
148
+ describe 'Custom Error Pages' do
149
+ it 'allows numeric status code mappings to be registered with ::error' do
150
+ mock_app {
151
+ set :raise_errors, false
152
+ error(500) { 'Foo!' }
153
+ get '/' do
154
+ [500, {}, 'Internal Foo Error']
155
+ end
156
+ }
157
+ get '/'
158
+ assert_equal 500, status
159
+ assert_equal 'Foo!', body
160
+ end
161
+
162
+ it 'allows ranges of status code mappings to be registered with :error' do
163
+ mock_app {
164
+ set :raise_errors, false
165
+ error(500..550) { "Error: #{response.status}" }
166
+ get '/' do
167
+ [507, {}, 'A very special error']
168
+ end
169
+ }
170
+ get '/'
171
+ assert_equal 507, status
172
+ assert_equal 'Error: 507', body
173
+ end
174
+
175
+ class FooError < RuntimeError
176
+ end
177
+
178
+ it 'runs after exception mappings and overwrites body' do
179
+ mock_app {
180
+ set :raise_errors, false
181
+ error FooError do
182
+ response.status = 502
183
+ 'from exception mapping'
184
+ end
185
+ error(500) { 'from 500 handler' }
186
+ error(502) { 'from custom error page' }
187
+
188
+ get '/' do
189
+ raise FooError
190
+ end
191
+ }
192
+ get '/'
193
+ assert_equal 502, status
194
+ assert_equal 'from custom error page', body
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,68 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class MiddlewareTest < Test::Unit::TestCase
4
+ setup do
5
+ @app = mock_app(Sinatra::Application) {
6
+ get '/*' do
7
+ response.headers['X-Tests'] = env['test.ran'].
8
+ map { |n| n.split('::').last }.
9
+ join(', ')
10
+ env['PATH_INFO']
11
+ end
12
+ }
13
+ end
14
+
15
+ class MockMiddleware < Struct.new(:app)
16
+ def call(env)
17
+ (env['test.ran'] ||= []) << self.class.to_s
18
+ app.call(env)
19
+ end
20
+ end
21
+
22
+ class UpcaseMiddleware < MockMiddleware
23
+ def call(env)
24
+ env['PATH_INFO'] = env['PATH_INFO'].upcase
25
+ super
26
+ end
27
+ end
28
+
29
+ it "is added with Sinatra::Application.use" do
30
+ @app.use UpcaseMiddleware
31
+ get '/hello-world'
32
+ assert ok?
33
+ assert_equal '/HELLO-WORLD', body
34
+ end
35
+
36
+ class DowncaseMiddleware < MockMiddleware
37
+ def call(env)
38
+ env['PATH_INFO'] = env['PATH_INFO'].downcase
39
+ super
40
+ end
41
+ end
42
+
43
+ it "runs in the order defined" do
44
+ @app.use UpcaseMiddleware
45
+ @app.use DowncaseMiddleware
46
+ get '/Foo'
47
+ assert_equal "/foo", body
48
+ assert_equal "UpcaseMiddleware, DowncaseMiddleware", response['X-Tests']
49
+ end
50
+
51
+ it "resets the prebuilt pipeline when new middleware is added" do
52
+ @app.use UpcaseMiddleware
53
+ get '/Foo'
54
+ assert_equal "/FOO", body
55
+ @app.use DowncaseMiddleware
56
+ get '/Foo'
57
+ assert_equal '/foo', body
58
+ assert_equal "UpcaseMiddleware, DowncaseMiddleware", response['X-Tests']
59
+ end
60
+
61
+ it "works when app is used as middleware" do
62
+ @app.use UpcaseMiddleware
63
+ @app = @app.new
64
+ get '/Foo'
65
+ assert_equal "/FOO", body
66
+ assert_equal "UpcaseMiddleware", response['X-Tests']
67
+ end
68
+ end
File without changes
@@ -0,0 +1,33 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class RequestTest < Test::Unit::TestCase
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
+
19
+ it 'is secure when the url scheme is https' do
20
+ request = Sinatra::Request.new('rack.url_scheme' => 'https')
21
+ assert request.secure?
22
+ end
23
+
24
+ it 'is not secure when the url scheme is http' do
25
+ request = Sinatra::Request.new('rack.url_scheme' => 'http')
26
+ assert !request.secure?
27
+ end
28
+
29
+ it 'respects X-Forwarded-Proto header for proxied SSL' do
30
+ request = Sinatra::Request.new('HTTP_X_FORWARDED_PROTO' => 'https')
31
+ assert request.secure?
32
+ end
33
+ end
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+
3
+ require File.dirname(__FILE__) + '/helper'
4
+
5
+ class ResponseTest < Test::Unit::TestCase
6
+ setup do
7
+ @response = Sinatra::Response.new
8
+ end
9
+
10
+ it "initializes with 200, text/html, and empty body" do
11
+ assert_equal 200, @response.status
12
+ assert_equal 'text/html', @response['Content-Type']
13
+ assert_equal [], @response.body
14
+ end
15
+
16
+ it 'uses case insensitive headers' do
17
+ @response['content-type'] = 'application/foo'
18
+ assert_equal 'application/foo', @response['Content-Type']
19
+ assert_equal 'application/foo', @response['CONTENT-TYPE']
20
+ end
21
+
22
+ it 'writes to body' do
23
+ @response.body = 'Hello'
24
+ @response.write ' World'
25
+ assert_equal 'Hello World', @response.body
26
+ end
27
+
28
+ [204, 304].each do |status_code|
29
+ it "removes the Content-Type header and body when response status is #{status_code}" do
30
+ @response.status = status_code
31
+ @response.body = ['Hello World']
32
+ assert_equal [status_code, {}, []], @response.finish
33
+ end
34
+ end
35
+
36
+ it 'Calculates the Content-Length using the bytesize of the body' do
37
+ @response.body = ['Hello', 'World!', '✈']
38
+ status, headers, body = @response.finish
39
+ assert_equal '14', headers['Content-Length']
40
+ assert_equal @response.body, body
41
+ end
42
+ end
@@ -0,0 +1,98 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class ResultTest < Test::Unit::TestCase
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 "raises a TypeError when result is a non two or three tuple Array" do
80
+ mock_app {
81
+ get '/' do
82
+ [409, 'formula of', 'something else', 'even more']
83
+ end
84
+ }
85
+
86
+ assert_raise(TypeError) { get '/' }
87
+ end
88
+
89
+ it "sets status when result is a Fixnum status code" do
90
+ mock_app {
91
+ get('/') { 205 }
92
+ }
93
+
94
+ get '/'
95
+ assert_equal 205, status
96
+ assert_equal '', body
97
+ end
98
+ end