Ruby-例外

実行と例外は常に一緒に行われます。存在しないファイルを開いている場合、この状況を適切に処理しなかった場合、プログラムの品質が悪いと見なされます。

例外が発生すると、プログラムは停止します。そのため、例外は、プログラムの実行中に発生する可能性のあるさまざまなタイプのエラーを処理し、プログラムを完全に停止する代わりに適切なアクションを実行するために使用されます。

Rubyは、例外を処理するための優れたメカニズムを提供します。例外を発生させる可能性のあるコードをbegin / endブロックで囲み、rescue句を使用して、処理する例外のタイプをRubyに通知します。

構文

begin  
# -  
rescue OneTypeOfException  
# -  
rescue AnotherTypeOfException  
# -  
else  
# Other exceptions
ensure
# Always will be executed
end

開始から救助まですべてが保護されます。このコードブロックの実行中に例外が発生した場合、レスキュー終了の間のブロックに制御が渡されます。

Rubyは、beginブロックのレスキュー句ごとに、発生したExceptionを各パラメーターと順番に比較します。レスキュー句で指定された例外が現在スローされている例外のタイプと同じであるか、その例外のスーパークラスである場合、一致は成功します。

例外が指定されたエラータイプのいずれにも一致しない場合、すべてのレスキュー句の後にelse句を使用できます

#!/usr/bin/ruby

begin
   file = open("/unexistant_file")
   if file
      puts "File opened successfully"
   end
rescue
      file = STDIN
end
print file, "==", STDIN, "\n"

これにより、次の結果が得られます。開くことができなかったため、STDINファイルに置き換えられていることがわかります

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

再試行ステートメントの使用

レスキューブロックを使用して例外をキャプチャしてから、retryステートメントを使用してbeginブロックを最初から実行できます

構文

begin
   # Exceptions raised by this code will 
   # be caught by the following rescue clause
rescue
   # This block will capture all types of exceptions
   retry  # This will move control to the beginning of begin
end

#!/usr/bin/ruby

begin
   file = open("/unexistant_file")
   if file
      puts "File opened successfully"
   end
rescue
   fname = "existant_file"
   retry
end

プロセスの流れは次のとおりです。

  • オープン時に例外が発生しました。
  • 救助に行きました。fnameが再割り当てされました。
  • 再試行により、開始の最初に行きました。
  • この時間ファイルは正常に開きます。
  • 本質的なプロセスを続けた。

NOTE−再置換された名前のファイルが存在しない場合、このサンプルコードは無限に再試行することに注意してください。例外プロセスに再試行を使用する場合は注意してください。

raiseステートメントの使用

raiseステートメントを使用して例外を発生させることができます。次のメソッドは、呼び出されるたびに例外を発生させます。2番目のメッセージが印刷されます。

構文

raise 

OR

raise "Error Message" 

OR

raise ExceptionType, "Error Message"

OR

raise ExceptionType, "Error Message" condition

最初の形式は、現在の例外(または、現在の例外がない場合はRuntimeError)を再発生させるだけです。これは、例外を渡す前にインターセプトする必要がある例外ハンドラーで使用されます。

2番目の形式は、新しいRuntimeError例外を作成し、そのメッセージを指定された文字列に設定します。この例外は、コールスタックで発生します。

3番目の形式は、最初の引数を使用して例外を作成し、関連するメッセージを2番目の引数に設定します。

4番目の形式は3番目の形式に似ていますが、例外を発生させない限り、のような任意の条件ステートメントを追加できます。

#!/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.'

これにより、次の結果が生成されます-

I am before the raise.  
I am rescued.  
I am after the begin block.

レイズの使用法を示すもう1つの例-

#!/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"]

sureステートメントの使用

場合によっては、例外が発生したかどうかに関係なく、コードブロックの最後で何らかの処理が行われることを保証する必要があります。たとえば、ブロックへのエントリ時にファイルを開いていて、ブロックの終了時にファイルが閉じていることを確認する必要がある場合があります。

確実句はちょうどこれを行います。sureは最後のレスキュー句の後にあり、ブロックの終了時に常に実行されるコードのチャンクを含みます。通常、ブロックが終了した場合、それが上昇し、救出する例外を、またはそれがキャッチされない例外によって終了した場合、かどうかは、問題ではないことを確認のブロックが実行されます。

構文

begin 
   #.. process 
   #..raise exception
rescue 
   #.. handle error 
ensure 
   #.. finally ensure execution
   #.. This will always execute.
end

begin
   raise 'A test exception.'
rescue Exception => e
   puts e.message
   puts e.backtrace.inspect
ensure
   puts "Ensuring execution"
end

これにより、次の結果が生成されます-

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

elseステートメントの使用

else句が存在する場合は、rescue句の後、ensureの前に配置されます。

ボディ他の句は、例外がコードの本体によって提起されていない場合にのみ実行されます。

構文

begin 
   #.. process 
   #..raise exception
rescue 
   # .. handle error
else
   #.. executes if there is no exception
ensure 
   #.. finally ensure execution
   #.. This will always execute.
end

begin
   # raise '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

これにより、次の結果が生成されます-

I'm not raising exception
Congratulations-- no errors!
Ensuring execution

発生したエラーメッセージは$を使用してキャプチャできます!変数。

キャッチアンドスロー

レイズとレスキューの例外メカニズムは、問題が発生したときに実行を中止するのに最適ですが、通常の処理中に、深くネストされた構造から飛び出すことができると便利な場合があります。ここでキャッチアンドスローが役に立ちます。

キャッチ(記号又は文字列であってもよい)指定された名前でラベル付けされたブロックを定義します。ブロックは、スローが発生するまで通常どおり実行されます。

構文

throw :lablename
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end

OR

throw :lablename condition
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end

次の例では、throwを使用して、「!」の場合にユーザーとの対話を終了します。プロンプトに応答して入力されます。

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

上記のプログラムは手動で操作する必要があるため、マシンで試してみてください。これにより、次の結果が生成されます-

Name: Ruby on Rails
Age: 3
Sex: !
Name:Just Ruby

クラス例外

Rubyの標準クラスとモジュールは例外を発生させます。すべての例外クラスは階層を形成し、クラスExceptionが最上位にあります。次のレベルには7つの異なるタイプが含まれています-

  • Interrupt
  • NoMemoryError
  • SignalException
  • ScriptError
  • StandardError
  • SystemExit

このレベルにはもう1つの例外があります。 Fatal、ただし、Rubyインタープリターはこれを内部でのみ使用します。

ScriptErrorとStandardErrorの両方にいくつかのサブクラスがありますが、ここで詳細を説明する必要はありません。重要なことは、独自の例外クラスを作成する場合、それらはクラスExceptionまたはその子孫の1つのサブクラスである必要があるということです。

例を見てみましょう-

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

ここで、この例外を使用する次の例を見てください-

File.open(path, "w") do |file|
begin
   # Write out the data ...
rescue
   # Something went wrong!
   raise FileSaveError.new($!)
end
end

ここで重要な行は、fileSaveError.new($!)発生させることです。例外が発生したことを通知するためにraiseを呼び出し、FileSaveErrorの新しいインスタンスを渡します。これは、特定の例外が原因でデータの書き込みが失敗したためです。