scorched 0.19 → 0.20
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +11 -1
- data/Gemfile +0 -0
- data/LICENSE +0 -0
- data/docs/02_fundamentals/01_the_controller.md +14 -9
- data/docs/02_fundamentals/04_requests_and_responses.md +2 -2
- data/docs/02_fundamentals/05_filters.md +12 -4
- data/docs/02_fundamentals/08_views.md +8 -1
- data/lib/scorched/controller.rb +78 -54
- data/lib/scorched/dynamic_delegate.rb +0 -0
- data/lib/scorched/error.rb +0 -0
- data/lib/scorched/static.rb +1 -1
- data/lib/scorched/version.rb +1 -1
- data/spec/controller_spec.rb +66 -14
- data/spec/helper.rb +2 -0
- data/spec/options_spec.rb +0 -0
- data/spec/public/static.txt +0 -0
- data/spec/request_spec.rb +0 -0
- data/spec/views/composer.erb +0 -0
- data/spec/views/layout.erb +0 -0
- data/spec/views/main.erb +0 -0
- data/spec/views/other.str +0 -0
- data/spec/views/partial.erb +0 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b78f42bbcf1ea4018406b7fcf95f31c78ed1c4e
|
4
|
+
data.tar.gz: 3a86547b8e623c089ec67a1a45f65a4ce2b1554d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ff3c8bc993bffc2d5d94682fc53288a6293edfe94f9f7e9341efb08f6af71cd868cc6614541b286add86c2d0c2ff2c80021115957d088c7afc3bd1c8de075e6
|
7
|
+
data.tar.gz: e96714a418248738c3bb78d76bed6d8a41b28055bed3d1840bca2e2c1430bfb67960e8e5d6fcb6341dbec244bf06172cd2513d20c031c9fe950d311931a3ab9f
|
data/CHANGES.md
CHANGED
@@ -1,8 +1,18 @@
|
|
1
1
|
Changelog
|
2
2
|
=========
|
3
3
|
|
4
|
+
_Note that Scorched is yet to reach a v1.0 release. This means breaking changes may still be made. If upgrading Scorched version for your project, review this changelog carefully._
|
5
|
+
|
6
|
+
### v0.20
|
7
|
+
* _After_ filters are now still processed when a request is halted. This restores the original behaviour prior to version 0.8. This fixes an issue where halting the request after setting flash session data would cause the request to bomb-out.
|
8
|
+
* As an extension of the change above, filters can now be marked as _forced_ using the new `force` option, which if true, means the filter will run even if the request is halted within another filter (including within another forced filter). This ensures a particular filter is run for every request. This required changing the public interface for the _filter_ method. The sugar methods _before_, _after_, and _error_ have remained backwards compatible.
|
9
|
+
* Named captures are now passed to route proc's as a single hash argument. The previous behaviour was an oversight.
|
10
|
+
* Halting within an error filter is now swallowed if the error filter is invoked by an error raised in a before or after filter.
|
11
|
+
* The `controller` helper can now be used to map predefined controllers simply by omitting the block, which is now optional. This a more convenient means of mapping controllers as compared to the more barebones `map` method.
|
12
|
+
* `log` method now returns the log object. Method arguments are also now optional, meaning you can use the more natural logger interface if you prefer, e.g. `log.info "hello"`.
|
13
|
+
|
4
14
|
### v0.19
|
5
|
-
* The behaviour of wildcards
|
15
|
+
* The behaviour of wildcards `*` and `**` (and their _named_ equivalents) have been reverted to their original behaviour of matching one or more characters, instead of zero or more. This means `/*` will no longer match `/`. Adding a question mark directly after a wildcard will have that wildcard match zero or more character, instead of one or more. So the pattern `/*?` will match both `/` and `/about`.
|
6
16
|
|
7
17
|
### v0.18
|
8
18
|
* Redirects now use a 303 or 302 HTTP status code by default, depending on HTTP version (similar logic to Sinatra). Trailing slash redirects (triggered by :strip_trailing_slash) still uses a 307 status.
|
data/Gemfile
CHANGED
File without changes
|
data/LICENSE
CHANGED
File without changes
|
@@ -88,17 +88,10 @@ You can use nesting and inheritance exclusively, or together, depending on your
|
|
88
88
|
|
89
89
|
Controller Helper
|
90
90
|
-----------------
|
91
|
-
There is a more succinct way of defining sub-controllers, and that's with the `controller` helper. Here's the previous example re-written using the `controller` helper.
|
91
|
+
There is a more succinct way of mapping and defining sub-controllers, and that's with the `controller` helper. Here's the previous example cut-down and re-written using the `controller` helper.
|
92
92
|
|
93
93
|
``` ruby
|
94
94
|
class MyApp < Scorched::Controller
|
95
|
-
render_defaults[:dir] = 'views'
|
96
|
-
render_defaults[:layout] = :main
|
97
|
-
|
98
|
-
conditions[:user] = proc { |usernames|
|
99
|
-
[*usernames].include? 'bob'
|
100
|
-
}
|
101
|
-
|
102
95
|
get '/' do
|
103
96
|
bold "Hello there"
|
104
97
|
end
|
@@ -117,7 +110,7 @@ class MyApp < Scorched::Controller
|
|
117
110
|
end
|
118
111
|
```
|
119
112
|
|
120
|
-
The `controller` helper takes an optional URL pattern as it's first argument, an optional parent class as
|
113
|
+
The `controller` helper takes an optional URL pattern as it's first argument, an optional parent class as its second, and finally a mapping hash as its third optional argument, where you can define a priority, conditions, or override the URL pattern. Of course, the `controller` helper takes a block as well, which defines the body of the new controller class.
|
121
114
|
|
122
115
|
The optional URL pattern defaults to `'/'` which means it's essentially a match-all mapping. In addition, the generated controller has `:auto_pass` set to `true` by default (refer to configuration documentation for more information). This is a handy combination for grouping a set of routes in their own scope, with their own methods, filters, configuration, etc.
|
123
116
|
|
@@ -153,6 +146,18 @@ end
|
|
153
146
|
|
154
147
|
That example, while serving no practical purpose, hopefully demonstrates how you can combine various constructs with sub-controllers, to come up with DRY creative solutions.
|
155
148
|
|
149
|
+
Finally, the `controller` helper can also be used a shortcut to map one controller to another, where the given class is mapped directly, instead of being the parent of a new controller class. These two examples are essentially equivalent:
|
150
|
+
|
151
|
+
``` ruby
|
152
|
+
ControllerA << {pattern: '/sub', target: ControllerB}
|
153
|
+
|
154
|
+
# Or
|
155
|
+
|
156
|
+
class ControllerA
|
157
|
+
controller '/', ControllerB # Note that no block was given
|
158
|
+
end
|
159
|
+
```
|
160
|
+
|
156
161
|
|
157
162
|
The Root Controller
|
158
163
|
-------------------
|
@@ -20,9 +20,9 @@ Halting Requests
|
|
20
20
|
----------------
|
21
21
|
There may be instances we're you want to shortcut out-of processing the current request. The `halt` method allows you to do this, though it's worth clarifying its behaviour.
|
22
22
|
|
23
|
-
When `halt` is called within a route, it simply
|
23
|
+
When `halt` is called within a route, it simply exits out of that route, and begins processing any _after_ filters. Halt can also be used within a _before_ or _after_ filter, in which case any remaining filters in the current controller are skipped, with the exception of _forced_ filters (see documentation on filters).
|
24
24
|
|
25
|
-
Calls to `halt` don't propagate up the controller chain. They're
|
25
|
+
Calls to `halt` don't propagate up the controller chain. They're caught within the controller they're thrown. A call to `halt` is equivalent to doing a manual `throw :halt`. Calling `halt` is often preferred though because as well as being syntactically sweeter, it can take an optional argument to set the response status and body, which is something you likely want to do when halting a request.
|
26
26
|
|
27
27
|
|
28
28
|
Passing Requests
|
@@ -11,7 +11,7 @@ Before and After filters allow pre- and post-processing of requests. They are ex
|
|
11
11
|
|
12
12
|
```ruby
|
13
13
|
before do
|
14
|
-
raise
|
14
|
+
raise "Must be logged in to access this site" unless session[:logged_in] == true
|
15
15
|
end
|
16
16
|
```
|
17
17
|
|
@@ -31,7 +31,15 @@ after status: 404 do
|
|
31
31
|
end
|
32
32
|
```
|
33
33
|
|
34
|
-
|
34
|
+
An optional _force_ option exists which ensures the filter is always run, even if another filter halts the request.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
after force: true do
|
38
|
+
# Close open file handles or something
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
How you use filters is up to your own imagination and creative problem solving.
|
35
43
|
|
36
44
|
|
37
45
|
Error Filters
|
@@ -40,10 +48,10 @@ Error filters are processed like regular filters, except they're called whenever
|
|
40
48
|
|
41
49
|
Error filters can handle exceptions raised from within the request target, as well as those raised within _before_ and _after_ filters. The way error filters have been implemented, allows exceptions raised within the request target to be handled before running the _after_ filters. This means that _after_ filters are still run as long as exceptions that occurred within the request target are handled.
|
42
50
|
|
43
|
-
Error filters can target only specific types of exception class, in much the same way as a typical Ruby rescue block.
|
51
|
+
Error filters can target only specific types of exception class, in much the same way as a typical Ruby rescue block. In the following example, the error filter is only executed when an uncaught PermissionError exception is raised, and when a made-up `catch_exceptions` condition evaluates to true.
|
44
52
|
|
45
53
|
```ruby
|
46
|
-
error PermissionError do |e|
|
54
|
+
error PermissionError, catch_exceptions: true do |e|
|
47
55
|
flash[:error] = "You do not have the appropriate permission to perform that action: #{e.message}"
|
48
56
|
end
|
49
57
|
```
|
@@ -21,4 +21,11 @@ When a layout is given, a subsequent call to `render` is made, with the rendered
|
|
21
21
|
|
22
22
|
Partials
|
23
23
|
--------
|
24
|
-
There are cases where you may want a view to be composed of more than just a layout and a single view. The view may contain one or more sub-views, commonly referred to as partials. Scorched makes provisions for this by ignoring the default layout when `render` is called within a view, hence negating the requirement to explicitly override the layout.
|
24
|
+
There are cases where you may want a view to be composed of more than just a layout and a single view. The view may contain one or more sub-views, commonly referred to as partials. Scorched makes provisions for this by ignoring the default layout when `render` is called within a view, hence negating the requirement to explicitly override the layout.
|
25
|
+
|
26
|
+
Helpers
|
27
|
+
-------
|
28
|
+
No explicit distinction is made between a controller helper and a view helper, as both share the same context. There are however some helper methods intended primarily for views.
|
29
|
+
|
30
|
+
* `absolute` - Returns the absolute URL of the web application root, with the optional argument joined to the end. For example, if you're application was mounted under example.com/myapp/: `absolute '/about' #=> /myapp/about`
|
31
|
+
* `url` - Same as absolute, except returns the full URL, e.g. `url '/about' #=> http://example.com/myapp/about`.
|
data/lib/scorched/controller.rb
CHANGED
@@ -15,7 +15,7 @@ module Scorched
|
|
15
15
|
config << {
|
16
16
|
:auto_pass => false, # Automatically _pass_ request back to outer controller if no route matches.
|
17
17
|
:cache_templates => true,
|
18
|
-
:logger =>
|
18
|
+
:logger => Logger.new(STDOUT),
|
19
19
|
:show_exceptions => false,
|
20
20
|
:show_http_error_pages => false, # If true, shows the default Scorched HTTP error page.
|
21
21
|
:static_dir => false, # The directory Scorched should serve static files from. Set to false if web server or anything else is serving static files.
|
@@ -32,7 +32,6 @@ module Scorched
|
|
32
32
|
}
|
33
33
|
|
34
34
|
if ENV['RACK_ENV'] == 'development'
|
35
|
-
config[:logger] = Logger.new(STDOUT)
|
36
35
|
config[:show_exceptions] = true
|
37
36
|
config[:static_dir] = 'public'
|
38
37
|
config[:cache_templates] = false
|
@@ -136,20 +135,19 @@ module Scorched
|
|
136
135
|
end
|
137
136
|
alias :<< :map
|
138
137
|
|
139
|
-
#
|
140
|
-
# hash if one is provided. Returns the new anonymous controller class.
|
138
|
+
# Maps a new ad-hoc or predefined controller.
|
141
139
|
#
|
142
|
-
#
|
143
|
-
#
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
self << {pattern: pattern, target:
|
152
|
-
|
140
|
+
# If a block is given, creates a new controller as a sub-class of _klass_ (_self_ by default), otherwise maps
|
141
|
+
# _klass_ itself. Returns the new anonymous controller class if a block is given, or _klass_ otherwise.
|
142
|
+
def controller(pattern = '/', klass = self, **mapping, &block)
|
143
|
+
if block_given?
|
144
|
+
controller = Class.new(klass, &block)
|
145
|
+
controller.config[:auto_pass] = true if klass < Scorched::Controller
|
146
|
+
else
|
147
|
+
controller = klass
|
148
|
+
end
|
149
|
+
self << {pattern: pattern, target: controller}.merge(mapping)
|
150
|
+
controller
|
153
151
|
end
|
154
152
|
|
155
153
|
# Generates and returns a new route proc from the given block, and optionally maps said proc using the given args.
|
@@ -167,7 +165,7 @@ module Scorched
|
|
167
165
|
# patch(pattern = nil, priority = nil, **conds, &block)
|
168
166
|
def route(pattern = nil, priority = nil, **conds, &block)
|
169
167
|
target = lambda do
|
170
|
-
response.body = instance_exec(*request.captures, &block)
|
168
|
+
response.body = instance_exec(*[request.captures].flatten, &block)
|
171
169
|
response
|
172
170
|
end
|
173
171
|
[*pattern].compact.each do |pattern|
|
@@ -184,22 +182,31 @@ module Scorched
|
|
184
182
|
end
|
185
183
|
end
|
186
184
|
|
187
|
-
# Defines a filter of +type+.
|
188
|
-
# +args+ is used internally by Scorched for passing additional arguments to
|
189
|
-
# the case of error
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
# after(*args, **conds, &block)
|
194
|
-
# error(*args, **conds, &block)
|
195
|
-
def filter(type, *args, **conds, &block)
|
196
|
-
filters[type.to_sym] << {args: args, conditions: conds, proc: block}
|
185
|
+
# Defines a filter of +type+.
|
186
|
+
# +args+ is used internally by Scorched for passing additional arguments to some filters, such as the exception in
|
187
|
+
# the case of error filters.
|
188
|
+
def filter(type, args: nil, force: nil, conditions: nil, **more_conditions, &block)
|
189
|
+
more_conditions.merge!(conditions || {})
|
190
|
+
filters[type.to_sym] << {args: args, force: force, conditions: more_conditions, proc: block}
|
197
191
|
end
|
198
192
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
193
|
+
# Syntactic sugar for defining a before filter.
|
194
|
+
# If +force+ is true, the filter is run even if another filter halts the request.
|
195
|
+
def before(force: false, **conditions, &block)
|
196
|
+
filter(:before, force: force, conditions: conditions, &block)
|
197
|
+
end
|
198
|
+
|
199
|
+
# Syntactic sugar for defining an after filter.
|
200
|
+
# If +force+ is true, the filter is run even if another filter halts the request.
|
201
|
+
def after(force: false, **conditions, &block)
|
202
|
+
filter(:after, force: force, conditions: conditions, &block)
|
203
|
+
end
|
204
|
+
|
205
|
+
# Syntactic sugar for defining an error filter.
|
206
|
+
# Takes one or more optional exception classes for which this error filter should handle. Handles all exceptions
|
207
|
+
# by default.
|
208
|
+
def error(*classes, **conditions, &block)
|
209
|
+
filter(:error, args: classes, conditions: conditions, &block)
|
203
210
|
end
|
204
211
|
|
205
212
|
private
|
@@ -211,7 +218,7 @@ module Scorched
|
|
211
218
|
return pattern if Regexp === pattern
|
212
219
|
raise Error, "Can't compile URL of type #{pattern.class}. Must be String or Regexp." unless String === pattern
|
213
220
|
match_to_end = !!pattern.sub!(/\$$/, '') || match_to_end
|
214
|
-
|
221
|
+
compiled = pattern.split(%r{(\*{1,2}\??|(?<!\\):{1,2}[^/*$]+\??)}).each_slice(2).map { |unmatched, match|
|
215
222
|
Regexp.escape(unmatched) << begin
|
216
223
|
op = (match && match[-1] == '?' && match.chomp!('?')) ? '*' : '+'
|
217
224
|
if %w{* **}.include? match
|
@@ -223,8 +230,8 @@ module Scorched
|
|
223
230
|
end
|
224
231
|
end
|
225
232
|
}.join
|
226
|
-
|
227
|
-
Regexp.new(
|
233
|
+
compiled << '$' if match_to_end
|
234
|
+
Regexp.new(compiled)
|
228
235
|
end
|
229
236
|
end
|
230
237
|
|
@@ -245,13 +252,14 @@ module Scorched
|
|
245
252
|
@response = Response.new
|
246
253
|
end
|
247
254
|
|
255
|
+
# This is where the magic happens.
|
248
256
|
def action
|
249
257
|
inner_error = nil
|
250
258
|
rescue_block = proc do |e|
|
251
259
|
raise unless filters[:error].any? do |f|
|
252
|
-
|
253
|
-
|
254
|
-
|
260
|
+
if !f[:args] || f[:args].empty? || f[:args].any? { |type| e.is_a?(type) }
|
261
|
+
instance_exec(e, &f[:proc]) unless check_for_failed_condition(f[:conditions])
|
262
|
+
end
|
255
263
|
end
|
256
264
|
end
|
257
265
|
|
@@ -273,22 +281,25 @@ module Scorched
|
|
273
281
|
}.max || 0,
|
274
282
|
-idx
|
275
283
|
]
|
276
|
-
}.reverse.each { |match
|
284
|
+
}.reverse.each { |match,idx|
|
277
285
|
request.breadcrumb << match
|
278
|
-
|
286
|
+
catch(:pass) {
|
279
287
|
target = match.mapping[:target]
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
+
catch(:halt) do
|
289
|
+
response.merge! begin
|
290
|
+
if Proc === target
|
291
|
+
instance_exec(&target)
|
292
|
+
else
|
293
|
+
target.call(env.merge(
|
294
|
+
'SCRIPT_NAME' => request.matched_path.chomp('/'),
|
295
|
+
'PATH_INFO' => request.unmatched_path[match.path.chomp('/').length..-1]
|
296
|
+
))
|
297
|
+
end
|
288
298
|
end
|
289
299
|
end
|
290
300
|
@_handled = true
|
291
301
|
}
|
302
|
+
break if @_handled
|
292
303
|
request.breadcrumb.pop
|
293
304
|
}
|
294
305
|
unless @_handled
|
@@ -298,9 +309,13 @@ module Scorched
|
|
298
309
|
rescue_block.call(inner_error)
|
299
310
|
end
|
300
311
|
run_filters(:after)
|
312
|
+
true
|
313
|
+
end || begin
|
314
|
+
run_filters(:before, true)
|
315
|
+
run_filters(:after, true)
|
301
316
|
end
|
302
317
|
rescue => outer_error
|
303
|
-
outer_error == inner_error ? raise : rescue_block.call(outer_error)
|
318
|
+
outer_error == inner_error ? raise : catch(:halt) { rescue_block.call(outer_error) }
|
304
319
|
end
|
305
320
|
response.finish
|
306
321
|
end
|
@@ -388,7 +403,7 @@ module Scorched
|
|
388
403
|
session[key]
|
389
404
|
end
|
390
405
|
|
391
|
-
after do
|
406
|
+
after(force: true) do
|
392
407
|
env['scorched.flash'].each { |k,v| session[k] = v } if session && env['scorched.flash']
|
393
408
|
end
|
394
409
|
|
@@ -527,20 +542,29 @@ module Scorched
|
|
527
542
|
|
528
543
|
private
|
529
544
|
|
530
|
-
def run_filters(type)
|
545
|
+
def run_filters(type, forced_only = false)
|
531
546
|
tracker = env['scorched.executed_filters'] ||= {before: Set.new, after: Set.new}
|
532
|
-
filters[type].reject{ |f| tracker[type].include? f }.each do |f|
|
547
|
+
filters[type].reject{ |f| tracker[type].include?(f) || (forced_only && !f[:force]) }.each do |f|
|
533
548
|
unless check_for_failed_condition(f[:conditions])
|
534
549
|
tracker[type] << f
|
535
|
-
|
550
|
+
if forced_only
|
551
|
+
catch(:halt) do
|
552
|
+
instance_exec(&f[:proc]); true
|
553
|
+
end or log.warn "Ignored halt while running forced filters."
|
554
|
+
else
|
555
|
+
instance_exec(&f[:proc])
|
556
|
+
end
|
536
557
|
end
|
537
558
|
end
|
538
559
|
end
|
539
560
|
|
540
|
-
def log(type, message)
|
561
|
+
def log(type = nil, message = nil)
|
541
562
|
config[:logger].progname ||= 'Scorched'
|
542
|
-
|
543
|
-
|
563
|
+
if(type)
|
564
|
+
type = Logger.const_get(type.to_s.upcase)
|
565
|
+
config[:logger].add(type, message)
|
566
|
+
end
|
567
|
+
config[:logger]
|
544
568
|
end
|
545
569
|
end
|
546
570
|
end
|
File without changes
|
data/lib/scorched/error.rb
CHANGED
File without changes
|
data/lib/scorched/static.rb
CHANGED
data/lib/scorched/version.rb
CHANGED
data/spec/controller_spec.rb
CHANGED
@@ -270,6 +270,16 @@ module Scorched
|
|
270
270
|
end
|
271
271
|
end
|
272
272
|
|
273
|
+
it "provides wildcard captures as arguments" do
|
274
|
+
app.get('/*/**') { |a,b| "#{a}#{b}" }
|
275
|
+
rt.get('/hello/there/dude').body.should == 'hellothere/dude'
|
276
|
+
end
|
277
|
+
|
278
|
+
it "provides named captures as a single hash argument" do
|
279
|
+
app.get('/:given_name/::surname') { |h| "#{h[:given_name]} #{h[:surname]}" }
|
280
|
+
rt.get('/bob/smith').body.should == 'bob smith'
|
281
|
+
end
|
282
|
+
|
273
283
|
it "always matches to the end of the URL (implied $)" do
|
274
284
|
app.get('/') { 'awesome '}
|
275
285
|
rt.get('/dog').status.should == 404
|
@@ -352,9 +362,9 @@ module Scorched
|
|
352
362
|
response.body.should == 'roof'
|
353
363
|
end
|
354
364
|
|
355
|
-
it "inherits from parent class, or
|
356
|
-
app.controller.superclass.should == app
|
357
|
-
app.controller('/', String).superclass.should == String
|
365
|
+
it "inherits from parent class, or otherwise the specified class" do
|
366
|
+
app.controller{}.superclass.should == app
|
367
|
+
app.controller('/', String){}.superclass.should == String
|
358
368
|
end
|
359
369
|
|
360
370
|
it "can take mapping options" do
|
@@ -377,6 +387,14 @@ module Scorched
|
|
377
387
|
rt.get('/').body.should == 'hello'
|
378
388
|
filters_run.should == 0
|
379
389
|
end
|
390
|
+
|
391
|
+
it "can be used to map a predefined controller" do
|
392
|
+
person_controller = Class.new(Scorched::Controller) do
|
393
|
+
get('/name') { 'George' }
|
394
|
+
end
|
395
|
+
app.controller '/person', person_controller
|
396
|
+
rt.get('/person/name').body.should == 'George'
|
397
|
+
end
|
380
398
|
end
|
381
399
|
end
|
382
400
|
|
@@ -547,6 +565,12 @@ module Scorched
|
|
547
565
|
rt.get('/').body.should == 'StandardErrorArgumentError'
|
548
566
|
end
|
549
567
|
|
568
|
+
they "swallow halts when executed in an outer context" do
|
569
|
+
app.before { raise "Big bad error" }
|
570
|
+
app.error { throw :halt }
|
571
|
+
rt.get('/') # Would otherwise bomb out with uncaught throw.
|
572
|
+
end
|
573
|
+
|
550
574
|
they "only get called once per error" do
|
551
575
|
times_called = 0
|
552
576
|
app.error { times_called += 1 }
|
@@ -621,8 +645,8 @@ module Scorched
|
|
621
645
|
end
|
622
646
|
|
623
647
|
it "takes an optional status" do
|
624
|
-
app.get('/') { halt
|
625
|
-
rt.get('/').status.should ==
|
648
|
+
app.get('/') { halt 600 }
|
649
|
+
rt.get('/').status.should == 600
|
626
650
|
end
|
627
651
|
|
628
652
|
it "takes an optional response body" do
|
@@ -631,21 +655,41 @@ module Scorched
|
|
631
655
|
end
|
632
656
|
|
633
657
|
it "can take a status and a response body" do
|
634
|
-
app.get('/') { halt
|
635
|
-
rt.get('/').status.should ==
|
658
|
+
app.get('/') { halt 600, 'cool' }
|
659
|
+
rt.get('/').status.should == 600
|
636
660
|
rt.get('/').body.should == 'cool'
|
637
661
|
end
|
638
662
|
|
639
|
-
it "
|
640
|
-
app.after { response.status =
|
663
|
+
it "still processes filters" do
|
664
|
+
app.after { response.status = 600 }
|
641
665
|
app.get('/') { halt }
|
642
|
-
rt.get('/').status.should ==
|
666
|
+
rt.get('/').status.should == 600
|
643
667
|
end
|
644
668
|
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
669
|
+
describe "within filters" do
|
670
|
+
it "short circuits filters if halted within filter" do
|
671
|
+
app.before { halt }
|
672
|
+
app.after { response.status = 600 }
|
673
|
+
rt.get('/').status.should_not == 600
|
674
|
+
end
|
675
|
+
|
676
|
+
it "forced filters are always run" do
|
677
|
+
app.before { halt }
|
678
|
+
app.after(force: true) { response.status = 600 }
|
679
|
+
app.after { response.status = 700 } # Shouldn't run because it's not forced
|
680
|
+
app.get('/') { 'hello' }
|
681
|
+
rt.get('/').status.should == 600
|
682
|
+
end
|
683
|
+
|
684
|
+
it "halting within a forced filter still runs other forced filters" do
|
685
|
+
app.before { halt }
|
686
|
+
app.before(force: true) { halt }
|
687
|
+
app.before(force: true) { response.status = 600 }
|
688
|
+
app.get('/') { 'hello' }
|
689
|
+
rt.get('/').status.should == 600
|
690
|
+
app.after(force: true) { response.status = 700 }
|
691
|
+
rt.get('/').status.should == 700
|
692
|
+
end
|
649
693
|
end
|
650
694
|
end
|
651
695
|
|
@@ -674,6 +718,14 @@ module Scorched
|
|
674
718
|
rt.get('/')
|
675
719
|
var.should == false
|
676
720
|
end
|
721
|
+
|
722
|
+
it "works in filters" do
|
723
|
+
app.error { redirect '/somewhere' }
|
724
|
+
app.get('/') { raise "Some error" }
|
725
|
+
rt.get('/').location.should == '/somewhere'
|
726
|
+
app.before { redirect '/somewhere_else' }
|
727
|
+
rt.get('/').location.should == '/somewhere_else'
|
728
|
+
end
|
677
729
|
end
|
678
730
|
|
679
731
|
describe "passing" do
|
data/spec/helper.rb
CHANGED
data/spec/options_spec.rb
CHANGED
File without changes
|
data/spec/public/static.txt
CHANGED
File without changes
|
data/spec/request_spec.rb
CHANGED
File without changes
|
data/spec/views/composer.erb
CHANGED
File without changes
|
data/spec/views/layout.erb
CHANGED
File without changes
|
data/spec/views/main.erb
CHANGED
File without changes
|
data/spec/views/other.str
CHANGED
File without changes
|
data/spec/views/partial.erb
CHANGED
File without changes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scorched
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.20'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tom Wardrop
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-12-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -172,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
172
172
|
version: '0'
|
173
173
|
requirements: []
|
174
174
|
rubyforge_project:
|
175
|
-
rubygems_version: 2.0.
|
175
|
+
rubygems_version: 2.0.6
|
176
176
|
signing_key:
|
177
177
|
specification_version: 4
|
178
178
|
summary: Light-weight, DRY as a desert, web framework for Ruby
|