English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Ruby Exceptions

Exceptions and execution are always associated. If you open a non-existent file and do not handle this situation properly, then your program is considered of 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 actions should be taken without causing the program to stop completely.

Ruby provides a perfect mechanism for handling exceptions. We can begin/end Attach the code that may throw an exception in the block and use rescue The clause tells Ruby the type of exception to be handled perfectly.

Syntax

begin # start
 
 raise.. # throws an exception
 
rescue [ExceptionType = StandardException] # catches exceptions of specified type, the default is StandardException
 $! # indicates the exception information
 $@ # indicates the code location where the exception occurred
else # other exceptions
 ..
ensure # Enter the code block regardless of whether there is an exception
 
end # end

from begin to rescue everything is protected. If an exception occurs during the execution of the code block, control will pass to rescue and end between

for begin each rescue clauses, Ruby will compare the thrown exception with each parameter in turn. If the exception named in the 'rescue' clause matches the current thrown exception type or is a superclass of the exception, then the match is successful.

If the exception does not match all the specified error types, we can put all the rescue After the 'rescue' clause, use a else clause.

Online Examples

#!/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 of the above example is as follows. You can see that,STDIN replaced file becauseopeningfailed.

#<IO:0xb7d16f84>==#<IO:0xb7d16f84>

使用 retry 语句

You can use rescue block catches an exception and then uses retry The statement starts executing from the beginning begin block.

Syntax

begin
    # The exception thrown by this code block will be caught by the following 'rescue' clause
rescue
    # This block will catch all types of exceptions
    retry # This will move the control back to the beginning of 'begin'
end

Online Examples

#!/usr/bin/ruby
 
begin
   file = open("/unexistant_file)
   if file
      puts "File opened successfully"
   end
rescue
   fname = "existant_file"
   retry
end

Here is the process of handling:

  • An exception occurred when opening.

  • Jump to 'rescue'. 'fname' is reassigned.

  • Jump back to the beginning of 'begin' through retry.

  • This time the file was successfully opened.

  • Continue the basic process.

Note:If the renamed file does not exist, this example code will try indefinitely. So be cautious when using exception handling in this case. retry.

使用 raise 语句

You can use raise The statement throws an exception. The following method throws an exception when called. Its second message will be output.

Syntax

raise 
 
Or
 
raise "Error Message" 
 
Or
 
raise ExceptionType, "Error Message"
 
Or
 
raise ExceptionType, "Error Message" condition

The first form simply re-throws the current exception (if there is no current exception, it throws a RuntimeError). This is used in exception handling programs that need to explain exceptions before passing them.

The second form creates a new RuntimeError Exception, set its message to the given string. The exception is then thrown to the call stack.

The third form creates an exception using the first parameter and then sets the related message to the second parameter.

第四种形式与第三种形式类似,您可以添加任何额外的条件语句(比如 unless)来抛出异常。

Online Examples

#!/usr/bin/ruby
 
begin  
    puts '我在 raise 之前.'  
    raise 'An error has occurred.'  
    puts '我在 raise 之前.'  
rescue  
    puts '我被 rescue 了.'  
end  
puts '我在 begin 块之后.'

以上示例运行输出结果为:

我在 raise 之前。  
我被 rescue 了。  
我在 begin 块之后。

另一个演示 raise 用法的示例:

Online Examples

#!/usr/bin/ruby
 
begin  
  raise 'A test exception.'  
rescue Exception => e  
  puts e.message  
  puts e.backtrace.inspect  
end

以上示例运行输出结果为:

A test exception.
["main.rb:4"]

使用 ensure 语句

有时候,无论是否抛出异常,您需要保证一些处理在代码块结束时完成。例如,您可能在进入时打开了一个文件,当您退出块时,您需要确保关闭文件。

ensure 子句做的就是这个。ensure 放在最后一个 rescue 子句后,并包含一个块终止时总是执行的代码块。它与块是否正常退出、是否抛出并处理异常、是否因一个未捕获的异常而终止,这些都没关系,ensure 块始终都会运行。

Syntax

begin 
   #.. 过程
   #.. 抛出异常
rescue 
   #.. 处理错误 
ensure 
   #.. 最后确保执行
   #.. 这总是会执行
end

Online Examples

begin
  raise 'A test exception.'
rescue Exception => e
  puts e.message
  puts e.backtrace.inspect
ensure
  puts "确保执行"
end

以上示例运行输出结果为:

A test exception.
["main.rb:4"]
确保执行

使用 else 语句

如果提供了 else 子句,它一般是放置在 rescue 子句之后,任意 ensure 之前。

else 子句的主体只有在代码主体没有抛出异常时执行。

Syntax

begin 
   #.. 过程 
   #.. 抛出异常
rescue 
   #.. 处理错误
else
   #.. 如果没有异常则执行
ensure 
   #.. 最后确保执行
   #.. 这总是会执行
end

Online Examples

begin
 # 抛出 'A test exception.'
 puts "我没有抛出异常"
rescue Exception => e
  puts e.message
  puts e.backtrace.inspect
else
   puts "恭喜-- 没有错误!"
ensure
  puts "确保执行"
end

以上示例运行输出结果为:

我没有抛出异常
恭喜-- 没有错误!
确保执行

The $! variable can be used to capture the error message thrown.

Catch and Throw

The exception mechanism of raise and rescue can give up execution when an error occurs, and sometimes it is necessary to jump out of some deeply nested structures during normal processing. In such cases, catch and throw come into play.

Catch It defines a block that uses the given name (which can be a Symbol or String) as a label. The block will execute normally until it encounters a throw.

Syntax

throw :lablename
#.. This will not be executed
catch :lablename do
#.. A match will be executed after encountering a throw
end
 
Or
 
throw :lablename condition
#.. This will not be executed
catch :lablename do
#.. A match will be executed after encountering a throw
end

Online Examples

In the following example, if the user enters '!' in response to any prompt, use a throw to terminate the interaction with the user.

Online Examples

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: ")
   # ..
   # Handle information
end
promptAndGet("Name:")

The above program requires manual interaction, and 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 raise exceptions. All exception classes form a hierarchy, including the top-level Exception class. The next level consists of seven different types:

  • Interrupt

  • NoMemoryError

  • SignalException

  • ScriptError

  • StandardError

  • SystemExit

Fatal is another exception in this layer, but the Ruby interpreter only uses it internally.

ScriptError and StandardError both have subclasses, but we do not need to understand these details here. The most important thing is to create our own exception classes, which must be subclasses of class Exception or its subclasses.

Let's look at an example:

Online Examples

class FileSaveError < StandardError
   attr_reader :reason
   def initialize(reason)
      @reason = reason
   end
end

Now, let's look at the following example, which will use the above exception:

Online Examples

File.open(path, "w") do |file|
begin
    # Write data ...
rescue
    # Error Occurred
    raise FileSaveError.new($!)
end
end

Here, the most important line is raise FileSaveError.new($!)We use raise to indicate that an exception has occurred, passing it to a new instance of FileSaveError due to a specific exception causing the data write to fail.