Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Rubyのbegin/rescueキーワードで例外処理をマスターする方法

Rubyでプログラミングをしていると、エラーメッセージに遭遇することがよくあります。技術的な用語では、これらを「例外(exception)」と呼びます。

例外には予期できるもの予期できないものがあります。例えば、ファイルが存在する場合と存在しない場合があるケースや、何らかの制限によって一時的にしか利用できないAPIなどは、予期できる例外の典型例です。

この記事では、予期できるエラーへの対処方法を学びます。

その方法は?

答えは、Rubyの「begin」と「rescue」という2つのキーワードです。これらはエラー状態を処理するために使われる重要なキーワードです。

begin/rescueの仕組み

まず理解しておくべきことがあります。Rubyのプログラムは、実行中のさまざまなタイミングでエラーを発生させる可能性があります。

具体例:

  • 存在しないファイルを読み込もうとした場合
  • 数値をゼロで割ろうとした場合
  • 接続先のWebサーバーのSSL証明書が期限切れになっている場合

エラーが発生しても… Rubyはすぐにクラッシュするわけではありません!

エラーから回復するチャンスが与えられます。これを「例外処理」と呼びます。

Rubyには、コード内でエラーからの回復を実装するためのキーワードが用意されています。それが beginrescue です。

Rubyで例外を処理する基本形

では、例外はどのように処理すればよいのでしょうか?

答えは、例外を発生させる可能性のあるコードを begin / rescue ブロックで囲むことです。

仕組みは以下の通りです。

最初のセクション(begin)には、実行したいコード、つまり例外を発生させる可能性のあるコードを記述します。

例:

begin
  IO.sysopen('/dev/null')
rescue
  # ...
end

ここでは sysopen を使ってファイルを開こうとしています。ファイルを開けない場合は例外が発生します。

こここそが rescue キーワードの出番です!

rescue を使うことで、例外が発生したときに何をするかを指定できます。つまり、失敗時の挙動を自分でコントロールできるのです。

例:

begin
  IO.sysopen('/dev/null')
rescue
  puts "Can't open IO device."
end

実際の開発では、このようなエラーをログに記録したり、デフォルト値を返したりするのが一般的です。

ただし、絶対に避けるべきなのは「エラーの無視」です。

複数の例外をrescueする方法

rescue には省略可能な引数を渡せることを知っておきましょう。

この引数とは何か?それは、捕捉したい例外クラスです。

どの例外クラスを指定すべきかは、実行しているコードによって異なります。

IO の場合:

  • ファイルが見つからない場合は Errno::ENOENT
  • 権限エラーの場合は Errno::EACCES

さらに便利な点は?

同じ begin/rescue ブロック内で複数の例外を処理できます。

次のように書きます:

begin
  IO.sysopen('/dev/null')
rescue Errno::ENOENT
  puts "File not found."
rescue Errno::EACCES
  puts "Insufficient permissions, not allowed to open file."
end

複数の例外に対して同じ処理を行いたい場合は…

こう書くこともできます:

begin
  IO.sysopen('/dev/null')
rescue Errno::ENOENT, Errno::EACCES
  puts "There was an error opening the file."
end

メソッドやブロック内での例外処理

begin キーワードは必ずしも必要というわけではありません。省略できるケースもあります。

それはどこ? メソッドの中とブロックの中です。

メソッドの例:

def get_null_device
  IO.sysopen('/dev/null')
rescue Errno::ENOENT
  puts "Can't open IO device."
end

メソッド定義自体が begin の役割を果たすため、省略できます。

ブロックでも同様のことができます。

ブロックの例:

["a.txt", "b.txt", "c.txt"].map do |f|
  IO.sysopen(f)
rescue Errno::ENOENT
  puts "Can't open IO device: #{f}."
end

実は、begin を使わずに rescue を使う方法がもう1つあります。

インラインrescueの使い方と注意点

rescue はインライン(行内)で使うこともできます。まれなシナリオでは、この形式が役立つことがあります。

例:

["a.txt", "b.txt", "c.txt"].select { |f| File.open(f) rescue nil }.map(&:size)

これにより、存在するファイルだけを開いて、存在しないものは無視できます。結果として、存在するファイルのサイズだけを取得でき、例外も発生しません。

なぜこんな書き方をするのか?

コードを1行にまとめられるからです。それだけの理由です。

しかし、この形式の rescue には「隠れた危険」があります。例外クラスを指定しないため、StandardError を継承するすべての例外、つまりほとんどすべての例外を捕捉してしまうからです。

なぜこれが良くないのか?

広範囲の例外を捕捉するのではなく、特定の例外だけを処理するのがベストプラクティスだからです。そうすることで、エラーを見逃さずに済みます。

隠されたエラーは、あらゆる種類の奇妙な挙動やデバッグ困難な問題につながります。

まとめ

この記事では、Rubyにおけるエラーの基礎知識、基本的な例外処理、そして begin / rescue キーワードの使い方について学びました。

適切な例外処理を身につけて、堅牢で信頼性の高いRubyアプリケーションを開発しましょう。

  1. Rubyのmapメソッド完全ガイド!配列・ハッシュのデータ変換を実例で解説

    Rubyのmapメソッドは、配列(Array)・ハッシュ(Hash)・範囲(Range)といったコレクションに対して使用できる強力なメソッドです。 mapの主な用途は、データの変換です。 例えば、文字列の配列があった場合、すべての文字列を順番に処理して、各文字を大文字に変換することができます。 また、Userオブジェクトのリストがある場合も同様です。 それらを変換して、対応するメールアドレスや電話番号など、Userクラスに定義された任意の属性のリストを作成できます。 それでは、具体的な使い方を見ていきましょう! Ruby mapメソッドの基本構文 mapの構文は次のようになっています。 a

  2. RubyのStructとOpenStructの使い方を徹底解説!値オブジェクトを簡単に作る方法

    Rubyには、関連する属性をまとめて保持する「値オブジェクト」を手軽に作れるStructという組み込みクラスが用意されています。本記事では、Structの基本的な使い方から注意点、そしてOpenStructとの違いまで詳しく解説します。 そもそもStructとは何か? StructはRubyに組み込まれたクラスで、新しいクラスを動的に生成し、値オブジェクト(Value Object)を作成するために使われます。値オブジェクトとは、関連性のある複数の属性をひとまとめにして扱うためのオブジェクトです。 具体例を挙げてみましょう。 2つの座標(xとy)を持つPointというデータを表したい場合、この