【Ruby】エラーハンドリングを完全に理解する7つのステップをプロが徹底的に解説

RubyエラーハンドリングのステップバイステップガイドRuby
この記事は約9分で読めます。

※本記事のコンテンツは、利用目的を問わずご活用いただけます。実務経験10000時間以上のエンジニアが監修しており、基礎知識があれば初心者にも理解していただけるように、常に解説内容のわかりやすさや記事の品質に注力しております。不具合・分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。(理解できない部分などの個別相談も無償で承っております)
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)


はじめに

あなたが初めてRubyプログラミングを始める時、エラーハンドリングは必要不可欠なスキルの一つです。

これにより、プログラムが意図しない動作をした時に適切に対処し、制御することが可能になります。

この記事では、Rubyでエラーハンドリングを行うための7つのステップを紹介します。

これを読めば、Rubyのエラーハンドリングの基本から応用まで、ステップバイステップで学ぶことができます。

●Rubyエラーハンドリングとは

Rubyエラーハンドリングとは、プログラム中で発生するエラー(例外)を適切に捕捉し、制御するための手段です。

Rubyには、エラーハンドリングのためのキーワードとして、beginrescueensureraiseretryが提供されています。

これらを使うことで、エラー発生時の動作を制御し、エラーメッセージを出力したり、エラー発生後のプログラムの動作を定義したりすることが可能です。

●エラーハンドリングの基本

Rubyのエラーハンドリングの基本は、beginrescueensureの3つのキーワードを使用することです。

○beginとrescue

エラーが発生する可能性のあるコードはbeginendで囲み、rescueを使ってその中で発生したエラーを捕捉します。

これにより、エラーが発生した時の処理を定義することができます。

□サンプルコード1:基本的なエラーハンドリング

begin
  # エラーが発生する可能性があるコード
  num = 1 / 0
rescue => e
  # エラーが発生したときの処理
  puts "エラーが発生しました:#{e.message}"
end

このコードでは、0で除算を試みているため、ZeroDivisionErrorが発生します。

しかし、このエラーはrescue節で捕捉され、エラーメッセージが出力されます。

なお、上記のコードを実行すると「エラーが発生しました:divided by 0」と表示されます。

○ensure

ensureは、begin節内でエラーが発生しようがしまいが、必ず実行されるコードを書くためのキーワードです。

これにより、エラーの発生に関係なく、必ず実行したい処理を定義することができます。

たとえば、ファイルのクローズやリソースの解放など、エラー発生後でも必ず行いたい処理をensure内に記述します。

□サンプルコード2:ensureの使用例

file = nil
begin
  # ファイルを開いて何かの処理を行う
  file = File.open("somefile.txt", "w")
  file.puts("Hello, world!")
rescue => e
  # エラーが発生した場合の処理
  puts "エラーが発生しました:#{e.message}"
ensure
  # 必ず最後にファイルを閉じる
  file.close unless file.nil?
end

このコードでは、File.openを使ってファイルを開いています。

そしてputsメソッドで文字列を書き込んでいます。

もし何らかのエラーが発生した場合、rescue節がエラーを捕捉してエラーメッセージを出力します。

そしてensure節にあるfile.closeが必ず実行され、開いたファイルが閉じられます。

このコードを実行すると、エラーが発生しない場合は何も出力されませんが、エラーが発生した場合にはエラーメッセージが出力され、最終的に開いたファイルが必ず閉じられます。

○raise

raiseは、明示的にエラー(例外)を発生させるためのキーワードです。

raiseを使用することで、プログラム中の特定の状況下で例外を発生させ、その例外をrescueで捕捉することが可能となります。

□サンプルコード3:raiseの使用例

def check_age(age)
  raise "Invalid age" if age < 0
  "Age is #{age}"
end

begin
  puts check_age(-1)
rescue => e
  puts "エラーが発生しました:#{e.message}"
end

このコードでは、年齢をチェックするメソッドcheck_ageを定義しています。

このメソッドでは、年齢が0未満の場合にraiseを使用してエラーを発生させています。

これにより、年齢が0未満という無効な値が入力された場合にエラーを発生させ、そのエラーをrescueで捕捉しています。

このコードを実行すると、「エラーが発生しました:Invalid age」と表示されます。

●エラーハンドリングの応用

エラーハンドリングの基本的な概念として、beginrescueensureraiseを紹介しましたが、これらを組み合わせることで更に高度なエラーハンドリングが可能になります。

ここからは、それらの応用的な使い方を紹介します。

○retry

retryは、エラーが発生した時にそのエラーを捕捉し、同じ処理を再実行するためのキーワードです。

retryrescue節の中で使われます。エラーが発生した場合にそのエラーを捕捉し、再度処理を実行することができます。

