Raising an Exception

Credit: Steve Arneil

Problem

An error has occurred and your code can keep running. You want to indicate the error and let some other piece of code handle it.

Solution

Raise an exception by calling the Kernel#raise method with a description of the error. Calling the raise method interrupts the flow of execution.

The following method raises an exception whenever its called. Its second message will never be printed:

def raise_exception puts I am before the raise. raise An error has occurred. puts I am after the raise. end raise_exception # I am before the raise. # RuntimeError: An error has occurred

Discussion

Heres a method, inverse, that returns the inverse of a number x. It does some basic error checking by raising an exception unless x is a number:

def inverse(x) raise "Argument is not numeric" unless x.is_a? Numeric 1.0 / x end

When you pass in a reasonable value of x, all is well:

inverse(2) # => 0.5

When x is not a number, the method raises an exception:

inverse( ot a number) # RuntimeError: Argument is not numeric

An exception is an object, and the Kernel#raise method creates an instance of an exception class. By default, Kernel#raise creates an exception of RuntimeError class, which is a subclass of StandardError. This in turn is a subclass of Exception, the superclass of all exception classes. You can list all the standard exception classes by starting a Ruby session and executing code like this:

ObjectSpace.each_object(Class) do |x| puts x if x.ancestors.member? Exception end

This variant lists only the better-known exception classes:

ObjectSpace.each_object(Class) { |x| puts x if x.name =~ /Error$/ } # SystemStackError # LocalJumpError # EOFError # IOError # RegexpError # …

To raise an exception of a specific class, you can pass in the class name as an argument to raise. RuntimeError is kind of generic for the inverse methods check against x. The problem is there is actually a problem with one of the arguments passed into the method. A more aptly named exception class for that check would be ArgumentError:

def inverse(x) raise ArgumentError, Argument is not numeric unless x.is_a? Numeric 1.0 / x end

To be even more specific about an error, you can define your own Exception subclass:

class NotInvertibleError < StandardError end

The implementation of inverse method would then become:

def inverse(x) raise NotInvertibleError, Argument is not numeric unless x.is_a? Numeric 1.0 / x end inverse( ot a number) # NotInvertibleError: Argument is not numeric

In some other programming languages, exceptions are "thrown." In Ruby, they are not thrown but "raised." Ruby does have a Kernel#throw method, but it has nothing to do with exceptions. See Recipe 7.8 for an example of tHRow, as opposed to raise.

See Also

Категории