Ruby exception
Exceptions and execution are always linked together. If you open a file that doesn't exist and don't handle the situation appropriately, your program is considered low quality.
If an exception occurs, the program stops. Exceptions are used to handle various types of errors that may occur during program execution, so appropriate action is taken without bringing the program to a complete halt.
Ruby provides a perfect mechanism for handling exceptions. We can enclose the code that may throw an exception in a begin/end block and use the rescue clause to tell Ruby what type of exception to handle.
Syntax
begin #开始 raise.. #抛出异常 rescue [ExceptionType = StandardException] #捕获指定类型的异常 缺省值是StandardException $! #表示异常信息 $@ #表示异常出现的代码位置 else #其余异常 .. ensure #不管有没有异常,进入该代码块 end #结束
Everything from begin to rescue is protected. If an exception occurs during the execution of a code block, control is passed to the block between rescue and end.
For each rescue clause in the begin block, Ruby compares the thrown exception with each argument in turn. If the exception named in the rescue clause is of the same type as the currently thrown exception, or is the parent class of that exception, the match is successful.
If the exception does not match all specified error types, we can use an else clause after all rescue clauses.
Example
#!/usr/bin/ruby begin file = open("/unexistant_file") if file puts "File opened successfully" end rescue file = STDIN end print file, "==", STDIN, "\n"
The output result of the above example is. You can see that STDIN replaces file because failed to open .
#<IO:0xb7d16f84>==#<IO:0xb7d16f84>
Use the retry statement
You can use the rescue block to catch the exception and then use the retry statement to start execution from the beginning begin Block.
Syntax
begin # 这段代码抛出的异常将被下面的 rescue 子句捕获 rescue # 这个块将捕获所有类型的异常 retry # 这将把控制移到 begin 的开头 end
Instance
#!/usr/bin/ruby begin file = open("/unexistant_file") if file puts "File opened successfully" end rescue fname = "existant_file" retry end
The following is the processing flow:
An exception occurred while opening.
Jump to rescue. fname is reassigned.
Jump to the beginning of begin through retry.
This time the file was opened successfully.
Continue with the basic process.
Note: If the renamed file does not exist, the code of this force will try infinitely. Therefore, use retry with caution when handling exceptions.
Using the raise statement
You can use the raise statement to throw an exception. The following method throws an exception when called. Its second message will be output.
Syntax
raise 或 raise "Error Message" 或 raise ExceptionType, "Error Message" 或 raise ExceptionType, "Error Message" condition
The first form simply rethrows the current exception (or a RuntimeError if there is no current exception). This is used in exception handlers that need to interpret the exception before passing it in.
The second form creates a new RuntimeError exception and sets its message to the given string. The exception is then thrown up the call stack.
The third form creates an exception using the first parameter, and then sets the related message as the second parameter.
The fourth form is similar to the third form, you can add any additional conditional statements (such as unless) to throw an exception.
Example
#!/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 after the begin block.'
The output result of the above example is:
I am before the raise. I am rescued. I am after the begin block.
Another example demonstrating raise usage:
#!/usr/bin/ruby begin raise 'A test exception.' rescue Exception => e puts e.message puts e.backtrace.inspect end
Above The output result of the instance running is:
A test exception. ["main.rb:4"]
Use ensure statement
Sometimes, regardless of whether an exception is thrown, you need to ensure that some processing is completed at the end of the code block. For example, you might have a file open when you enter, and when you exit the block, you need to make sure you close the file.
ensure This is what the clause does. ensure is placed after the last rescue clause and contains a block of code that is always executed when the block terminates. It doesn't matter whether the block exits gracefully, whether an exception is thrown and handled, or whether it terminates with an uncaught exception, the ensure block will always run.
Grammar
begin #.. 过程 #.. 抛出异常 rescue #.. 处理错误 ensure #.. 最后确保执行 #.. 这总是会执行 end
Example
begin raise 'A test exception.' rescue Exception => e puts e.message puts e.backtrace.inspect ensure puts "Ensuring execution" end
The output result of the above example is:
A test exception. ["main.rb:4"] Ensuring execution
Use else statement
If an else clause is provided, it is generally placed after the rescue clause and before any ensure.
else The body of the clause is only executed if the body of the code does not throw an exception.
Syntax
begin #.. 过程 #.. 抛出异常 rescue #.. 处理错误 else #.. 如果没有异常则执行 ensure #.. 最后确保执行 #.. 这总是会执行 end
Examples
begin # 抛出 '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
The output of the above example is:
I'm not raising exception Congratulations-- no errors! Ensuring execution
Use the $! variable to capture the error message thrown.
Catch and Throw
The exception mechanism of raise and rescue can give up execution when an error occurs. Sometimes it is necessary to jump out of some deeply nested structures during normal processing. This is where catch and throw come in handy.
catch Defines a block that uses the given name (can be a Symbol or String) as a label. The block will execute normally until a throw is encountered.
Syntax
throw :lablename #.. 这不会被执行 catch :lablename do #.. 在遇到一个 throw 后匹配将被执行的 catch end 或 throw :lablename condition #.. 这不会被执行 catch :lablename do #.. 在遇到一个 throw 后匹配将被执行的 catch end
Examples
In the following example, if the user types '!' in response to any prompt, a throw is used to terminate the interaction with the user.
def promptAndGet(prompt) print prompt res = readline.chomp throw :quitRequested if res == "!" return res end catch :quitRequested do name = promptAndGet("Name: ") age = promptAndGet("Age: ") sex = promptAndGet("Sex: ") # .. # 处理信息 end promptAndGet("Name:")
The above program requires human interaction, you can try it on your computer. The output result of the above example is:
Name: Ruby on Rails Age: 3 Sex: ! Name:Just Ruby
Class Exception
Ruby's standard classes and modules throw exceptions. All exception classes form a hierarchy, including the Exception class at the top. The next level down are seven different types:
Interrupt
NoMemoryError
SignalException
ScriptError
StandardError
SystemExit
Fatal is another exception in this layer, but the Ruby interpreter only uses it internally.
Both ScriptError and StandardError have some subclasses, but we don’t need to know those details here. The most important thing is to create our own exception classes, they must be subclasses of class Exception or its descendants.
Let us look at an example:
class FileSaveError < StandardError attr_reader :reason def initialize(reason) @reason = reason end end
Now, look at the following example, where the above exception will be used:
File.open(path, "w") do |file| begin # 写出数据 ... rescue # 发生错误 raise FileSaveError.new($!) end end
Here, the most important line is raise FileSaveError.new($!). We call raise to indicate that an exception has occurred, passing it to a new instance of FileSaveError that failed to write data due to the specific exception.