Ruby-exceptions

提供:Dev Guides
移動先:案内検索

Ruby-例外

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

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

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

構文

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

_begin_から_rescue_までのすべてが保護されています。 このコードブロックの実行中に例外が発生した場合、_rescue_と_end_の間のブロックに制御が渡されます。

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

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

#!/usr/bin/ruby

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

これにより、次の結果が生成されます。 _open_が失敗したため、_STDIN_が_file_に置き換えられていることがわかります。

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

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

_rescue_ブロックを使用して例外をキャプチャし、_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が再割り当てされました。
  • 再試行することにより、開始の最初に行きました。
  • 今回はファイルが正常に開きます。
  • 本質的なプロセスを継続しました。

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

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番目の形式に似ていますが、_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.

_raise_の使用法を示すもう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"]

ensureステートメントの使用

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

_ensure_句はこれを行います。 _ensure_は、最後のレスキュー句の後に続き、ブロックの終了時に常に実行されるコードのチャンクを含みます。 ブロックが正常に終了するか、例外を発生させてレスキューするか、またはキャッチされなかった例外で終了した場合、_ensure_ブロックが実行されます。

構文

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_の前に配置されます。

_else_句の本体は、コード本体によって例外が発生しない場合にのみ実行されます。

構文

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

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

キャッチアンドスロー

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

_catch_は、指定された名前(SymbolまたはString)でラベル付けされたブロックを定義します。 ブロックは、スローが発生するまで通常実行されます。

構文

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

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

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

  • 割り込み
  • NoMemoryError
  • SignalException
  • ScriptError
  • StandardError
  • SystemExit

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

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

例を見てみましょう-

class FileSaveError < StandardError
   attr_reader :reason
   def initialize(reason)
      &commat;reason = reason
   end
end

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

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

ここで重要な行はraise _FileSaveError.new(&dollar;!)_です。 raiseを呼び出して例外が発生したことを通知し、FileSaveErrorの新しいインスタンスを渡します。その理由は、特定の例外が原因でデータの書き込みが失敗したためです。