Exceptions and executions are always linked together. If you open a file that does not exist and you do not properly handle the situation, your program is considered to be of low quality.
If an exception occurs, the program stops. Exceptions are used to handle various types of errors that may occur during the execution of a program, so take the appropriate action and not let the program stop altogether.
Ruby provides a perfect mechanism for handling exceptions. We can enclose code in the Begin/end block that might throw an exception, and use the rescue clause to tell Ruby the perfect type of exception to handle.
Grammar
Begin
#-
Rescue onetypeofexception
#-
Rescue anothertypeofexception
#-
Else
# Other exceptions
ensure
# is always executed
end
Everything from begin to rescue is protected. If an exception occurs during code block execution, the control is passed to the block between rescue and end.
For each rescue clause in the Begin block, Ruby compares the thrown exception to each parameter in turn. If the exception named in the rescue clause is the same as the currently thrown exception type, or is the parent class of the exception, the match succeeds.
If the exception does not match all of the specified error types, we can use an ELSE clause after all the rescue clauses.
Instance
#!/usr/bin/ruby
begin
File = open ("/unexistant_file")
if file
puts "file opened successfully"
End
Rescue
file = stdin
end
print file, "= =", stdin, "\ n"
This will produce the following results. As you can see, STDIN replaces file because it failed to open.
#<io:0xb7d16f84>==#<io:0xb7d16f84>
using the retry statement
You can use the rescue block to catch an exception and then use the Retry statement to start the Begin block from the beginning.
Grammar
Begin
# The exception thrown by this code will be captured by the following rescue clause
Rescue
# This block captures all types of exceptions
Retry # This will move control to the start end
instance of
begin
#!/usr/bin/ruby
begin
File = open ("/unexistant_file")
if file
puts "file opened successfully '
End
rescue
fname = ' existant_file '
retry
End
Here is the processing process:
- An exception occurred while opening.
- Jump to rescue. FName is being assigned a new value.
- Jumps through the retry to the beginning of the begin.
- The file was successfully opened.
- Continue the basic process.
Note: If the renamed file does not exist, the power code will try indefinitely. So when handling exceptions, use retry sparingly.
using the Raise statement
You can use the raise statement to throw an exception. The following method throws an exception at call time. Its second message will be output.
Grammar
Raise
or
raise "error message"
or
raise Exceptiontype, "error message"
or
raise Exceptiontype, "Error message" condition
The first form simply throws the current exception back (throws a runtimeerror if there is no current exception). This is used in an exception handler that needs to interpret an exception before passing in an exception.
The second form creates a new RuntimeError exception and sets its message to the given string. The exception is thrown to the call stack.
The third form creates an exception using the first parameter, and then sets the related message to the second argument.
The fourth form is similar to the third form, and you can add any additional conditional statements (such as unless) to throw the exception.
Instance
#!/usr/bin/ruby
begin
puts ' I am before the raise. '
Raise ' An error has occurred. '
Puts ' I am after the raise. '
Rescue
puts ' I am rescued. '
End
puts ' I am on the begin block. '
This will produce the following results:
I am before the raise.
I am rescued.
I am after the "Begin block."
Another example that demonstrates raise usage:
#!/usr/bin/ruby
begin
Raise ' A test exception. '
Rescue Exception => e
puts E.message puts end
This will produce the following results:
A Test exception.
["Main.rb:4"]
Using the ensure statement
Sometimes, whether or not an exception is thrown, you need to ensure that some processing completes at the end of the code block. For example, you might open a file when you enter, and when you exit the block, you need to be sure to close the file.
This is what the ensure clause does. Ensure is placed after the last rescue clause and contains a block of code that is always executed when a block terminates. It does not matter whether the block exits normally, throws and handles the exception, and whether it terminates with an ensure exception, which is all right, and the block will always run.
Grammar
Begin
# ... process # ...
throws an exception
rescue # ...
handling Errors
ensure #.
finally ensure execution
#. This always executes end
instance
begin
raise ' A test exception. '
Rescue Exception => E puts E.message puts E.backtrace.inspect ensure puts
"Ensuring execution" End
This will produce the following results:
A Test exception.
["Main.rb:4"]
ensuring execution
Use Else statement
If the ELSE clause is provided, it is generally placed after the rescue clause, before any ensure.
The body of the ELSE clause is executed only if the code body does not throw an exception.
Grammar
Begin
# ... process # ...
throw an exception
rescue # ...
handle errors
Else # ...
if there are no exceptions, execute
ensure
# ... finally ensure that the execution
#.. this always executes the
end
instance
begin
# throw ' A test exception. '
Puts "I ' m not raising exception"
Rescue exception => e
puts
' e.message puts E.backtrace.inspect Else
puts "congratulations--no errors!"
Ensure
puts "ensuring execution"
end
This will produce the following results:
I ' m not raising exception
congratulations--no errors!
ensuring execution
Using $! A variable can capture an error message that is thrown.
Catch and Throw
The exception mechanism for raise and rescue can give up execution in the event of an error, and sometimes need to jump out of the deep nesting structure while normal processing occurs. The catch and the throw came in handy at this point.
Catch defines a block that uses the given name (which can be a Symbol or String) as a label. The block will perform properly knowing that a throw has been encountered.
Grammar
Throw:lablename
#. This will not be executed
catch:lablename do
#. Matches the catch end OR throw that will be executed after a throw is encountered
: Lablename Condition
# ... this will not be executed
catch:lablename do
#. Match the catch end that will be executed after a throw is encountered
Instance
In the following instance, if the user types '! ' to respond to any prompts, use a throw to terminate the interaction with the user.
def promptandget (prompt)
print prompt
res = readline.chomp
throw:quitrequested if res = = "!"
return res
-
catch:quitrequested do
name = Promptandget (' name: ') Age
= Promptandget (' Age: ') C21/>sex = Promptandget ("Sex:")
#.
# Processing Information
end
promptandget (' Name: ')
The above program requires human interaction and you can try it on your computer. This will produce the following results:
Name:ruby on Rails
age:3
Sex:!
Name:just Ruby
Class Exception
Ruby's standard classes and modules throw exceptions. All the exception classes comprise a hierarchy, including the top Exception class. The next layer is seven different types:
- Interrupt
- Nomemoryerror
- Signalexception
- Scripterror
- StandardError
- Systemexit
- Fatal is another exception in the layer, but the Ruby interpreter only uses it internally.
Scripterror and StandardError have some subclasses, but we don't need to know these details here. The most important thing is to create our own exception classes, which must be subclasses of class Exception or their descendants.
Let's look at an example:
Class Filesaveerror < StandardError
Attr_reader:reason
def Initialize (reason)
@reason = Reason
End End
Now, looking at the example below, you will use the above exception:
File.Open (Path, "w") do |file|
Begin
# Write data ...
Rescue
# Error
raise Filesaveerror.new ($!)
End End
The most important line here is raise Filesaveerror.new ($!). We call raise to indicate that the exception has occurred, passing it to a new instance of Filesaveerror, which caused the data write to fail due to a particular exception.