Handling an Exception

Credit: Steve Arneil

Problem

You want to handle or recover from a raised exception.

Solution

Rescue the exception with a begin/rescue block. The code you put into the rescue clause should handle the exception and allow the program to continue executing.

This code demonstrates the rescue clause:

	def raise_and_rescue
	 begin
	 puts I am before the raise.
	 raise An error has occurred.
	 puts I am after the raise.
	 rescue
	 puts I am rescued!
	 end
	 puts I am after the begin block.
	end

	raise_and_rescue
	# I am before the raise.
	# I am rescued!
	# I am after the begin block.

The exception doesn stop the program from running to completion, but the code that was interrupted by the exception never gets run. Once the exception is handled, execution continues immediately after the begin block that spawned it.

Discussion

You can handle an exception with a rescue block if you know how to recover from the exception, if you want to display it in a nonstandard way, or if you know that the exception is not really a problem. You can solve the problem, present it to the end user, or just ignore it and forge ahead.

By default, a rescue clause rescues exceptions of class StandardError or its subclasses. Mentioning a specific class in a rescue statement will make it rescue exceptions of that class and its subclasses.

Heres a method, do_it, that calls the Kernel#eval method to run some Ruby code passed to it. If the code cannot be run (because its not valid Ruby), eval raises an exceptiona SyntaxError. This exception is not a subclass of StandardError; its a subclass of ScriptError, which is a subclass of Exception.

	def do_it(code)
	 eval(code)
	rescue
	 puts "Cannot do it!"
	end

	do_it(puts 1 + 1)
	# 2

	do_it(puts 1 +)
	# SyntaxError: (eval):1:in do_it: compile error

That rescue block never gets called because SyntaxError is not a subclass of StandardError. We need to tell our rescue block to rescue us from SyntaxError, or else from one of its superclasses, ScriptError and Exception:

	def do_it(code)
	 eval(code)
	rescue SyntaxError
	 puts "Cannot do it!"
	end

	do_it(puts 1 +)
	# Cannot do it!

You 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
	 # …
	end

If you want to interrogate a rescued exception, you can map the Exception object to a variable within the rescue clause. Exception objects have useful methods like message and backtrace:

	begin
	 raise A test exception.
	rescue Exception => e
	 puts e.message
	 puts e.backtrace.inspect
	end
	# ["(irb):33:in irb_binding",
	# "/usr/lib/ruby/1.8/irb/workspace.rb:52:in irb_binding",
	# ":0"]

You can also use the special variable $! within a rescue block to refer to the most recently raised Exception. If you do a require English, you can use the $ERROR_INFO variable, which is easier to remember.

	require English
	begin
	 raise Another test 
exception.
	rescue Exception
	 puts $!.message
	 puts $ERROR_INFO.message
	end
	# Another test exception.
	# Another test exception.

Since $! is a global variable, and might be changed at any time by another thread, its safer to map each Exception object you rescue to an object.

See Also

  • Recipe 17.2, "Raising an Exception"
  • Recipe 17.4, "Rerunning After an Exception"


Strings

Numbers

Date and Time

Arrays

Hashes

Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming

XML and HTML

Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net