3. Introduction
• An exception is an object that represents some kind of exceptional
conditions, it indicates hat sometime has gone wrong.
– This could be a programming error attempting to divide by zero.
– Attempting to invoke a method on an object that define an method or
passing an invalid argument to a method.
– It could be result of an some king of external condition, making
network request when the network down or trying to create an object
when the system is out of memory.
• When one of these errors or conditions occurs an exception is
raised.
• By default, Ruby programs terminate when an exception occurs.
• But it is possible to declare exception handlers. An exception
handler is a block of code that is executed if an exception occurs
during the execution of some other block of code.
• Raising an exception transfers the flow of control to exception
handling code.
• Ruby uses the Kernel method raise to raise exceptions and uses
rescue clause to handle exceptions.
• Exceptions raised by raise are instances of the Exception class or
one of its many subclasses.
4. Exception Classes and Exception Objects
• Exception objects are instance of the Exception class or one of
its subclass.
Object
+--Exception
+--NoMemoryError
+--ScriptError
| +--LoadError
| +--NotImplementedError
| +--SyntaxError
+--SecurityError # Was a StandardError in 1.8
+--SignalException
| +--Interrupt
+--SystemExit
+--SystemStackError # Was a StandardError in 1.8
+--StandardError
+--ArgumentError
5. Contd..
+--FiberError # New in 1.9
+--IOError
| +--EOFError
+--IndexError
| +--KeyError # New in 1.9
| +--StopIteration # New in 1.9
+--LocalJumpError
+--NameError
| +--NoMethodError
+--RangeError
| +--FloatDomainError
+--RegexpError
+--RuntimeError
+--SystemCallError
+--ThreadError
+--TypeError
+--ZeroDivisionError
6. Contd..
• You don’t need to be familiar with each of these
exception subclass.
• The most of these subclass extend a class known as
StandardError.
• These are the “normal” exceptions that typical Ruby
programs try to handle.
• Most of them are undocumented because, most of them
add no new methods to those defined by the base
Exception class.
7. Methods of exception objects
• The exception class defines two methods that return details
about the exception.
• The message method returns a string that may provide
human readable details about what went wrong.
• The backtrace method returns an array of strings that
represents the call stack at the point the exception was raised.
• Exception objects are typically created by the raise method.
When this is done, the raise method sets the stack trace of
the exception appropriately.
• The set_backtrace method is used to set the backtrace for the
custom exceptions.
8. Defining new exceptions
• If you are defining a module a Ruby code, it is often
appropriate to define your own subclass of StandardError for
exception that are specific to your module.
• This may be a trivial, one-line subclass
Class MyError < StandardError; end
9. Raising Exceptions with raise
• The Kernel method raise raises an exception.
• There are several ways to invoke raise
– If raise is called with no arguments, it creates a new RuntimeError object and
raises it.
– If raise is called with a single Exception object as its argument, it raises that
exception.
– If raise is called with a single string argument, it creates a new RuntimeError
exception object, with the specified string as its message, and raises that
exception.
– If the first argument to raise is an object that has an exception method, then
raise invokes that method and raises the Exception object that it returns.
def factorial(n)
raise “Bad argument” if n<1
return 1 if n ==1
n*factorial(n-1)
end
– The other ways to raise exception
raise RuntimeError, “Bad argument” if n<1
raise RuntimeError.new(“Bad argument”) if n<1
raise RuntimeError.exception(“Bad argument”) if n<1
10. Contd..
• ArgumentError is more appropriate than RuntimeError and
more detailed error message would be helpful.
raise ArgumentError, “Exception argument >=1. Got #{n}} if n<1
• The intent of the exception we’re raising here is to point
out a problem with the invocation of the factorial method,
not with the code inside the method.
• The caller method of kernel is used as third argument to
provide a custom stack trace.
raise ArgumentError, “Exception argument >= 1. Got #{n}”, caller
11. Handling Exceptions with rescue
• A rescue clause, by contrast, is a fundamental part of the
Ruby language.
• rescue is not a statement in its own right, but rather a
clause that can be attached to other Ruby statements.
• Most commonly, a rescue clause is attached to a begin
statement.
• A begin statement with a rescue clause looks like this:
begin
#code
rescue
#Exception handling code goes here
End
12. Naming the exception
• In rescue clause, the global variable $! Refers to the Exception
object that is being handled.
• If your program includes the line:
require ‘English’, then you can use the global variable $ERROR_INFO
instead.
• A better alternative to $! or $ERROR_INFO is to specify a variable
name for the exception object in the rescue clause itself:
Rescue => ex
• The statements of this rescue clause can now use the ex to refer to
Exception object that describes the exception.
• The rescue clause does not define a new variable scope and a
variable named in the rescue clause is visible even after the end of
the rescue clause.
13. Handling exceptions by type
• The rescue clauses shown here handled any exception that is a
StandardError and ignore any exception object that is not a
StandardError.
• To handle non standard exceptions outside the StandardError
hierarchy or to handle only specific types of exceptions, you must
include one or more exception classes in the rescue clause.
rescue Exception
• To handle an ArgumentError and assign the exception object to the
variable e:
rescue ArgumentError => e
rescue ArgumentError, TypeError => error
• The rescue keyword is followed by zero or more comma-separated
expressions, each of which must evaluate to a class object that
represents the Expression class or a subclass.
14. Contd..
• We might use a case statement to run different code based on
the class of the exception object.
Begin
x=factorial(n)
rescue ArgumentError => ex
puts “Try again with value >= 1”
rescue TypeErrror => ex
puts “Try again with an integer”
end
• Ruby interpreter attempts to match exceptions to rescue
clauses in the order they are written.
15. Retry in a rescue clause
• When the retry statement is used within a rescue clause, it returns the
block of code to which the rescue is attached.
• When an exception is caused by a transient failure, such as an overloaded
server, it might make sense to handle the exception by simply trying again.
• retry is not suitable handling technique for these exceptions.
require ‘open-uri’
tries = 0
begin
tries += 1
open(http://www.example.com)
rescue OpenURI::HTTPError => e
puts e.message
if(tries<4)
sleep(2**tries)
retry
end
end
16. The else Clause
• A begin statement may include an else clause after its
rescue clauses.
• You might guess that the else clause is a catch-all rescue
that it handles any exception that does not match a
previous rescue claues.
• The code in the else clause is executed if the code in the
body of the begin statement runs to completion without
exceptions.
• The exception raised by the else clause are not handled by
the rescue statements.
17. The ensure Clause
• The optional ensure clause, if it appears, must come after all rescue and
else clasues.
• It may also be used by itself without any rescue or else clause.
• The ensure clause contains code that always runs, no matter what
happens with the code following begin.
– If the code runs to completion, then control jumps to the else clause, if there
is one and then to the ensure clause.
– If the code executes a return statement, then the execution skips the else
clause and jumps directly to the ensure clause before returning.
– If the following code begin raises an exception, then control jumps to the
appropriate rescue clause, and then to the ensure clause.
– If there is no rescue clause, or if no rescue clause can handle the exception,
then control jumps directly to the ensure clause.
• The purpose of ensure clause is to ensure that housekeeping details such
as closing files, disconnecting database connections, and committing or
aborting transactions get taken care.