Exceptions are unexpected events that disrupt an application’s flow. Ruby’s exception-handling features make it easy to manage these errors, ensuring applications remain stable and user-friendly.
Here's an example of common exception handling flow in Ruby:
begin
do_something # may raise an exception
1/0 # raises an exception
rescue ZeroDivisionError => e
# `ZeroDivisionError` exception handler
else
# If no exceptions were raised
ensure
# Code which always gets executed
end
In this article, I’ll share a few tips on effectively handling exceptions in Ruby to keep your applications running smoothly.
fail
with error
fail
is a lesser-known keyword for raising errors in an application. However, it adds clarity to the code when you want it to explicitly fail and the program to exit.
Let's see an example:
begin
fail "The weather is too bad for this code to work."
rescue
puts "I'll try tomorrow."
exit 0
end
In this example, fail raises an error just like raise does. However, fail conveys a clearer intention from the developer for the application to fail.
rescue
with multiple exceptions
rescue
statement shares simillar syntax to case
operator.
case foo
when Number, Decimal
puts "It is a number"
when String
puts "It is a string"
end
begin
do_something
rescue NoMethodError, NameError
puts "Method or variable is not defined"
rescue RuntimeError
puts "Runtime error occured"
end
This allows for clear handling of various error scenarios while maintaining readability in the code.
Rescueing from Exception
The Exception class is the base of Ruby's exception hierarchy. Therefore, when you rescue Exception, you are effectively rescuing from all Ruby built-in exceptions, including its subclasses like SyntaxError, LoadError, and Interrupt.
begin
do_something
rescue Exception => e # bad
rescue => e # bad
end
Exception#cause
In Ruby, we can always rescue and raise another exception, which is a common pattern. The Exception#cause
method allows you to check if an exception was raised by another exception, and if so, it enables you to trace it back, making it easier to debug the code.
begin
begin
1/0
rescue
raise RuntimeError
end
rescue => e
puts e.class
puts e.cause.class
end
# Output:
RuntimeError
ZeroDivisionError
Current exception with $!
Ruby stores current exception in a $!
variable which you can access in a code or whilst in a debuggig session in console.
begin
raise RuntimeError, "It's hammertime"
rescue RuntimeError
puts $!.message
end
# Outputs:
"It's hammertime"
In this short post, we explored several tips for effective exception handling in Ruby. Using fail for clear error signaling, managing multiple exceptions with rescue, and leveraging Exception#cause
for tracing errors are all strategies that enhance code readability and maintainability.
Thank you for reading and see you next time 🚀