What is an Exception?
Exceptions are an exceptional state in the course of the code. It’s a way for the programming language to let the programmer/user know that there is an unforseen process causing unexpected behavior.
In most programming language, when an exception is raised, the program stops and a message is sent back.
42 + 'answer'
# => TypeError (String can't be coerced into Integer)A lot of programming language provides a hierarchy of built-in classes to simplify the exception handling.
In Ruby, the very first exception class is the Exception class, which has several subclasses, many of which also have descendents of their own.
Exception to Handle
Exceptions can and for some should be handled. In Ruby, the descendents of the StandardError class are errors which are safe to handle. They are caused by circumstances such as unexpected user input, faulty type conversions or dividing by zero.
Some errors, however, must not be handled; doing so would be dangerous. Handling them would result in masking critical errors and can make debugging more difficult than it already is.
This include importants errors such as NoMemoryError, SyntaxError and LoadError.
How to Handle an Exceptional State
In Ruby, we use the begin/rescue block to handle errors. The block prevent your program from stopping if the specified exception is raised.
begin
# do something dangerous here
rescue TypeError
# do something if TypeError is raised
rescue ArgumentError
# do something else if ArgumentError is raised
end
When a issue is raised between begin and rescue, Ruby stops the execution of the code and goes straight to the rescue block. In other words:
begin
array.fetch(index) # The index is out of bonds
puts "This code won't execute if out of bonds"
rescue IndexError
puts "Out of bonds!"
end
In the code above, te puts method call behind the array.fetch line will not execute if index is out of bonds; Ruby goes straight to rescue.
It is also possible to specify multiple exception on the same line in order to take the same action for more than one type of exception:
begin
# do something dangerous here
rescue ZeroDivisionError, TypeError
# do something if ZeroDivisionError or TypeError are raised
endUseful Clauses in Ruby
There are several useful clause to use along the begin/rescue block. Let’s see some of them.
begin
# do something dangerous here
rescue
# handle the inevitable exception
ensure
# do this every time, exception or not
end
ensure is run whether an exception was raised or not. It’s useful to close file or connection with database, for example.
Another example is retry: it lets you retry running your code after it raised an exception:
RETRY_LIMIT = 5
begin
attempts = attempts || 0
# do something dangerous
rescue
attempts += 1
retry if attempts < RETRY_LIMIT
endThis is useful when dealing with network connection and remote connection, where the line can sometime be busy.
Manually Raising Exceptions
It is possible to manually raises exception. In Ruby, it is done with the… raise method!
raise TypeError.new("Task failed successfully.")Exceptions raised manually can, or course, be handled in the same manner as exceptions Ruby raises automatically.
Crate Custom Exceptions
Exceptions being classes, we can create our own custom exception classes, if we so wish.
class ValidateSomethingError < StandardError
# validate something one way or anotehr
end