Ruby Exception Handling: Rescuing 3rd Party Exceptions Without Begin

July 12, 2016

Traditional Ruby Exception Handling

Picture of red error warning exclamation point

Every online blog post that I come across that talks about exception handling in Ruby starts off something like this:

  puts "some code that might cause an error"
rescue StandardError => e
  puts "rescued"

A begin/rescue block is pretty much the cliche of Ruby exception handling, as is rescuing StandardError.

In fact, the traditional advice is that StandardError will capture the exceptions that a normal Ruby program is supposed to use.

But you don’t have to stick with cliches

Imagine my delight when one of my coworkers informed me that you don’t necessarily need to use begin. For example:

def get_money_details
  geocoder_info = get_geocoder_info #some function that can trigger a ::Geocoder::Error
  do_something_with_geocoder_info(geocoder_info) #some function to do something with geocoder_info
  construct_money_details #some function that handles money details and can trigger a Binary::Errors::TaxError
  rescue ::Geocoder::Error => e
    return construct_null_tax_details({status_message: e.message })
  rescue Binary::Errors::TaxError => e
    @error_notifier.notify(e.message, { type: Binary::Errors::TaxError::GENERAL_BINARY_TYPE})
  return construct_null_tax_details({ status_message: e.message })

Note that I don’t use begin anywhere in the above code. If the geocoder_info function raises a ::Geocoder::Error, then there’s a rescue block for that. If construct_money_details raises a Binary::Errors::TaxError, then there’s a rescue block for that as well.

Compress to a single rescue block?

As mentioned in the blog post by Thoughtbot, you could come up with an array of errors and compress it to a single rescue block as follows:

ERRORS = [::Geocoder::Error, Binary::Errors::TaxError]
  #some function calll
rescue *ERRORS => e
  #some rescue code

But since I needed to call the notify method with 2 different arguments, I opted to have a double rescue block.

But I think the code is a bit more compact and styled more nicely than it would have been had I used a begin keyword.