diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 912b0287af9fddf0cb9c4b408158a0f2ad3e8cff..3f340958ea6a4291e1531d3eb9e0e28d1c3761da 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,19 @@ +* Added support for error dispatcher classes in ActiveSupport::Rescuable. Now it acts closer to Ruby's rescue. + + class BaseController < ApplicationController + module ErrorDispatcher + def self.===(other) + Exception === other && other.respond_to?(:status) + end + end + + rescue_from ErrorDispatcher do |error| + render status: error.status, json: { error: error.to_s } + end + end + + *Genadi Samokovarov* + * Added `#verified` and `#valid_message?` methods to `ActiveSupport::MessageVerifier` Previously, the only way to decode a message with `ActiveSupport::MessageVerifier` was to use `#verify`, which would raise an exception on invalid messages. Now `#verified` can also be used, which returns `nil` on messages that cannot be decoded. diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb index a7eba91ac52910ba9cfdf4e55f0f5f2b5fae24c2..1a02acd5b1d3b3d641703d3c618f83c940284508 100644 --- a/activesupport/lib/active_support/rescuable.rb +++ b/activesupport/lib/active_support/rescuable.rb @@ -60,7 +60,7 @@ def rescue_from(*klasses, &block) end klasses.each do |klass| - key = if klass.is_a?(Class) && klass <= Exception + key = if klass.is_a?(Module) && klass.respond_to?(:===) klass.name elsif klass.is_a?(String) klass @@ -101,7 +101,7 @@ def handler_for_rescue(exception) # itself when rescue_from CONSTANT is executed. klass = self.class.const_get(klass_name) rescue nil klass ||= klass_name.constantize rescue nil - exception.is_a?(klass) if klass + klass === exception if klass end case rescuer diff --git a/activesupport/test/rescuable_test.rb b/activesupport/test/rescuable_test.rb index b8af888f7c1e1b8fc83f2485adb85618b4bf8c8d..bd43ad07978e2853174b26704740376bb91dfdb9 100644 --- a/activesupport/test/rescuable_test.rb +++ b/activesupport/test/rescuable_test.rb @@ -12,6 +12,12 @@ class MadRonon < StandardError class CoolError < StandardError end +module WeirdError + def self.===(other) + Exception === other && other.respond_to?(:weird?) + end +end + class Stargate attr_accessor :result @@ -29,6 +35,10 @@ class Stargate @result = e.message end + rescue_from WeirdError do + @result = 'weird' + end + def dispatch(method) send(method) rescue Exception => e @@ -47,6 +57,16 @@ def ronanize raise MadRonon.new("dex") end + def weird + StandardError.new.tap do |exc| + def exc.weird? + true + end + + raise exc + end + end + def sos @result = 'killed' end @@ -91,14 +111,19 @@ def test_rescue_from_with_block_with_args assert_equal 'dex', @stargate.result end + def test_rescue_from_error_dispatchers_with_case_operator + @stargate.dispatch :weird + assert_equal 'weird', @stargate.result + end + def test_rescues_defined_later_are_added_at_end_of_the_rescue_handlers_array - expected = ["WraithAttack", "WraithAttack", "NuclearExplosion", "MadRonon"] + expected = ["WraithAttack", "WraithAttack", "NuclearExplosion", "MadRonon", "WeirdError"] result = @stargate.send(:rescue_handlers).collect(&:first) assert_equal expected, result end def test_children_should_inherit_rescue_definitions_from_parents_and_child_rescue_should_be_appended - expected = ["WraithAttack", "WraithAttack", "NuclearExplosion", "MadRonon", "CoolError"] + expected = ["WraithAttack", "WraithAttack", "NuclearExplosion", "MadRonon", "WeirdError", "CoolError"] result = @cool_stargate.send(:rescue_handlers).collect(&:first) assert_equal expected, result end