Ruby 例外

例外と実行は常に関連しています。存在しないファイルを開こうとした場合、その状況を適切に処理しないと、プログラムは低品質とみなされます。

例外が発生するとプログラムは停止します。例外は、プログラムの実行中に発生する可能性のあるさまざまな種類のエラーを処理するために使用され、プログラムを完全に停止させることなく適切な対処を行えるようにします。

Ruby は例外を処理するための完璧なメカニズムを提供します。私たちはbegin/endbegin ブロック内に例外を発生させる可能性のあるコードを配置し、rescuerescue 節で Ruby に処理させる例外の種類を伝えます。

構文

begin #開始 raise.. #例外を発生させる rescue [ExceptionType = StandardException] #指定した型の例外を捕捉します。デフォルト値は StandardException です。 $! #例外情報を表示します $@ #例外が発生したコードの位置を表示します else #その他の例外 .. ensure #例外の有無にかかわらず、このコードブロックに入ります end #終了

からbegin 到 rescuebegin...end 内のすべてが保護されます。コードブロックの実行中に例外が発生した場合、制御はrescueとendrescue と end の間のブロックに移ります。

~についてはbeginブロック内の各rescuerescue 節について、Ruby は発生した例外と各パラメータを順番に比較します。rescue 節で指定された例外が現在発生している例外の型と同じか、またはその親クラスである場合にマッチします。

例外が指定されたすべてのエラータイプにマッチしない場合、私たちはすべてのrescuerescue 節の後にelseelse 節を使用できます。

例

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

上記の例の実行結果は次のとおりです。ご覧のとおり、STDINに置き換わりましたfile、なぜならファイルを開く失敗したからです。

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

使用retry文

あなたはrescuerescue ブロックで例外を捕捉し、次にretryretry 文で先頭からbeginbegin ブロックを実行します。

構文

begin #このコードで発生した例外は、次の rescue 節で捕捉されます。 rescue #このブロックはすべての種類の例外を捕捉します。 retry #これにより制御は begin の先頭に移動します。 end

例

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

以下は処理の流れです:

  • ファイルを開くときに例外が発生します。
  • rescue にジャンプします。fname が再代入されます。
  • retry によって begin の先頭にジャンプします。
  • 今回はファイルが正常に開かれました。
  • 通常の処理を続けます。

注意:もし再指定されたファイルが存在しない場合、この例のコードは無限に試行します。そのため、例外処理では慎重にretry。

使用raise文

文raiseraise 文を使用して例外を発生させることができます。次のメソッドは呼び出し時に例外を発生させます。その2番目のメッセージが出力されます。

構文

raise 或 raise "Error Message" 或 raise ExceptionType, "Error Message" 或 raise ExceptionType, "Error Message" condition

1番目の形式は、現在の例外を単に再発生させます(現在の例外がない場合は RuntimeError を発生させます)。これは、例外を渡す前に説明する必要がある例外ハンドラで使用されます。

2番目の形式は新しいRuntimeError例外を作成し、そのメッセージを指定された文字列に設定します。その例外はその後、呼び出しスタックにスローされます。

3番目の形式は、最初のパラメータで例外を作成し、関連するメッセージを2番目のパラメータに設定します。

4番目の形式は3番目の形式と似ています。追加の条件ステートメント(たとえばunless)を追加して例外を発生させることができます。

例

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

別のデモraiseraise の使用法を示す例:

例

#!/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文

例外が発生するかどうかに関係なく、コードブロックの終了時に特定の処理が完了することを保証する必要がある場合があります。たとえば、入り口でファイルを開いた場合、ブロックを終了するときにファイルを閉じることを保証する必要があります。

ensureensure 節がこれを行います。ensure は最後の rescue 節の後に置かれ、ブロックの終了時に常に実行されるコードブロックを含みます。ブロックが正常に終了するか、例外が発生して処理されるか、捕捉されない例外によって終了するかは関係ありません。ensureensure ブロックは常に実行されます。

構文

begin #.. 処理 #.. 例外を発生させる rescue #.. エラーを処理 ensure #.. 最後に ensure を実行 #.. これは常に実行される 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文

もしelseelse 節が提供される場合、通常はrescuerescue 節の後、任意のensureensure の前に配置されます。

elseelse 節の本体は、コード本体が例外を発生させなかった場合にのみ実行されます。

構文

begin #.. 処理 #.. 例外を発生させる rescue #.. エラーを処理 else #.. 例外がなければ実行 ensure #.. 最後に ensure を実行 #.. これは常に実行される end

例

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

上記の例の実行結果は次のとおりです:

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

$! 変数を使用すると、発生したエラーメッセージを取得できます。

Catch と Throw

raise と rescue の例外メカニズムは、エラー発生時に実行を放棄するものです。通常の処理中に深くネストされた構造から抜け出したい場合があります。そのようなときは catch と throw が役立ちます。

catchcatch は、指定された名前(Symbol または String)をラベルとして使用するブロックを定義します。ブロックは throw に遭遇するまで正常に実行されます。

構文

throw :lablename #.. これは実行されません catch :lablename do #.. throw に遭遇した後、マッチする catch が実行されます end 或 throw :lablename condition #.. これは実行されません catch :lablename do #.. throw に遭遇した後、マッチする catch が実行されます 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: ") # .. #メッセージ処理 end promptAndGet("Name:")

上記のプログラムは手動での対話が必要です。お使いのコンピュータで試すことができます。上記の例の実行結果は次のとおりです:

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

クラス Exception

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

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

Fatal はこの層のもう1つの例外ですが、Ruby インタプリタはそれを内部でのみ使用します。

ScriptError と StandardError にはいくつかのサブクラスがありますが、ここではその詳細を理解する必要はありません。最も重要なことは、独自の例外クラスを作成することです。それらは Exception クラスまたはその子孫のサブクラスでなければなりません。

例を見てみましょう:

例

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

次に、上記の例外を使用する次の例を見てみましょう:

例

File.open(path, "w") do |file| begin #データを書き込みます ... rescue #エラーが発生しました raise FileSaveError.new($!) end end

ここで最も重要な行は raise です。FileSaveError.new($!)私たちは raise を呼び出して例外が発生したことを示し、それを FileSaveError の新しいインスタンスに渡します。これは、特定の例外がデータ書き込みの失敗を引き起こしたためです。

その他の拡張