rescue that calls a method with a rescue - ruby

This only prints rescue 1, is there a way to print both rescue 1 and rescue 2?
def mimiti
raise 'hi there!'
rescue
puts 'rescue 1'
end
begin
mimiti
rescue
puts 'rescue 2'
end

Yes, you can re-raise an exception after catching and handling it:
def mimiti
raise 'hi there!'
rescue StandardError => e
puts 'rescue 1'
raise e
end

Related

Rescue NameError but not NoMethodError

I need to catch a NameError in a special case. But I don't want to catch all SubClasses of NameError. Is there a way to achieve this?
# This shall be catched
begin
String::NotExistend.new
rescue NameError
puts 'Will do something with this error'
end
# This shall not be catched
begin
# Will raise a NoMethodError but I don't want this Error to be catched
String.myattribute = 'value'
rescue NameError
puts 'Should never be called'
end
You can also do it in a more traditional way
begin
# your code goes here
rescue NoMethodError
raise
rescue NameError
puts 'Will do something with this error'
end
You can re-raise exception if its class is different than a given:
begin
# your code goes here
rescue NameError => exception
# note that `exception.kind_of?` will not work as expected here
raise unless exception.class.eql?(NameError)
# handle `NameError` exception here
end
You can also check the exception message and decide what to do.
Here is an example using the code you provided.
# This shall be catched
begin
String::NotExistend.new
rescue NameError => e
if e.message['String::NotExistend']
puts 'Will do something with this error'
else
raise
end
end
# This shall not be catched
begin
# Will raise a NoMethodError but I don't want this Error to be catched
String.myattribute = 'value'
rescue NameError => e
if e.message['String::NotExistend']
puts 'Should never be called'
else
raise
end
end

Accessing Error Messages within a Rescue Block

Is there any way to get access to an error message in a rescue block as a string? For example:
def foo
raise RuntimeError, "This is an error"
end
def bar
begin
foo
rescue RuntimeError
puts "Rescued"
end
end
bar
Is there any way to gain access to "This is an error" from with-in the rescue block? Something like this:
...
rescue RuntimeError
puts <error-message>
end
...
You need to specify a variable to store the error in
def foo
raise RuntimeError, "This is an error"
end
def bar
begin
foo
rescue RuntimeError => ex
puts "Rescued #{ex.message}"
end
end

How to get the reference alive to the older one, when there is a second exception in Ruby?

begin
raise "explosion"
rescue
p $!
raise "Are you mad"
p $!
end
# #<RuntimeError: explosion>
# RuntimeError: Are you mad
# from (irb):5:in `rescue in irb_binding'
# from (irb):1
# from /usr/bin/irb:12:in `<main>'
$! always holds only the current exception object reference.
But is there any way to get a reference to the original exception object (here it is "explosion"), after another exception has been raised? <~~~ Here is my question.
Myself tried and reached to the answer,hope now it is more clearer to all who was in Smokey situation with my queries.
Are you saying you want to have reference to the original exception when you rescue the second exception? If so, then you need to capture the original exception in a variable during the rescue. This is done by doing:
rescue StandardError => e
where StandardError can be any type of exception or omitted (in which case StandardError is the default).
For example, the code:
begin
raise "original exception"
rescue StandardError => e
puts "Original Exception:"
puts $!
puts e
begin
raise "second exception"
rescue
puts "Second Exception:"
puts $!
puts e
end
end
Gives the output:
Original Exception:
original exception
original exception
Second Exception:
second exception
original exception
As you can see e has stored the original exception for use after the second exception.
class MyError < StandardError
attr_reader :original
def initialize(msg, original=$!)
super(msg)
#original = original;
end
end
begin
begin
raise "explosion"
rescue => error
raise MyError, "Are you mad"
end
rescue => error
puts "Current failure: #{error.inspect}"
puts "Original failure: #{error.original.inspect}"
end
OUTPUT
Current failure: #<MyError: Are you mad>
Original failure: #<RuntimeError: explosion>
=> nil

Handling exceptions raised in a Ruby thread

