Issue #467 Make #pass Behave as Expected in Error Blocks #506

Merged
merged 1 commit into from Apr 26, 2012
View
@@ -989,9 +989,13 @@ def handle_exception!(boom)
def error_block!(key, *block_params)
base = settings
while base.respond_to?(:errors)
- next base = base.superclass unless args = base.errors[key]
- args += [block_params]
- return process_route(*args)
+ next base = base.superclass unless args_array = base.errors[key]
+ args_array.reverse_each do |args|
+ first = args == args_array.first
+ args += [block_params]
+ resp = process_route(*args)
+ return resp unless resp.nil? && !first
+ end
end
return false unless key.respond_to? :superclass and key.superclass < Exception
error_block!(key.superclass, *block_params)
@@ -1091,11 +1095,11 @@ def disable(*opts)
# Define a custom error handler. Optionally takes either an Exception
# class, or an HTTP status code to specify which errors should be
# handled.
- def error(*codes, &block)
+ def error(*codes, &block)
args = compile! "ERROR", //, block
codes = codes.map { |c| Array(c) }.flatten
codes << Exception if codes.empty?
- codes.each { |c| @errors[c] = args }
+ codes.each { |c| (@errors[c] ||= []) << args }
end
# Sugar for `error(404) { ... }`
@@ -14,6 +14,8 @@ class FooStatusOutOfRangeError < RuntimeError
def code; 4000 end
end
+class FirstError < RuntimeError; end
+class SecondError < RuntimeError; end
class MappedErrorTest < Test::Unit::TestCase
def test_default
@@ -207,6 +209,41 @@ def test_default
assert_equal 500, status
end
+ it "allows a stack of exception_handlers" do
+ mock_app {
+ set :raise_errors, false
+ error(FirstError) { 'First!' }
+ error(SecondError) { 'Second!' }
+ get('/'){ raise SecondError }
+ }
+ get '/'
+ assert_equal 500, status
+ assert_equal 'Second!', body
+ end
+
+ it "allows an exception handler to pass control to the next exception handler" do
+ mock_app {
+ set :raise_errors, false
+ error(500, FirstError) { 'First!' }
+ error(500, SecondError) { pass }
+ get('/') { raise 500 }
+ }
+ get '/'
+ assert_equal 500, status
+ assert_equal 'First!', body
+ end
+
+ it "allows an exception handler to handle the exception" do
+ mock_app {
+ set :raise_errors, false
+ error(500, FirstError) { 'First!' }
+ error(500, SecondError) { 'Second!' }
+ get('/') { raise 500 }
+ }
+ get '/'
+ assert_equal 500, status
+ assert_equal 'Second!', body
+ end
end
describe 'Custom Error Pages' do