Exception Handling in Ruby
Ahmad Hamza
What's an exception?
When you raise an exception in Ruby, the world stops and your program starts to shut down other wise your program will eventually exit with an error message.
Exceptions are Ruby's way of dealing with unexpected events.
eg: SyntaxError or NoMethodError
irb(main):001:0> 1 / 0 
ZeroDivisionError: divided by 0Just like:
begin
  1/0
rescue
  puts "Got an exception, but I'm responding intelligently!"
  do_something_intelligent()
end
# This program does not crash.
# Outputs: "Got an exception, but I'm responding intelligently!"How to stop this shutdown process, and react to the error intelligently ?
This is called "rescuing," "handling," or "catching" an exception. They all mean the same thing. This is how you do it in Ruby.
The exception still happens but it doesn't cause the program to crash because it was rescued.
Nice, OK.. ??
The error message says "Something went wrong", but it does not let us know what exactly went wrong ?
Exception Objects
To get an exception object, you will use the slightly different syntax.
Exception objects are normal Ruby objects.
# Rescues all errors, an puts the exception object in `e`
rescue => e
# Rescues only ZeroDivisionError and puts the exception object in `e`
rescue ZeroDivisionError => eZeroDivisionError is the class of object in 'e'
begin
1 / 0
rescue ZeroDivisionError => e
  puts "Exception Class: #{ e.class.name }"
  puts "Exception Message: #{ e.message }"
  puts "Exception Backtrace: #{ e.backtrace }"
end
# Outputs:
# Exception Class: ZeroDivisionError
# Exception Message: divided by 0
# Exception Backtrace: ...backtrace as an array...Raising Your Own Exceptions
'raise' - trigger your own exceptions
When you raise, you get to pick which type of exception to use.
You also get to set the error message.
More examples: Gist
def raise_exception  
  puts 'I am before the raise.'  
  raise 'An error has occured'  
  puts 'I am after the raise'  
end
raise_exception
#output
I am before the raise.
RuntimeError: An error has occured
from (irb):3:in `raise_exception'
from (irb):6raise
The raise method is from the Kernel module.
By default, raise creates an exception of the RuntimeError class.
To raise an exception of a specific class, you can pass in the class name as an argument to raise.
def inverse(x)
  raise ArgumentError, 'Argument is not numeric' unless x.is_a? Numeric
  1.0 / x
end
puts inverse(2)
puts inverse('not a number')
#output
0.5
ArgumentError: Argument is not numeric
	from (irb):2:in `inverse'
	from (irb):7raise - can be called in several ways
# Explicitly mention the error
raise RuntimeError.new("You messed up!")
# Produces the same result
raise RuntimeError, "You messed up!"
# Produces the same result. But you can only raise 
# RuntimeErrors this way
raise "You messed up!"Handling an exception
Steps:
- Enclose the code that could raise an exception in a begin-end block
- Use one or more rescue clauses to tell Ruby the types of exceptions we want to handle.
Note: The body of a method definition is an implicit begin-end block; the begin is omitted, and the entire body of the method is subject to exception handling, ending with the end of the method.
def raise_and_rescue  
  begin  
    puts 'I am before the raise.'  
    raise 'An error has occured.'  
    puts 'I am after the raise.'  
  rescue  
    puts 'I am rescued.'  
  end  
  puts 'I am after the begin block.'  
end  
raise_and_rescue
# output:
I am before the raise.  
I am rescued.  
I am after the begin block.Observe that the code interrupted by the exception never gets run. Once the exception is handled, execution continues immediately after the begin block that spawned it.
If you write a rescue clause with no parameter list, the parameter defaults to StandardError.
Each rescue clause can specify multiple exceptions to catch. At the end of each rescue clause you can give Ruby the name of a local variable to receive the matched exception.
begin
  rand(2) == 0 ? ([] + '') : (foo)
rescue TypeError, NameError => e
  puts "oops: #{e.message}"
end
# output:
oops: no implicit conversion of String into ArrayYou can stack rescue clauses in a begin/rescue block. Exceptions not handled by one rescue clause will trickle down to the next:
begin  
  # -  
rescue OneTypeOfException  
  # -  
rescue AnotherTypeOfException  
  # -  
else  
  # Other exceptions  
end ensure
If you need the guarantee that some processing is done at the end of a block of code, regardless of whether an exception was raised then the ensure clause can be used. ensure goes after the last rescue clause and contains a chunk of code that will always be executed as the block terminates.
The ensure block will always run.
The general flow of begin/rescue/else/ensure/end looks like this:
begin
  # something which might raise an exception
rescue SomeExceptionClass => some_variable
  # deals with some exception
rescue SomeOtherException => some_other_variable
  # deals with some other exception
else
  # runs only if *no* exception was raised
ensure
  # ensure that this code always runs, no matter what
endMaking Custom Exceptions
Just create a new class that inherits from StandardError
class PermissionDeniedError < StandardError
end
PermissionDeniedError.new()Since it is a normal Ruby class, you can add methods and data to it like any other class.
class PermissionDeniedError < StandardError
  attr_reader :action
  def initialize(message, action)
    # Call the parent constructor to set the message
    super(message)
    # Store the action in an instance variable
    @action = action
  end
end
# Then, when the user tries to delete something they do not
# have permission to delete, you might do something like this:
raise PermissionDeniedError.new("Permission Denied", :delete)Exception class
➜ irb
irb(main):001:0> ArgumentError.superclass
=> StandardError
irb(main):002:0> ArgumentError.superclass.superclass
=> Exception
irb(main):003:0> ArgumentError.superclass.superclass.superclass
=> Object
Exception is the parent class of all other exception classes.
Some useful public methods of Exception class:
- backtrace: The backtrace is an array of strings, each containing either "filename:lineNo: in `method" or "filename:lineNo"
- message: returns the exception message or name
- inspect: Return this exception's class name and message
Exception and its children

Rescuing All Exceptions (the bad way)
// Don't do this 
begin
  do_something()
rescue Exception => e
  ...
endDon't rescue every exception, it breaks program in weird ways. Because Ruby uses exceptions for things other than errors. It also uses them to handle messages from the operating system called "Signals." If you've ever pressed "ctrl-c" to exit a program, you've used a signal. By suppressing all exceptions, you also suppress those signals.
Rescuing All Errors (the right way)
begin
  do_something()
rescue StandardError => e
  # Only your app exceptions are swallowed. Things like SyntaxErrror are left alone. 
endif you want to rescue "all errors" you should rescue StandardError.
If you don't specify an exception class, Ruby assumes you mean StandardError
begin
  do_something()
rescue => e
  # This is the same as rescuing StandardError
endRescuing Specific Errors (the best way)
begin
  do_something()
rescue Errno::ETIMEDOUT => e
  // This will only rescue Errno::ETIMEDOUT exceptions
endNow that you know how to rescue all errors, you should know that it's usually a bad idea, a code smell, considered harmful, etc.
You can even rescue multiple kinds of exceptions in the same rescue block, so no excuses. :)
begin
  do_something()
rescue Errno::ETIMEDOUT, Errno::ECONNREFUSED => e
endSo take the time and do it right. Rescue specific exceptions.
Questions?
Thank You
Raising an Exception
By Ahmad Hamza
Raising an Exception
- 584
 
   
   
  