I am looking for a solution of classic problem of exception handling. Consider following piece of code:
def foo(n)
puts " for #{n}"
sleep n
raise "after #{n}"
end
begin
threads = []
[5, 15, 20, 3].each do |i|
threads << Thread.new do
foo(i)
end
end
threads.each(&:join)
rescue Exception => e
puts "EXCEPTION: #{e.inspect}"
puts "MESSAGE: #{e.message}"
end
This code catches the exception after 5 seconds.
But if I change the array as [15, 5, 20, 3], above code catch the exception after 15 seconds. In short, it always catch the exception raised in first thread.
Any idea, why so. Why doesn't it catch the exception after 3 seconds each time? How do I catch the first raised exception by any thread?
If you want any unhandled exception in any thread to cause the interpreter to exit, you need to set Thread::abort_on_exception= to true. Unhandled exception cause the thread to stop running. If you don't set this variable to true, exception will only be raised when you call Thread#join or Thread#value for the thread. If set to true it will be raised when it occurs and will propagate to the main thread.
Thread.abort_on_exception=true # add this
def foo(n)
puts " for #{n}"
sleep n
raise "after #{n}"
end
begin
threads = []
[15, 5, 20, 3].each do |i|
threads << Thread.new do
foo(i)
end
end
threads.each(&:join)
rescue Exception => e
puts "EXCEPTION: #{e.inspect}"
puts "MESSAGE: #{e.message}"
end
Output:
for 5
for 20
for 3
for 15
EXCEPTION: #<RuntimeError: after 3>
MESSAGE: after 3
Note: but if you want any particular thread instance to raise exception this way there are similar abort_on_exception= Thread instance method:
t = Thread.new {
# do something and raise exception
}
t.abort_on_exception = true
Thread.class_eval do
alias_method :initialize_without_exception_bubbling, :initialize
def initialize(*args, &block)
initialize_without_exception_bubbling(*args) {
begin
block.call
rescue Exception => e
Thread.main.raise e
end
}
end
end
Postponed exceptions processing (Inspired by #Jason Ling)
class SafeThread < Thread
def initialize(*args, &block)
super(*args) do
begin
block.call
rescue Exception => e
#exception = e
end
end
end
def join
raise_postponed_exception
super
raise_postponed_exception
end
def raise_postponed_exception
Thread.current.raise #exception if #exception
end
end
puts :start
begin
thread = SafeThread.new do
raise 'error from sub-thread'
end
puts 'do something heavy before joining other thread'
sleep 1
thread.join
rescue Exception => e
puts "Caught: #{e}"
end
puts 'proper end'
This will wait for the first thread to either raise or return (and re-raise):
require 'thwait'
def wait_for_first_block_to_complete(*blocks)
threads = blocks.map do |block|
Thread.new do
block.call
rescue StandardError
$!
end
end
waiter = ThreadsWait.new(*threads)
value = waiter.next_wait.value
threads.each(&:kill)
raise value if value.is_a?(StandardError)
value
end
Jason Ling's answer will miss out any arguments passed to Thread.new. This will break Puma and other gems. To avoid this problem, you can use:
Thread.class_eval do
alias_method :initialize_without_exception_bubbling, :initialize
def initialize(*args, &block)
initialize_without_exception_bubbling(*args) {
begin
block.call(*args)
rescue Exception => e
Thread.main.raise e
end
}
end
end

Is SystemExit a special kind of Exception?

How does SystemExit behave differently from other Exceptions? I think I understand some of the reasoning about why it wouldn't be good to raise a proper Exception. For example, you wouldn't want something strange like this to happen:
begin
exit
rescue => e
# Silently swallow up the exception and don't exit
end
But how does the rescue ignore SystemExit? (What criteria does it use?)
When you write rescue without one or more classes, it is the same as writing:
begin
...
rescue StandardError => e
...
end
There are Exceptions that do not inherit from StandardError, however. SystemExit is one of these, and so it is not captured. Here is a subset of the hierarchy in Ruby 1.9.2, which you can find out yourself:
BasicObject
Exception
NoMemoryError
ScriptError
LoadError
Gem::LoadError
NotImplementedError
SyntaxError
SecurityError
SignalException
Interrupt
StandardError
ArgumentError
EncodingError
Encoding::CompatibilityError
Encoding::ConverterNotFoundError
Encoding::InvalidByteSequenceError
Encoding::UndefinedConversionError
FiberError
IOError
EOFError
IndexError
KeyError
StopIteration
LocalJumpError
NameError
NoMethodError
RangeError
FloatDomainError
RegexpError
RuntimeError
SystemCallError
ThreadError
TypeError
ZeroDivisionError
SystemExit
SystemStackError
fatal
You can thus capture just SystemExit with:
begin
...
rescue SystemExit => e
...
end
...or you can choose to capture every exception, including SystemExit with:
begin
...
rescue Exception => e
...
end
Try it yourself:
begin
exit 42
puts "No no no!"
rescue Exception => e
puts "Nice try, buddy."
end
puts "And on we run..."
#=> "Nice try, buddy."
#=> "And on we run..."
Note that this example will not work in (some versions of?) IRB, which supplies its own exit method that masks the normal Object#exit.
In 1.8.7:
method :exit
#=> #<Method: Object(IRB::ExtendCommandBundle)#exit>
In 1.9.3:
method :exit
#=> #<Method: main.irb_exit>
Simple example:
begin
exit
puts "never get here"
rescue SystemExit
puts "rescued a SystemExit exception"
end
puts "after begin block"
The exit status / success?, etc. can be read too:
begin
exit 1
rescue SystemExit => e
puts "Success? #{e.success?}" # Success? false
end
begin
exit
rescue SystemExit => e
puts "Success? #{e.success?}" # Success? true
end
Full list of methods: [:status, :success?, :exception, :message, :backtrace, :backtrace_locations, :set_backtrace, :cause]

Resources