Lazy Ruby Exceptions

Lazy Ruby Exceptions

What Are Exceptions?

Simply put, an exception is an error.

Less simply put: An exception puts a program in a state that is, for lack of a better word, undefined, or cannot—safely—be handled by the language runtime itself.

Get It

Not needed: Ruby has them out of the box.

How do You Use Exceptions?

First things first: Exceptions are not control statements. If you rely on Exceptions to determine what your software is supposed to do, something’s awry.

Use exceptions for:

  • Program state (awfully close to program flow, but I’ll explain later)
  • Resource access
  • Unrecoverable errors

Exception Statements in Ruby

Ruby’s exception syntax is simple, yet powerful:

begin # Awesomeness rescue # Recover from an Exception ensure # Clean up after ourselves end

Two statements in this example are of particular importance:

rescue can take one or more Exception classes (for example: SyntaxError, LoadError, IOError, etc) as an argument. The hash rocket => is used to get a reference to the exception.

ensure is an optional argument, and gets executed no matter what. The code following ensure is, quite literally, ensured to run.

Here’s a toy example:

begin raise "I'm an exception" rescue puts "In the rescue clause..." puts "I give up!" error = "Cannot recover from this!" ensure puts "Ensured to run." puts error end

raise triggers Ruby’s exception handling whenever you need it.

Ensuring Sanity

ensure is useful when you gain access to a resource that should not be left open or lying around. A good example would be a database connection: Instead of leaving an unused database connection around until the database server decides that nobody’s going to use this connection, it gets closed. A good rule of thumb to using ensure is: Am I doing input or output? If so, ensure that my IO access is properly closed.

Eventually this’ll be handled elsewhere, but you cannot rely on it, nor is it very neighborly if we don’t clean up after ourselves.

A Note on Blocks

Ruby provides block methods for IO, like File#read. These blocks have exception handling built in: If you open a file or network socket in a block, Ruby will ensure that it cleans up behind you. So, whenever you can use the black form to access IO (it is a much more natural or readable style, too, in my experience).

Raising and Creating Exceptions

Ruby provides an Exception class from which all other exceptions are derived. I suggest that you, too, derive your custom exceptions from this base.

The base class provides you with backtrace information (where and how was the exception invoked?) at no extra work, which is vey useful:

class CustomException < Exception end  error = raise CustomException.new "Error message" puts error

And as you can see, you can treat an exception like any other object in Ruby with its own constructor.

Exceptions For Program State

Let’s say you have a nifty Ruby program which interfaces with databases. You have wrappers for all the different database engines out there, from SQLite to Oracle, but with littel changes here and there (like DB connections, file access, &c.).

If you don’t yet know which databases are available, you can try to probe for their availability, and if you encounter an exception, you can cross this engine off your list of database wrappers to load.

Another example is checking for teh vailability of gems that are useful, but not necessary for your own program. For example, if you rescue the LoadError if term-ansicolor cannot be found by require, you can still proceed with your program, just without pretty colours.

And, of course, a more mundane use of exceptions and program state is saving a local copy of data when a remote resource becomes unavailable.

Do Not Swallow Exceptions

Exceptions are something the user has to be informed of when they happen (unless you can silently recover, but even then a message is appropriate). Even if you can clean up after yourself, make sure the underlying exception is propagated and kept intact! That you can recover from a specific exception doesn’t mean that everything else can. It’s all abotu being a good neighbor.

Further Reading

Avdi Grimm has written a whole book on Ruby exceptions: Exceptional Ruby: Master the art of handling failure in Ruby. I’ve seen rave reviews of the book, so I recommend checking it out if you have the cash to spare.

Resources

1 comment:

Unknown said...

Informative post. Actually I don't have any information regarding this.I want to know more about it.Please share some more post so that all the doubts will be clear.
digital certificates