Exception handling in Ruby with begin, rescue, and ensure

Begin, rescue, and ensure provide flexible exception handling. Supposed we have the following method:

def divide(a, b)
  begin
    a / b
  rescue TypeError => e
    puts "I am rescuing from a TypeError"
    puts e
    puts e.class
    puts e.backtrace
  rescue ZeroDivisionError => e
    puts "I am rescuing from a ZeroDivisionError"
    puts e
    puts e.class
    puts e.backtrace
  else
    puts "No exception was raised"
  ensure
    puts "BLAH BLAH BLAH"
  end
end

Let’s examine what this method outputs with various inputs.

>> divide(4, 2)
No exception was raised
BLAH BLAH BLAH

If the function is passed valid output, the code in else is executed and so is the code in ensure. The code in ensure is executed regardless, but else is only executed if there are no exceptions.

>> divide(1, "cat")
I am rescuing from a TypeError
String can't be coerced into Fixnum
TypeError
lib/begin_rescue.rb:3:in `/'
lib/begin_rescue.rb:3:in `divide'
lib/begin_rescue.rb:22:in `<main>'
BLAH BLAH BLAH

Where there is a TypeError, the code in the TypeError rescue block and the ensure block are executed. By passing => e to the rescue TypeError => e line, we have access to the error message, error class, and error backtrace – useful stuff for debugging purposes.

>> divide(1, 0)
I am rescuing from a ZeroDivisionError
divided by 0
ZeroDivisionError
lib/begin_rescue.rb:3:in `/'
lib/begin_rescue.rb:3:in `divide'
lib/begin_rescue.rb:23:in `<main>'
BLAH BLAH BLAH

Curiously, the following code does not execute the code in the ensure block (didn’t we previously establish that the code in the ensure block is always executed under all conditions).

lib/begin_rescue.rb:1:in `divide': wrong number of arguments (0 for 2) (ArgumentError)
	from lib/begin_rescue.rb:21:in `<main>'

In this case the ArgumentError is raised before the function is executed, so the ensure never gets the chance to run. We can rescue from an ArgumentError (rescuing from ArgumentErrors is not a good idea, BTW), by putting the method call in another begin/rescue block:

begin
  divide
rescue ArgumentError
  puts "Ahhhhh, that's better"
end
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s