Ruby Exception Handling

Ruby Exception Handling: RangeError

Making our way along through the Ruby Exception Handling series, today we’ll explore the RangeError within Ruby. Simply put, the RangeError is raised when a numerical value is provided to a Ruby method that falls outside the allowed range of values.

We’ll take some time in this article to fully explore the RangeError including where it resides within the Ruby Exception class hierarchy, along with a few code examples to illustrate some possible ways to raise RangeErrors yourself, so let’s get going!

The Technical Rundown

  • All Ruby exceptions are descendants of the Exception class, or a subclass therein.
  • StandardError is a direct descendant of the Exception class, and is also a superclass with many descendants of its own.
  • RangeError is a direct descendant of the StandardError class.

When Should You Use It?

To further explore the RangeError let’s start right out with some example code:

This produces the expected result of the first two values:

However, like many built-in Ruby methods, the first method we’re using on our Array expects the passed value to fall within a certain range. Like most programming languages, Ruby’s Integer value is four bytes in length, allowing the maximum value of an Integer to be 2,147,483,647. Many methods in Ruby, including Array.first that we used above, expect any passed numeric argument to be a valid Integer (or long), meaning the value cannot exceed that 2.14 million maximum.

So, what happens if we pass a number that’s just a bit larger than the maximum allowed for the Integer to the Array.firstmethod?

Ruby isn’t happy about this and it raises a RangeError, indicating the value we’ve provided is larger than an Integer (long), and is therefore a bignum:

That’s all well and good, and we can see how built-in Ruby methods might raise a RangeError, but what about raising a RangeError in our own code? When is it appropriate to use that type of error? To illustrate, we’ve created a Book class with three attributes: author, page_count, and title:

Simple enough. Now we can create an instance of our Book class within the create_book function:

This works just as expected, creating our book object and outputting the attribute data for it:

Our Book class places no restrictions or limitations on the attribute fields we’ve provided. Specifically, what if we need to create an abridged book class, which would only be valid for books with a limited number of pages? For that, we’ve inherited our Book class with the AbridgedBook class seen below:

We’ve also slightly changed the behavior of the page_count attribute from the original Book class it inherits from. We’re using attr_reader instead of attr_accessor, so we only automatically generate the getter method. For the setter of page_count=, we define the method ourselves so we can specify a valid range (1 to 1000) that the page_count attribute can fall within. If it’s outside these bounds, we raise a RangeError. Lastly, we’re using the super method call, which calls the superclass matching method (in this case initialize), so we don’t need to redefine the assignment of repeated fields like author and title.

To make use of AbridgedBook we have two functions, create_abridged_book and create_invalid_abridged_book. For create_abridged_book we are creating a book record for The Stand by Stephen King, which is 823 pages, falling within the valid range of page_count:

As expected, this works just fine and our AbridgedBook instance is created and we spit out some info about it:

However, within the create_invalid_abridged_book we can confirm that our range limitations for page_count are working by creating an book instance for War and Peace, which is a whopping 1225 pages:

As we hoped, our AbridgedBook.page_count= setter method catches this value and raises a RangeError as we asked it to, informing us that 1225 is outside the bounds we specified:

To get the most out of your own applications and to fully manage any and all Ruby Exceptions, check out the Airbrake Ruby exception handling tool, offering real-time alerts and instantaneous insight into what went wrong with your Ruby code, including integrated support for a variety of popular Ruby gems and frameworks.