darkhelmet-sinatra 0.9.1.1 → 0.10.1
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.
- data/AUTHORS +2 -0
- data/CHANGES +180 -0
- data/LICENSE +1 -1
- data/README.jp.rdoc +552 -0
- data/README.rdoc +177 -38
- data/Rakefile +18 -25
- data/lib/sinatra.rb +1 -2
- data/lib/sinatra/base.rb +405 -305
- data/lib/sinatra/main.rb +5 -24
- data/lib/sinatra/showexceptions.rb +303 -0
- data/lib/sinatra/tilt.rb +509 -0
- data/sinatra.gemspec +21 -51
- data/test/base_test.rb +123 -93
- data/test/builder_test.rb +2 -1
- data/test/contest.rb +64 -0
- data/test/erb_test.rb +1 -1
- data/test/erubis_test.rb +82 -0
- data/test/extensions_test.rb +24 -8
- data/test/filter_test.rb +99 -3
- data/test/haml_test.rb +25 -3
- data/test/helper.rb +43 -48
- data/test/helpers_test.rb +500 -424
- data/test/mapped_error_test.rb +163 -137
- data/test/middleware_test.rb +3 -3
- data/test/request_test.rb +16 -1
- data/test/response_test.rb +2 -2
- data/test/result_test.rb +1 -1
- data/test/route_added_hook_test.rb +59 -0
- data/test/routing_test.rb +170 -22
- data/test/sass_test.rb +44 -1
- data/test/server_test.rb +19 -13
- data/test/sinatra_test.rb +1 -1
- data/test/static_test.rb +9 -2
- data/test/templates_test.rb +78 -11
- data/test/views/error.builder +3 -0
- data/test/views/error.erb +3 -0
- data/test/views/error.erubis +3 -0
- data/test/views/error.haml +3 -0
- data/test/views/error.sass +2 -0
- data/test/views/foo/hello.test +1 -0
- data/test/views/hello.erubis +1 -0
- data/test/views/layout2.erubis +2 -0
- metadata +37 -55
- data/compat/app_test.rb +0 -282
- data/compat/application_test.rb +0 -262
- data/compat/builder_test.rb +0 -101
- data/compat/compat_test.rb +0 -12
- data/compat/custom_error_test.rb +0 -62
- data/compat/erb_test.rb +0 -136
- data/compat/events_test.rb +0 -78
- data/compat/filter_test.rb +0 -30
- data/compat/haml_test.rb +0 -233
- data/compat/helper.rb +0 -30
- data/compat/mapped_error_test.rb +0 -72
- data/compat/pipeline_test.rb +0 -45
- data/compat/public/foo.xml +0 -1
- data/compat/sass_test.rb +0 -57
- data/compat/sessions_test.rb +0 -42
- data/compat/streaming_test.rb +0 -133
- data/compat/sym_params_test.rb +0 -19
- data/compat/template_test.rb +0 -30
- data/compat/use_in_file_templates_test.rb +0 -47
- data/compat/views/foo.builder +0 -1
- data/compat/views/foo.erb +0 -1
- data/compat/views/foo.haml +0 -1
- data/compat/views/foo.sass +0 -2
- data/compat/views/foo_layout.erb +0 -2
- data/compat/views/foo_layout.haml +0 -2
- data/compat/views/layout_test/foo.builder +0 -1
- data/compat/views/layout_test/foo.erb +0 -1
- data/compat/views/layout_test/foo.haml +0 -1
- data/compat/views/layout_test/foo.sass +0 -2
- data/compat/views/layout_test/layout.builder +0 -3
- data/compat/views/layout_test/layout.erb +0 -1
- data/compat/views/layout_test/layout.haml +0 -1
- data/compat/views/layout_test/layout.sass +0 -2
- data/compat/views/no_layout/no_layout.builder +0 -1
- data/compat/views/no_layout/no_layout.haml +0 -1
- data/lib/sinatra/compat.rb +0 -250
- data/lib/sinatra/test.rb +0 -126
- data/lib/sinatra/test/bacon.rb +0 -19
- data/lib/sinatra/test/rspec.rb +0 -13
- data/lib/sinatra/test/spec.rb +0 -11
- data/lib/sinatra/test/unit.rb +0 -13
- data/test/data/reload_app_file.rb +0 -3
- data/test/options_test.rb +0 -374
- data/test/reload_test.rb +0 -68
- data/test/test_test.rb +0 -144
data/test/mapped_error_test.rb
CHANGED
@@ -6,155 +6,181 @@ end
|
|
6
6
|
class FooNotFound < Sinatra::NotFound
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
set :raise_errors, false
|
13
|
-
error(FooError) { 'Foo!' }
|
14
|
-
get '/' do
|
15
|
-
raise FooError
|
16
|
-
end
|
17
|
-
}
|
18
|
-
get '/'
|
19
|
-
assert_equal 500, status
|
20
|
-
assert_equal 'Foo!', body
|
9
|
+
class MappedErrorTest < Test::Unit::TestCase
|
10
|
+
def test_default
|
11
|
+
assert true
|
21
12
|
end
|
22
13
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
43
35
|
}
|
44
|
-
get '/' do
|
45
|
-
raise FooError
|
46
|
-
end
|
47
|
-
}
|
48
|
-
get '/'
|
49
|
-
assert_equal 'looks good', body
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'dumps errors to rack.errors when dump_errors is enabled' do
|
53
|
-
mock_app {
|
54
|
-
set :raise_errors, false
|
55
|
-
set :dump_errors, true
|
56
|
-
get('/') { raise FooError, 'BOOM!' }
|
57
|
-
}
|
58
|
-
|
59
|
-
get '/'
|
60
|
-
assert_equal 500, status
|
61
|
-
assert @response.errors =~ /FooError - BOOM!:/
|
62
|
-
end
|
63
36
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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 without calling the handler when the raise_errors options is set" do
|
59
|
+
mock_app {
|
60
|
+
set :raise_errors, true
|
61
|
+
error(FooError) { "she's not there." }
|
62
|
+
get '/' do
|
63
|
+
raise FooError
|
64
|
+
end
|
65
|
+
}
|
66
|
+
assert_raise(FooError) { get '/' }
|
67
|
+
end
|
68
|
+
|
69
|
+
it "never raises Sinatra::NotFound beyond the application" do
|
70
|
+
mock_app {
|
71
|
+
set :raise_errors, true
|
72
|
+
get '/' do
|
73
|
+
raise Sinatra::NotFound
|
74
|
+
end
|
75
|
+
}
|
76
|
+
assert_nothing_raised { get '/' }
|
77
|
+
assert_equal 404, status
|
78
|
+
end
|
79
|
+
|
80
|
+
it "cascades for subclasses of Sinatra::NotFound" do
|
81
|
+
mock_app {
|
82
|
+
set :raise_errors, true
|
83
|
+
error(FooNotFound) { "foo! not found." }
|
84
|
+
get '/' do
|
85
|
+
raise FooNotFound
|
86
|
+
end
|
87
|
+
}
|
88
|
+
assert_nothing_raised { get '/' }
|
89
|
+
assert_equal 404, status
|
90
|
+
assert_equal 'foo! not found.', body
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'has a not_found method for backwards compatibility' do
|
94
|
+
mock_app {
|
95
|
+
not_found do
|
96
|
+
"Lost, are we?"
|
97
|
+
end
|
98
|
+
}
|
74
99
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
raise Sinatra::NotFound
|
80
|
-
end
|
81
|
-
}
|
82
|
-
assert_nothing_raised { get '/' }
|
83
|
-
assert_equal 404, status
|
84
|
-
end
|
100
|
+
get '/test'
|
101
|
+
assert_equal 404, status
|
102
|
+
assert_equal "Lost, are we?", body
|
103
|
+
end
|
85
104
|
|
86
|
-
|
87
|
-
|
88
|
-
|
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
|
105
|
+
it 'inherits error mappings from base class' do
|
106
|
+
base = Class.new(Sinatra::Base)
|
107
|
+
base.error(FooError) { 'base class' }
|
98
108
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
109
|
+
mock_app(base) {
|
110
|
+
set :raise_errors, false
|
111
|
+
get '/' do
|
112
|
+
raise FooError
|
113
|
+
end
|
114
|
+
}
|
105
115
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
110
|
-
end
|
116
|
+
get '/'
|
117
|
+
assert_equal 'base class', body
|
118
|
+
end
|
111
119
|
|
112
|
-
|
113
|
-
|
114
|
-
|
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
|
120
|
+
it 'overrides error mappings in base class' do
|
121
|
+
base = Class.new(Sinatra::Base)
|
122
|
+
base.error(FooError) { 'base class' }
|
125
123
|
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
}
|
134
|
-
get '/'
|
135
|
-
assert_equal 507, status
|
136
|
-
assert_equal 'Error: 507', body
|
137
|
-
end
|
124
|
+
mock_app(base) {
|
125
|
+
set :raise_errors, false
|
126
|
+
error(FooError) { 'subclass' }
|
127
|
+
get '/' do
|
128
|
+
raise FooError
|
129
|
+
end
|
130
|
+
}
|
138
131
|
|
139
|
-
|
132
|
+
get '/'
|
133
|
+
assert_equal 'subclass', body
|
134
|
+
end
|
140
135
|
end
|
141
136
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
'
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
137
|
+
describe 'Custom Error Pages' do
|
138
|
+
it 'allows numeric status code mappings to be registered with ::error' do
|
139
|
+
mock_app {
|
140
|
+
set :raise_errors, false
|
141
|
+
error(500) { 'Foo!' }
|
142
|
+
get '/' do
|
143
|
+
[500, {}, 'Internal Foo Error']
|
144
|
+
end
|
145
|
+
}
|
146
|
+
get '/'
|
147
|
+
assert_equal 500, status
|
148
|
+
assert_equal 'Foo!', body
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'allows ranges of status code mappings to be registered with :error' do
|
152
|
+
mock_app {
|
153
|
+
set :raise_errors, false
|
154
|
+
error(500..550) { "Error: #{response.status}" }
|
155
|
+
get '/' do
|
156
|
+
[507, {}, 'A very special error']
|
157
|
+
end
|
158
|
+
}
|
159
|
+
get '/'
|
160
|
+
assert_equal 507, status
|
161
|
+
assert_equal 'Error: 507', body
|
162
|
+
end
|
163
|
+
|
164
|
+
class FooError < RuntimeError
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'runs after exception mappings and overwrites body' do
|
168
|
+
mock_app {
|
169
|
+
set :raise_errors, false
|
170
|
+
error FooError do
|
171
|
+
response.status = 502
|
172
|
+
'from exception mapping'
|
173
|
+
end
|
174
|
+
error(500) { 'from 500 handler' }
|
175
|
+
error(502) { 'from custom error page' }
|
176
|
+
|
177
|
+
get '/' do
|
178
|
+
raise FooError
|
179
|
+
end
|
180
|
+
}
|
181
|
+
get '/'
|
182
|
+
assert_equal 502, status
|
183
|
+
assert_equal 'from custom error page', body
|
184
|
+
end
|
159
185
|
end
|
160
186
|
end
|
data/test/middleware_test.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
@app = mock_app(Sinatra::
|
3
|
+
class MiddlewareTest < Test::Unit::TestCase
|
4
|
+
setup do
|
5
|
+
@app = mock_app(Sinatra::Application) {
|
6
6
|
get '/*' do
|
7
7
|
response.headers['X-Tests'] = env['test.ran'].
|
8
8
|
map { |n| n.split('::').last }.
|
data/test/request_test.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/helper'
|
2
2
|
|
3
|
-
|
3
|
+
class RequestTest < Test::Unit::TestCase
|
4
4
|
it 'responds to #user_agent' do
|
5
5
|
request = Sinatra::Request.new({'HTTP_USER_AGENT' => 'Test'})
|
6
6
|
assert request.respond_to?(:user_agent)
|
@@ -15,4 +15,19 @@ describe 'Sinatra::Request' do
|
|
15
15
|
)
|
16
16
|
assert_equal 'bar', request.params['foo']
|
17
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
|
18
33
|
end
|
data/test/response_test.rb
CHANGED
data/test/result_test.rb
CHANGED
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/helper'
|
2
|
+
|
3
|
+
module RouteAddedTest
|
4
|
+
@routes, @procs = [], []
|
5
|
+
def self.routes ; @routes ; end
|
6
|
+
def self.procs ; @procs ; end
|
7
|
+
def self.route_added(verb, path, proc)
|
8
|
+
@routes << [verb, path]
|
9
|
+
@procs << proc
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class RouteAddedHookTest < Test::Unit::TestCase
|
14
|
+
setup {
|
15
|
+
RouteAddedTest.routes.clear
|
16
|
+
RouteAddedTest.procs.clear
|
17
|
+
}
|
18
|
+
|
19
|
+
it "should be notified of an added route" do
|
20
|
+
mock_app(Class.new(Sinatra::Base)) {
|
21
|
+
register RouteAddedTest
|
22
|
+
get('/') {}
|
23
|
+
}
|
24
|
+
|
25
|
+
assert_equal [["GET", "/"], ["HEAD", "/"]],
|
26
|
+
RouteAddedTest.routes
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should include hooks from superclass" do
|
30
|
+
a = Class.new(Class.new(Sinatra::Base))
|
31
|
+
b = Class.new(a)
|
32
|
+
|
33
|
+
a.register RouteAddedTest
|
34
|
+
b.class_eval { post("/sub_app_route") {} }
|
35
|
+
|
36
|
+
assert_equal [["POST", "/sub_app_route"]],
|
37
|
+
RouteAddedTest.routes
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should only run once per extension" do
|
41
|
+
mock_app(Class.new(Sinatra::Base)) {
|
42
|
+
register RouteAddedTest
|
43
|
+
register RouteAddedTest
|
44
|
+
get('/') {}
|
45
|
+
}
|
46
|
+
|
47
|
+
assert_equal [["GET", "/"], ["HEAD", "/"]],
|
48
|
+
RouteAddedTest.routes
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should pass route blocks as an argument" do
|
52
|
+
mock_app(Class.new(Sinatra::Base)) {
|
53
|
+
register RouteAddedTest
|
54
|
+
get('/') {}
|
55
|
+
}
|
56
|
+
|
57
|
+
assert_kind_of Proc, RouteAddedTest.procs.first
|
58
|
+
end
|
59
|
+
end
|
data/test/routing_test.rb
CHANGED
@@ -5,7 +5,23 @@ def route_def(pattern)
|
|
5
5
|
mock_app { get(pattern) { } }
|
6
6
|
end
|
7
7
|
|
8
|
-
|
8
|
+
class RegexpLookAlike
|
9
|
+
class MatchData
|
10
|
+
def captures
|
11
|
+
["this", "is", "a", "test"]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def match(string)
|
16
|
+
::RegexpLookAlike::MatchData.new if string == "/this/is/a/test/"
|
17
|
+
end
|
18
|
+
|
19
|
+
def keys
|
20
|
+
["one", "two", "three", "four"]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class RoutingTest < Test::Unit::TestCase
|
9
25
|
%w[get put post delete].each do |verb|
|
10
26
|
it "defines #{verb.upcase} request handlers with #{verb}" do
|
11
27
|
mock_app {
|
@@ -44,6 +60,30 @@ describe "Routing" do
|
|
44
60
|
assert_equal 404, status
|
45
61
|
end
|
46
62
|
|
63
|
+
it "404s and sets X-Cascade header when no route satisfies the request" do
|
64
|
+
mock_app {
|
65
|
+
get('/foo') { }
|
66
|
+
}
|
67
|
+
get '/bar'
|
68
|
+
assert_equal 404, status
|
69
|
+
assert_equal 'pass', response.headers['X-Cascade']
|
70
|
+
end
|
71
|
+
|
72
|
+
it "overrides the content-type in error handlers" do
|
73
|
+
mock_app {
|
74
|
+
before { content_type 'text/plain' }
|
75
|
+
error Sinatra::NotFound do
|
76
|
+
content_type "text/html"
|
77
|
+
"<h1>Not Found</h1>"
|
78
|
+
end
|
79
|
+
}
|
80
|
+
|
81
|
+
get '/foo'
|
82
|
+
assert_equal 404, status
|
83
|
+
assert_equal 'text/html', response["Content-Type"]
|
84
|
+
assert_equal "<h1>Not Found</h1>", response.body
|
85
|
+
end
|
86
|
+
|
47
87
|
it 'takes multiple definitions of a route' do
|
48
88
|
mock_app {
|
49
89
|
user_agent(/Foo/)
|
@@ -243,17 +283,7 @@ describe "Routing" do
|
|
243
283
|
end
|
244
284
|
|
245
285
|
it "supports deeply nested params" do
|
246
|
-
|
247
|
-
'browser[chrome][engine][name]' => 'V8',
|
248
|
-
'browser[chrome][engine][version]' => '1.0',
|
249
|
-
'browser[firefox][engine][name]' => 'spidermonkey',
|
250
|
-
'browser[firefox][engine][version]' => '1.7.0',
|
251
|
-
'emacs[map][goto-line]' => 'M-g g',
|
252
|
-
'emacs[version]' => '22.3.1',
|
253
|
-
'paste[name]' => 'hello world',
|
254
|
-
'paste[syntax]' => 'ruby'
|
255
|
-
}
|
256
|
-
expected = {
|
286
|
+
expected_params = {
|
257
287
|
"emacs" => {
|
258
288
|
"map" => { "goto-line" => "M-g g" },
|
259
289
|
"version" => "22.3.1"
|
@@ -266,11 +296,11 @@ describe "Routing" do
|
|
266
296
|
}
|
267
297
|
mock_app {
|
268
298
|
get '/foo' do
|
269
|
-
assert_equal
|
299
|
+
assert_equal expected_params, params
|
270
300
|
'looks good'
|
271
301
|
end
|
272
302
|
}
|
273
|
-
get
|
303
|
+
get '/foo', expected_params
|
274
304
|
assert ok?
|
275
305
|
assert_equal 'looks good', body
|
276
306
|
end
|
@@ -352,9 +382,26 @@ describe "Routing" do
|
|
352
382
|
assert_equal 'right on', body
|
353
383
|
end
|
354
384
|
|
385
|
+
it 'supports regular expression look-alike routes' do
|
386
|
+
mock_app {
|
387
|
+
get(RegexpLookAlike.new) do
|
388
|
+
assert_equal 'this', params[:one]
|
389
|
+
assert_equal 'is', params[:two]
|
390
|
+
assert_equal 'a', params[:three]
|
391
|
+
assert_equal 'test', params[:four]
|
392
|
+
'right on'
|
393
|
+
end
|
394
|
+
}
|
395
|
+
|
396
|
+
get '/this/is/a/test/'
|
397
|
+
assert ok?
|
398
|
+
assert_equal 'right on', body
|
399
|
+
end
|
400
|
+
|
355
401
|
it 'raises a TypeError when pattern is not a String or Regexp' do
|
356
|
-
|
357
|
-
|
402
|
+
assert_raise(TypeError) {
|
403
|
+
mock_app { get(42){} }
|
404
|
+
}
|
358
405
|
end
|
359
406
|
|
360
407
|
it "returns response immediately on halt" do
|
@@ -424,6 +471,38 @@ describe "Routing" do
|
|
424
471
|
assert not_found?
|
425
472
|
end
|
426
473
|
|
474
|
+
it "transitions to 404 and sets X-Cascade header when passed and no subsequent route matches" do
|
475
|
+
mock_app {
|
476
|
+
get '/:foo' do
|
477
|
+
pass
|
478
|
+
'Hello Foo'
|
479
|
+
end
|
480
|
+
|
481
|
+
get '/bar' do
|
482
|
+
'Hello Bar'
|
483
|
+
end
|
484
|
+
}
|
485
|
+
|
486
|
+
get '/foo'
|
487
|
+
assert not_found?
|
488
|
+
assert_equal 'pass', response.headers['X-Cascade']
|
489
|
+
end
|
490
|
+
|
491
|
+
it "uses optional block passed to pass as route block if no other route is found" do
|
492
|
+
mock_app {
|
493
|
+
get "/" do
|
494
|
+
pass do
|
495
|
+
"this"
|
496
|
+
end
|
497
|
+
"not this"
|
498
|
+
end
|
499
|
+
}
|
500
|
+
|
501
|
+
get "/"
|
502
|
+
assert ok?
|
503
|
+
assert "this", body
|
504
|
+
end
|
505
|
+
|
427
506
|
it "passes when matching condition returns false" do
|
428
507
|
mock_app {
|
429
508
|
condition { params[:foo] == 'bar' }
|
@@ -479,7 +558,7 @@ describe "Routing" do
|
|
479
558
|
get '/foo'
|
480
559
|
assert not_found?
|
481
560
|
|
482
|
-
get '/foo',
|
561
|
+
get '/foo', {}, { 'HTTP_HOST' => 'example.com' }
|
483
562
|
assert_equal 200, status
|
484
563
|
assert_equal 'Hello World', body
|
485
564
|
end
|
@@ -494,7 +573,7 @@ describe "Routing" do
|
|
494
573
|
get '/foo'
|
495
574
|
assert not_found?
|
496
575
|
|
497
|
-
get '/foo',
|
576
|
+
get '/foo', {}, { 'HTTP_USER_AGENT' => 'Foo Bar' }
|
498
577
|
assert_equal 200, status
|
499
578
|
assert_equal 'Hello World', body
|
500
579
|
end
|
@@ -506,7 +585,7 @@ describe "Routing" do
|
|
506
585
|
'Hello ' + params[:agent].first
|
507
586
|
end
|
508
587
|
}
|
509
|
-
get '/foo',
|
588
|
+
get '/foo', {}, { 'HTTP_USER_AGENT' => 'Foo Bar' }
|
510
589
|
assert_equal 200, status
|
511
590
|
assert_equal 'Hello Bar', body
|
512
591
|
end
|
@@ -518,12 +597,12 @@ describe "Routing" do
|
|
518
597
|
end
|
519
598
|
}
|
520
599
|
|
521
|
-
get '/',
|
600
|
+
get '/', {}, { 'HTTP_ACCEPT' => 'application/xml' }
|
522
601
|
assert ok?
|
523
602
|
assert_equal 'application/xml', body
|
524
603
|
assert_equal 'application/xml', response.headers['Content-Type']
|
525
604
|
|
526
|
-
get '/',
|
605
|
+
get '/', {}, { :accept => 'text/html' }
|
527
606
|
assert !ok?
|
528
607
|
end
|
529
608
|
|
@@ -537,7 +616,7 @@ describe "Routing" do
|
|
537
616
|
}
|
538
617
|
|
539
618
|
types.each do |type|
|
540
|
-
get '/',
|
619
|
+
get '/', {}, { 'HTTP_ACCEPT' => type }
|
541
620
|
assert ok?
|
542
621
|
assert_equal type, body
|
543
622
|
assert_equal type, response.headers['Content-Type']
|
@@ -655,6 +734,40 @@ describe "Routing" do
|
|
655
734
|
assert_equal 'ab', body
|
656
735
|
end
|
657
736
|
|
737
|
+
it 'allows custom route-conditions to be set via route options' do
|
738
|
+
protector = Module.new {
|
739
|
+
def protect(*args)
|
740
|
+
condition {
|
741
|
+
unless authorize(params["user"], params["password"])
|
742
|
+
halt 403, "go away"
|
743
|
+
end
|
744
|
+
}
|
745
|
+
end
|
746
|
+
}
|
747
|
+
|
748
|
+
mock_app {
|
749
|
+
register protector
|
750
|
+
|
751
|
+
helpers do
|
752
|
+
def authorize(username, password)
|
753
|
+
username == "foo" && password == "bar"
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
757
|
+
get "/", :protect => true do
|
758
|
+
"hey"
|
759
|
+
end
|
760
|
+
}
|
761
|
+
|
762
|
+
get "/"
|
763
|
+
assert forbidden?
|
764
|
+
assert_equal "go away", body
|
765
|
+
|
766
|
+
get "/", :user => "foo", :password => "bar"
|
767
|
+
assert ok?
|
768
|
+
assert_equal "hey", body
|
769
|
+
end
|
770
|
+
|
658
771
|
# NOTE Block params behaves differently under 1.8 and 1.9. Under 1.8, block
|
659
772
|
# param arity is lax: declaring a mismatched number of block params results
|
660
773
|
# in a warning. Under 1.9, block param arity is strict: mismatched block
|
@@ -709,4 +822,39 @@ describe "Routing" do
|
|
709
822
|
end
|
710
823
|
|
711
824
|
end
|
825
|
+
|
826
|
+
it "matches routes defined in superclasses" do
|
827
|
+
base = Class.new(Sinatra::Base)
|
828
|
+
base.get('/foo') { 'foo in baseclass' }
|
829
|
+
|
830
|
+
mock_app(base) {
|
831
|
+
get('/bar') { 'bar in subclass' }
|
832
|
+
}
|
833
|
+
|
834
|
+
get '/foo'
|
835
|
+
assert ok?
|
836
|
+
assert_equal 'foo in baseclass', body
|
837
|
+
|
838
|
+
get '/bar'
|
839
|
+
assert ok?
|
840
|
+
assert_equal 'bar in subclass', body
|
841
|
+
end
|
842
|
+
|
843
|
+
it "matches routes in subclasses before superclasses" do
|
844
|
+
base = Class.new(Sinatra::Base)
|
845
|
+
base.get('/foo') { 'foo in baseclass' }
|
846
|
+
base.get('/bar') { 'bar in baseclass' }
|
847
|
+
|
848
|
+
mock_app(base) {
|
849
|
+
get('/foo') { 'foo in subclass' }
|
850
|
+
}
|
851
|
+
|
852
|
+
get '/foo'
|
853
|
+
assert ok?
|
854
|
+
assert_equal 'foo in subclass', body
|
855
|
+
|
856
|
+
get '/bar'
|
857
|
+
assert ok?
|
858
|
+
assert_equal 'bar in baseclass', body
|
859
|
+
end
|
712
860
|
end
|