これは一時的なエラー、例えばネットワーク接続の問題など、再試行によって解決可能なエラーの場合に特に役立ちます。

□サンプルコード4:retryの使用例

begin
  tries ||= 3
  # ネットワークからデータを読み込むなどの処理
  puts "ネットワーク接続を試みます..."
  raise "ネットワークエラー"
rescue => e
  if (tries -= 1) > 0
    puts "エラーが発生しました。再試行します(残り#{tries}回):#{e.message}"
    retry
  else
    puts "エラーが続いています。処理を終了します:#{e.message}"
  end
end

このコードでは、ネットワークからデータを読み込む処理を模擬的に行っています。

この処理でエラーが発生した場合、rescue節がエラーを捕捉し、再試行するためにretryを使用しています。

再試行は最大3回行われ、それでもエラーが続く場合は処理を終了します。

このコードを実行すると、”エラーが発生しました。再試行します(残り2回):ネットワークエラー”、”エラーが発生しました。

再試行します(残り1回):ネットワークエラー”、”エラーが続いています。処理を終了します:ネットワークエラー”というメッセージが順に表示されます。

○エラークラスのカスタマイズ

Rubyでは、標準的なエラークラスを使うだけでなく、独自のエラークラスを定義して使用することもできます。

これにより、アプリケーション特有のエラー条件をより詳細に表現することが可能になります。

独自のエラークラスを作るには、StandardErrorクラスまたはそのサブクラスを継承して新しいクラスを定義します。

□サンプルコード5:カスタムエラークラスの作成

class MyCustomError < StandardError
  def initialize(message="カスタムエラーが発生しました")
    super
  end
end

begin
  # エラーを発生させる
  raise MyCustomError
rescue MyCustomError => e
  puts "エラーを捕捉しました:#{e.message}"
end

このコードでは、MyCustomErrorという独自のエラークラスを作成しています。

このエラークラスはStandardErrorを継承し、特殊メソッドinitializeをオーバーライドしてデフォルトのエラーメッセージを設定しています。

その後、raiseキーワードを使用してこのカスタムエラーを発生させ、それをrescue節で捕捉しています。

このコードを実行すると、”エラーを捕捉しました:カスタムエラーが発生しました”と表示されます。

●エラーハンドリングの注意点

エラーハンドリングを行う際には、次の点に注意してください。

①適切なエラークラスを指定する

Rubyは多数のビルトインエラークラスを持っています。

これらを適切に利用し、具体的なエラータイプに対応するエラーハンドリングを実装しましょう。

②rescueで全てのエラーを捕捉しない

具体的なエラークラスを指定しないrescueは全てのエラーを捕捉します。

これは意図しないエラーも捕捉してしまう可能性があるため、避けるべきです。

③エラーメッセージを明確にする

エラーメッセージは問題を診断するための重要な情報源です。

エラーの原因と解決策を明確に伝えるメッセージを提供しましょう。

④retryの使用に注意する

retryを使うと、特定のエラーに対する再試行を容易に実装できます。

しかし、無制限にretryすると無限ループに陥る可能性があるため、再試行回数を適切に制限することが重要です。

●エラーハンドリングのベストプラクティス

Rubyにおけるエラーハンドリングのベストプラクティスをいくつか紹介します。

①例外処理を適切にレイヤリングする

システム全体で一貫したエラーハンドリング戦略を持つことは重要です。システムの各部分が自己完結型で、適切なレベルの例外処理を行うことを確認しましょう。

②デバッグを容易にする

デバッグを容易にするために、エラーメッセージにはエラーが発生した具体的な状況を含めるようにしましょう。

③予期しないエラーに対しては再試行しない

予期しないエラーが発生した場合、そのエラーを解決するまでの間、同じ操作を繰り返すことは避けるべきです。

④エラーを報告する

エラーが発生した場合には、それをログやエラートラッキングシステムに報告しましょう。

これにより、エラーの発生源を追跡しやすくなります。

例外を発生させるタイミングを選ぶ: 例外は本当に例外的な状況でのみ使用すべきです。

エラーチェックの一部として頻繁に例外を使用すると、コードが読みにくくなり、パフォーマンスにも影響を与えます。

まとめ

Rubyでのエラーハンドリングは、プログラムの安定性と信頼性を向上させる重要な技術です。

この記事では、エラーハンドリングの基本からbegin, rescue, ensure, raise, retryの使用方法、カスタムエラークラスの作成方法、そしてエラーハンドリングのベストプラクティスまで、7つのステップで詳しく解説しました。

これらの知識を活用し、より良いコードを書くように努めましょう。

エラーは必ずしも悪いものではなく、それを適切に処理することで、ソフトウェアをより堅牢で信頼性の高いものにすることができます。