Ruby Exceptions

Ruby exception is an object, an instance of the class Exception or descendent of that class. It represents some exceptional condition.

In a Ruby program, when something goes wrong, it throws an exceptional behavior. By default Ruby program terminates on throwing an exception.

We can declare some exception handlers within Ruby. An exception handler is a block of code which is executed when exception occurs in some other block of code.

Exceptions are handled in two ways. Either you can terminate the program or deal with the exception. To deal with an exception, you can provide a rescue clause. By providing this, program control flows to the rescue clause.

When an exception is raised but not handled, global variable $! contains the current exception and $@ contains the current exception’s backtrace.

Ruby predefined classes like Exception and its children helps you to handle errors of your program. In Ruby exception hierarchy, most of the sub classes extend class StandardError. These are the normal exceptions.


Ruby Class Exceptions

Built-in subclasses of exception are as follows:

  • NoMemoryError
  • ScriptError
  • SecurityError
  • SignalException
  • StandardError
  • SystenExit
  • SystemStackError
  • fatal – impossible to rescue

Example:

def raise_exception     

  puts 'I am before the raise.'     

  raise 'oops! An error has occured'     

  puts 'I am after the raise'     

end     

raise_exception

Output:

Ruby exceptions 1

The raise method comes from the Kernel module.


Handling an Exception

To handle exception, the code that raises exception is enclosed within begin-end block. Using rescue clauses we can state type of exceptions we want to handle.

Example:

def raise_and_rescue     

  begin     

    puts 'Before the raise.'     

    raise 'An error occured.'     

    puts 'After the raise.'     

  rescue     

    puts 'Code rescued.'     

  end     

  puts 'After the begin block.'     

end     

raise_and_rescue

Output:

Ruby exceptions 2

In the above example, interrupted code does not run completely. After exception handling code resumes after the begin-end block.

If no argument is defined in the rescue clause, the parameter defaults to StandardError. Each rescue clause specify multiple exceptions to catch. If raise is used without any parameters, exception may re-raised.

The rescue clauses are written in a begin/rescue block. Exceptions if not handled by one rescue clause will br handled with the next one.

begin  

code..  

rescue OneTypeOfException  

code..  

rescue AnotherTypeOfException  

 code..  

else  

  # Other exceptions  

end

In the begin block, each rescue clause with the raised exception will be compared against each of parameters in turn. It will be matched when the type of error thrown and exception named in the rescue clause is either same or is a superclass of that exception. The else clause is executed if body of begin statement is completed without exceptions. If an exception occurs, else clause will not be executed.


Exception Object

Exception objects are normal objects. A rescued exception can be hold to a variable within the rescue clause.

Example:

begin   

  raise 'an exception'   

rescue ZeroDivisionError => e   

  puts "Exception Class: #{ e.class.name }"   

  puts "Exception Message: #{ e.message }"   

  puts "Exception Backtrace: #{ e.backtrace }"   

end

The Exception class defines two methods that return details about the exception. The message method returns a string that define the explanation of error. The backtrace method returns an array of string that represent the call stack at that point where exception was raised.


Using retry Statement

Usaually in a rescue clause, the exception is captured and code resumes after begin block. Using retry statement, the rescue block code can be resumed from begin after capturing an exception.

Syntax:

begin  

   code....  

rescue  

    # capture exceptions  

    retry  # program will run from the begin block  

end

Example:

#!/usr/bin/ruby   

  

begin   

   x = Dir.mkdir "alreadyExist"   

   if x   

      puts "Directory created"   

   end   

rescue   

   y = "newDir"   

   retry   

end

The above program runs as follows:

Step 1 In the begin block, code is written to make a directory that already exists.

Step 2 This will throw an error.

Step 3 In rescue block, y was reassigned.

Step 4 The retry statement will go to the begin block.

Step 5 Directory will be created.


Using raise Statement

The raise statement is used to raise an exception.

Syntax:

raise   

Or,

  1. raise “Error Message”   

Or,

raise ExceptionType, "Error Message"  

Or,

raise ExceptionType, "Error Message" condition  

The first one re-raises the current exception. It is used for exception handlers where exception is intercepted before passing it on.

The second one creates a new RuntimeError exception. This exception is then raised up the call stack.

The third one uses first argument to create an exception, then sets associated message to the second argument.

The fourth one similar to third one. In this you can add any conditional statement to raise an exception.

Example:

#!/usr/bin/ruby   

  

begin     

    puts 'code before raise.'     

    raise 'exception occurred.'     

    puts 'code after raise.'     

rescue     

    puts 'I am rescued.'     

end     

puts 'code after begin block.'

Output:

Ruby exceptions 3

Using ensure Statement

There is an ensure clause which guarantees some processing at the end of code. The ensure block always run whether an exception is raised or not. It is placed after last rescue clause and will always executed as the block terminates.

The ensure block will run at any case whether an exception arises, exception is rescued or code is terminated by uncaught exception.

Syntax:

begin   

  code..  

   #..raise exception  

rescue   

   #.. exception is rescued  

ensure   

   #.. This code will always execute.  

end

Example:

begin   

  raise 'Exception'   

rescue Exception => e   

  puts e.message   

  puts e.backtrace.inspect   

ensure   

  puts "The ensure code will always run"   

end

Output:

Ruby exceptions 4

Using else Statement

The else clause is always present after rescue clause and before ensure clause. If no exceptions are raised, then only else block is executed.

Syntax:

begin   

   code..   

   #..raise exception  

rescue   

   # .. exception is rescued  

else  

   #.. executes if there is no exception  

ensure   

   #..  This code will always execute.  

end

Example:


  1. begin   
  2.  # raise 'A test exception.'   
  3.  puts "no exception is raised"   
  4. rescue Exception => e   
  5.   puts e.message   
  6.   puts e.backtrace.inspect   
  7. else   
  8.    puts "else code will be executed as no exception is raised."   
  9. ensure   
  10.   puts "ensure code will run"   
  11. end  

Output:

Ruby exceptions 5

Ruby Catch and Throw

Ruby catch and throw provide a way to jump from the execution early when no further work is needed in a code.

The catch defines a block that is labeled with a given name. It is used to jump out of nested code. Using catch, the block will be executed normally until throw is encountered.

The catch and throw method is faster than rescue and raise clauses. Hence, it is more suitable to use.

Syntax:

throw :lablename  

#.. this  code will not be executed  

catch :lablename do  

#.. matching catch will be executed after a throw is encountered.  

end

Or,

throw :lablename condition  

#.. this code will not be executed  

catch :lablename do  

#.. matching catch will be executed after a throw is encountered.  

end

Example:

def promptAndGet(prompt)   

   print prompt   

   res = readline.chomp   

   throw :quitRequested if res == "!"   

   return res   

end   

  

catch :quitRequested do   

   name = promptAndGet("Name: ")   

   age = promptAndGet("Occupation: ")   

   # ..   

   # process information   

end   

promptAndGet("Name:")

Output:

Ruby exceptions 6

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *