DEV Community

loading...

Rescue Your Ruby Program: Intro to Error Handling

lberge17 profile image Laura Berge ・3 min read

In Ruby, any time our code throws an error, our program will break. Now, this is often a good feature because errors tell us what our bug is and where in the code it's located. However, sometimes we have some code that may throw an error, such as getting user input that isn't what we expected. Let's say we have a calculator program and a user tries to divide a number by 0.

loop do
    print "Please enter a base number:"
    x = gets
    print "Please enter a divisor:"
    y = gets
    puts x.to_i * y.to_i
end

The code above will throw a ZeroDivisionError if y is equal to zero or a non-number string. (Strings converted to integers in ruby evaluate to 0). However, we don't want our program to break when the user inputs 0. Instead, we want to let them know that dividing a number by 0 is impossible in math. So, we need to find a way to display a message to the user and keep our program going. We can accomplish this using a rescue in Ruby.

Rescue in Ruby

begin
    # code to execute that may throw an error
rescue
    # code that is executed if the above code throws an error
end

In our case, we could write the code like:

loop do
    print "Please enter a base number:"
    x = gets
    print "Please enter a divisor:"
    y = gets
    puts y
    begin
        puts x.to_i / y.to_i
    rescue
        puts "Sorry, the divisor you entered is invalid. Please enter a non-zero number for the divisor."
    end
end

If the user enters an invalid divisor, the error message is shown and the program continues to run. Now we can even be more specific if we know what errors we're expecting.

Passing Arguments to Rescue

Rescue by default handles any StandardError, but we can a specific error as an argument. If we pass in an error like TypeError, that rescue block will only execute if the error thrown is a TypeError.

loop do
    print "Please enter a base number:"
    x = gets
    print "Please enter a divisor:"
    y = gets
    puts y
    begin
        puts x.to_i / y.to_i
    rescue ZeroDivisionError
        puts "Sorry, the divisor you entered is invalid. Please enter a non-zero number for the divisor."
    end
end

In this way, we can handle multiple errors differently in the same statement.

begin
    # the code in question
rescue ZeroDivisionError
    # execute code specific to this error
rescue TypeError
    # so on
rescue ArgumentError
    # and so forth
end

We can also operate on the error thrown as a variable.

begin
    # the code in question
rescue => error
    puts "A #{error.class} was thrown: #{error.message}"
end

Else and Ensure

In our begin-end block, we can also use else and ensure statements. The else block will run if no exception is thrown, and the ensure block will always run.

begin
    # code in question
rescue
    puts "Oops we have an error..."
else
    puts "No errors here"
ensure
    puts "I will always run - error or not!"
end

Raising Errors

Now that we know a bit about how to rescue our errors, what if we actually want to raise a custom error of our own? We can do this using raise in Ruby.

raise StandardError.new("custom error message")

If you have a program that needs a new type of error, you can also create one using class inheritance.

class MyCustomError < StandardError
end

if true
    raise MyCustomError("my custom error message")
end

Questions

Feel free to let me know in the comments:

  1. Have you used begin/end blocks in your code before?
  2. Have you ever created a custom error for a program or application?
  3. What is the error message you dread the most?
  4. What is your favorite error message?
  5. Other comments/questions?

Discussion (0)

pic
Editor guide