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:
- Have you used begin/end blocks in your code before?
- Have you ever created a custom error for a program or application?
- What is the error message you dread the most?
- What is your favorite error message?
- Other comments/questions?
Top comments (0)