liveBook · Manning

Exception

As explained in The Well-Grounded Rubyist, Fourth Edition

An exception is a Ruby runtime event representing an abnormal condition that interrupts ordinary program execution and can be handled by exception mechanisms.

A program can pass `ruby -cw` and still fail while running. If it divides by zero, Ruby raises a `ZeroDivisionError`: normal execution stops. An exception is an object whose class descends from `Exception`. Without a matching rescue clause, the program terminates; with one, control moves to the rescue clause. section 6.4 section 6.4.1

print "Enter a number: "
n = gets.to_i
begin
  result = 100 / n
rescue
  puts "Your number didn't work. Was it zero???"
  exit
end
puts "100/#{n} is #{result}."

Try entering zero, then a nonzero number. Zero sends execution from `100 / n` to `rescue`; successful division skips the rescue clause and prints the result. section 6.4.2

A bare `rescue` handles descendants of `StandardError`, but `rescue ZeroDivisionError` targets that failure alone. Prefer a specific class when another error should remain visible. Within a method or `do/end` block, `rescue` can apply without an explicit `begin`; add `begin/end` when only part of the body should be protected. section 6.4.2

You can also raise and inspect exceptions yourself:

  • `raise ArgumentError, "I need a number under 10"` supplies a class and message. `raise "Problem!"` instead raises `RuntimeError` with that message. section 6.4.5
  • `rescue ArgumentError => e` captures the exception instance. `e.message` gives its message; `e.backtrace` gives a call-stack trail of methods, files, and line numbers. section 6.4.6
  • A rescue clause can log a failure and then use bare `raise` to re-raise it. An `ensure` clause runs whether or not an exception occurs, making it suitable for closing an opened file handle. section 6.4.6 section 6.4.7
class InvalidLineError < StandardError
end
def line_from_file(filename, substring)
  fh = File.open(filename)
  line = fh.gets
  raise InvalidLineError unless line.include?(substring)
  return line
  rescue InvalidLineError
    puts "Invalid line!"
    raise
  ensure
    fh.close
end

A custom `InvalidLineError` names a particular failure. Its rescue clause handles that class, re-raises it after reporting it, and uses `ensure` to close the file handle; other failures can propagate. section 6.4.8 section 6.4.7

Custom exceptions usually inherit from `StandardError`, so bare `rescue` can catch them. Nesting their classes in a module avoids name clashes. For file operations, `Errno` classes identify system-level failures such as a missing file (`Errno::ENOENT`) or denied permission (`Errno::EACCES`). section 6.4.8 section 12.2.9

How The Well-Grounded Rubyist, Fourth Edition covers it

How deep it goes
Works through raising, targeted rescue, inspection, re-raising, custom classes, and ensure; defers block-based file closing.
Examples
Uses division by zero, number validation, invalid file lines, and file-system errors to illustrate failures and handling.
What it assumes
Assumes familiarity with methods, blocks, and classes while defining exception objects and demonstrating rescue from a small division example.
What you can do after
Practice/perform targeted rescue, explicit raising, exception inspection, re-raising, and cleanup with ensure.
How it connects
Connects exception handling to control flow, class inheritance, method and block scope, and file I/O.

Also explained in

Compare how 25 books explain exception →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Well-Grounded Rubyist, Fourth Edition. The section links point to the parts of the book it draws on.