handle loops in the cause chain in Rescuable#rescue_with_handler
This commit is contained in:
parent
8b69e32412
commit
4fc2ea1181
@ -84,12 +84,18 @@ def rescue_from(*klasses, with: nil, &block)
|
|||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# Returns the exception if it was handled and +nil+ if it was not.
|
# Returns the exception if it was handled and +nil+ if it was not.
|
||||||
def rescue_with_handler(exception, object: self)
|
def rescue_with_handler(exception, object: self, visited_exceptions: [])
|
||||||
|
visited_exceptions << exception
|
||||||
|
|
||||||
if handler = handler_for_rescue(exception, object: object)
|
if handler = handler_for_rescue(exception, object: object)
|
||||||
handler.call exception
|
handler.call exception
|
||||||
exception
|
exception
|
||||||
elsif exception
|
elsif exception
|
||||||
rescue_with_handler(exception.cause, object: object)
|
if visited_exceptions.include?(exception.cause)
|
||||||
|
nil
|
||||||
|
else
|
||||||
|
rescue_with_handler(exception.cause, object: object, visited_exceptions: visited_exceptions)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -43,7 +43,9 @@ class NuclearExplosion < StandardError; end
|
|||||||
def dispatch(method)
|
def dispatch(method)
|
||||||
send(method)
|
send(method)
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
rescue_with_handler(e)
|
unless rescue_with_handler(e)
|
||||||
|
@result = "unhandled"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def attack
|
def attack
|
||||||
@ -58,6 +60,26 @@ def ronanize
|
|||||||
raise MadRonon.new("dex")
|
raise MadRonon.new("dex")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def crash
|
||||||
|
raise "unhandled RuntimeError"
|
||||||
|
end
|
||||||
|
|
||||||
|
def looped_crash
|
||||||
|
ex1 = StandardError.new("error 1")
|
||||||
|
ex2 = StandardError.new("error 2")
|
||||||
|
begin
|
||||||
|
begin
|
||||||
|
raise ex1
|
||||||
|
rescue
|
||||||
|
# sets the cause on ex2 to be ex1
|
||||||
|
raise ex2
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
# sets the cause on ex1 to be ex2
|
||||||
|
raise ex1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def fall_back_to_cause
|
def fall_back_to_cause
|
||||||
# This exception is the cause and has a handler.
|
# This exception is the cause and has a handler.
|
||||||
ronanize
|
ronanize
|
||||||
@ -139,4 +161,14 @@ def test_rescue_falls_back_to_exception_cause
|
|||||||
@stargate.dispatch :fall_back_to_cause
|
@stargate.dispatch :fall_back_to_cause
|
||||||
assert_equal "dex", @stargate.result
|
assert_equal "dex", @stargate.result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_unhandled_exceptions
|
||||||
|
@stargate.dispatch(:crash)
|
||||||
|
assert_equal "unhandled", @stargate.result
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_rescue_handles_loops_in_exception_cause_chain
|
||||||
|
@stargate.dispatch :looped_crash
|
||||||
|
assert_equal "unhandled", @stargate.result
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user