diff --git a/language/fixtures/rescue.rb b/language/fixtures/rescue.rb index b906e17a2f..7e3e4240c2 100644 --- a/language/fixtures/rescue.rb +++ b/language/fixtures/rescue.rb @@ -1,4 +1,108 @@ module RescueSpecs + class ClassVariableCaptor + def capture(msg) + raise msg + rescue => @@captured_error + :caught + end + + def captured_error + self.class.remove_class_variable(:@@captured_error) + end + end + + class ConstantCaptor + # Using lambda gets around the dynamic constant assignment warning + CAPTURE = -> msg { + begin + raise msg + rescue => CapturedError + :caught + end + } + + def capture(msg) + CAPTURE.call(msg) + end + + def captured_error + self.class.send(:remove_const, :CapturedError) + end + end + + class GlobalVariableCaptor + def capture(msg) + raise msg + rescue => $captured_error + :caught + end + + def captured_error + $captured_error.tap do + $captured_error = nil # Can't remove globals, only nil them out + end + end + end + + class InstanceVariableCaptor + attr_reader :captured_error + + def capture(msg) + raise msg + rescue => @captured_error + :caught + end + end + + class LocalVariableCaptor + attr_reader :captured_error + + def capture(msg) + raise msg + rescue => captured_error + @captured_error = captured_error + :caught + end + end + + class SafeNavigationSetterCaptor + attr_accessor :captured_error + + def capture(msg) + raise msg + rescue => self&.captured_error + :caught + end + end + + class SetterCaptor + attr_accessor :captured_error + + def capture(msg) + raise msg + rescue => self.captured_error + :caught + end + end + + class SquareBracketsCaptor + def capture(msg) + @hash = {} + + raise msg + rescue => self[:error] + :caught + end + + def []=(key, value) + @hash[key] = value + end + + def captured_error + @hash[:error] + end + end + def self.begin_else(raise_exception) begin ScratchPad << :one diff --git a/language/rescue_spec.rb b/language/rescue_spec.rb index 7fa674d009..a6afd4981c 100644 --- a/language/rescue_spec.rb +++ b/language/rescue_spec.rb @@ -23,11 +23,22 @@ class ArbitraryException < StandardError end.should == :caught end - it "can capture the raised exception in a local variable" do - begin - raise SpecificExampleException, "some text" - rescue SpecificExampleException => e - e.message.should == "some text" + { + # Standard use case + 'can capture the raised exception in a local variable' => RescueSpecs::LocalVariableCaptor, + # Exotic use cases + 'can capture the raised exception in a class variable' => RescueSpecs::ClassVariableCaptor, + 'can capture the raised exception in a constant' => RescueSpecs::ConstantCaptor, + 'can capture the raised exception in a global variable' => RescueSpecs::GlobalVariableCaptor, + 'can capture the raised exception in an instance variable' => RescueSpecs::InstanceVariableCaptor, + 'can capture the raised exception using a safely navigated setter method' => RescueSpecs::SafeNavigationSetterCaptor, + 'can capture the raised exception using a setter method' => RescueSpecs::SetterCaptor, + 'can capture the raised exception using a square brackets setter' => RescueSpecs::SquareBracketsCaptor, + }.each do |description, klass| + it description do + captor = klass.new + captor.capture('some text').should == :caught # Ensure rescue body still runs + captor.captured_error.message.should == 'some text' end end