Rescue Your Ruby Program: Intro to Error Handling
Tags: ruby, debugging, errors
Published: 2020-07-28 02:09:45

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.

```ruby
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.

<h2>Rescue in Ruby</h2>

```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:

```ruby
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.

<h2>Passing Arguments to Rescue</h2>

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.

```ruby
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.

```ruby
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.

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

<h2>Else and Ensure</h2>

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.

```ruby
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
```

<h2>Raising Errors</h2>

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.

```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.

```ruby
class MyCustomError < StandardError
end

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

<h2>Questions</h2>

Feel free to let me know in the comments:

<ol>
  <li>Have you used begin/end blocks in your code before?</li>
  <li>Have you ever created a custom error for a program or application?</li>
  <li>What is the error message you dread the most?</li>
  <li>What is your favorite error message?</li>
  <li>Other comments/questions?</li>
</ol>