Raising an Exception






Raising an Exception

Credit: Steve Arneil

Problem

An error has occurred and your code can't 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 it's 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

Here's 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('not 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 method's 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('not 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

  • Recipe 7.8, "Stopping an Iteration"

  • Recipe 17.2, " Raising an Exception"

  • Recipe 17.3, "Handling an Exception"



 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows