Ruby の StandardError でどういう間違いをすると, どの例外が発生するのかのメモ
Ruby の例外クラス Exception
のサブクラス StandardError
で, どういう失敗をすると StandardError
のどのサブクラス (例外) が発生するのかのメモです.
Ruby のバージョンは 2.5.1
になります.
ArgumentError
メソッドを呼び出す際に, 間違った引数を渡すと発生します.
例 1) 間違った引数の数を渡した時:
'1'.to_i(1, 2) rescue $!
# => #<ArgumentError: wrong number of arguments (given 2, expected 0..1)>
例 2) 受け入れられない引数を渡した時:
'1'.to_i 1 rescue $! # => #<ArgumentError: invalid radix 1>
UncaughtThrowError
catch
と throw
で, throw
に catch
に存在しないタグを渡すと発生します:
catch(1) { throw 2 } rescue $! # => #<UncaughtThrowError: uncaught throw 2>
EncodingError
EncodingError
はエンコードエラーのベースクラスです.
例 1) 存在しないコードコンバータでエンコードしようとした時:
'hello'.encode 'CUSTOM_ENCODING' rescue $!
# => #<Encoding::ConverterNotFoundError: code converter not found (UTF-8 to CUSTOM_ENCODING)>
FiberError
Fiber.new
で作った Fiber を Fiber#resume
で再開した後に, もう一度 Fiber#resume
で再開しようとすると発生します:
fiber = Fiber.new {}
fiber.resume
fiber.resume rescue $! # => #<FiberError: dead fiber called>
IOError
IO 操作の失敗時に発生します.
例 1) 読み込み専用モードの File
オブジェクトに書き込みをしようとすると発生します:
File.open('example.txt') do |f|
f.write('Hello World') rescue $! # => #<IOError: not opened for writing>
end
例 2) IO#close
でストリームを閉じた後に, 読み込みをしようとすると発生します:
File.open('example.txt') do |f|
f.close
f.read rescue $! # => #<IOError: closed stream>
end
EOFError
ファイルの終わりに達してから, なんらかの IO 操作をすると発生します:
File.open('example.txt') do |f|
f.read
f.readline rescue $! # => #<EOFError: end of file reached>
end
IndexError
無効なインデックスで参照すると発生します:
[:a].fetch 1 rescue $!
# => #<IndexError: index 1 outside of array bounds: -1...1>
KeyError
指定されたキーが見つからないと発生します:
{a: :a}.fetch :b rescue $! # => #<KeyError: key not found: :b>
StopIteration
Enumerator#next
呼び出し時に次の要素がないと発生します:
enum = [:a].each
enum.next
enum.next rescue $! # => #<StopIteration: iteration reached an end>
LocalJumpError
要求通りに yield
できないと発生します:
def foo; yield end
foo rescue $! # => #<LocalJumpError: no block given (yield)>
def bar; proc { return } end
bar.call rescue $! # => #<LocalJumpError: unexpected return>
NameError
与えられた名前が無効だったり, 定義されていないと発生します:
foo rescue $!
# => #<NameError: undefined local variable or method `foo' for main:Object>
Symbol.const_set :a, :a rescue $! # => #<NameError: wrong constant name a>
Symbol::A rescue $! # => #<NameError: uninitialized constant Symbol::A>
NoMethodError
レシーバに定義されておらず, method_missing
でも処理されないメソッドを呼び出すと発生します:
'hello'.pascalcase rescue $!
# => #<NoMethodError: undefined method `pascalcase' for "hello":String>
RangeError
与えられた数が範囲外だと発生します:
[:a, :b].drop 1_000**10 rescue $!
# => #<RangeError: bignum too big to convert into `long'>
FloatDomainError
Float::INFINITY
や Float::NAN
といった特殊な値を, その値に対応していない Integer
や Rational
に変換しようとすると発生します:
Float::INFINITY.to_i rescue $! # => #<FloatDomainError: Infinity>
Float::INFINITY.to_r rescue $! # => #<FloatDomainError: Infinity>
Float::NAN.to_i rescue $! # => #<FloatDomainError: NaN>
Float::NAN.to_r rescue $! # => #<FloatDomainError: NaN>
RegexpError
Regexp.new
に無効な正規表現文字列を渡すと発生します:
Regexp.new '+' rescue $!
# => #<RegexpError: target of repeat operator is not specified: /+/>
Regexp.new '*' rescue $!
# => #<RegexpError: target of repeat operator is not specified: /*/>
Regexp.new '?' rescue $!
# => #<RegexpError: target of repeat operator is not specified: /?/>
Regexp.new '\1' rescue $!
# => #<RegexpError: invalid backref number/name: /\1/>
Regexp.new '\k<a>' rescue $!
# => #<RegexpError: undefined name <a> reference: /\k<a>/>
Regexp.new '\g<a>' rescue $!
# => #<RegexpError: undefined name <a> reference: /\g<a>/>
RuntimeError
一般的なエラーの例外クラスで Kernel#raise
を Exception
クラスを何も指定しないで呼び出すと発生します:
raise 'a generic error' rescue $! # => #<RuntimeError: a generic error>
FrozenError
フローズンオブジェクトを変更しようとした時に発生します:
[].freeze << :a rescue $! # => #<FrozenError: can't modify frozen Array>
{}.freeze.merge!({a: :a}) rescue $! # => #<FrozenError: can't modify frozen Hash>
SystemCallError
SystemCallError
は全てのローレベルなプラットフォーム依存のエラーのベースクラスです.
現在のプラットフォームで利用可能なエラーは SystemCallError
のサブクラスで, Errno
モジュールに定義されています.
Errno.constants
でその全てのエラーの定数リストを取得できます.
例 1) 存在しないファイルを開こうとした時:
File.open('example.txt') rescue $!
# => #<Errno::ENOENT: No such file or directory @ rb_sysopen - example.txt>
例 2) パーミッションが拒否された時:
File.open('example.txt', 'w') rescue $!
# => #<Errno::EACCES: Permission denied @ rb_sysopen - example.txt>
ThreadError
スレッドに対して無効な操作をすると発生します.
例 1) Thread.new
をブロック無しで呼び出した時:
Thread.new rescue $! # => #<ThreadError: must be called with a block>
TypeError
予期したものと違うタイプのオブジェクトに遭遇した時に発生します:
1 + '1' rescue $! # => #<TypeError: String can't be coerced into Integer>
'1' + 1 rescue $!
# => #<TypeError: no implicit conversion of Integer into String>
'Hello' + :World rescue $!
# => #<TypeError: no implicit conversion of Symbol into String>
[:a, :b].fetch '0' rescue $!
# => #<TypeError: no implicit conversion of String into Integer>
ZeroDivisionError
Integer
や Rational
を Integer
の 0
で割ろうとした時に発生します:
1 / 0 rescue $! # => #<ZeroDivisionError: divided by 0>
1/1r / 0 rescue $! # => #<ZeroDivisionError: divided by 0>
まとめ
Ruby の StandardError
の全てのサブクラスは rescue
でキャッチできるので, rescue
を statement modifier として使い, $!
で発生した例外を参照しています.
StandardError
はその名の通り, Ruby の標準的なエラーなので, よくお目にかかります.
自分でクラスを作ろうとする際, どんな例外クラスを発生させるべきか決める時に, StandardError
のサブクラスのそれぞれの例外はどんな時に発生するのかということをあらかじめ知っておくと参考になると思ったり, もしくは, 何かコードを書いて実行した時に発生した例外が具体的にどういう意味を表しているのかということをより理解することができるようになると思いこのようなメモを書きました.
Ruby の StandardError
とその親クラス Exception
に関するより詳しい情報は次の URL から参照できます:
https://ruby-doc.org/core-2.5.1/Exception.html
また Ruby の例外をどのように処理するかという情報は次の URL から参照できます:
https://ruby-doc.org/core-2.5.1/doc/syntax/exceptions_rdoc.html
関連記事
Ruby のメソッドチェインって便利で楽しい2018.05.04
Ruby の正規表現を備忘録としてまとめてみた2018.08.30
Ruby のグローバル変数をそれぞれ調べてみた2018.06.12
Git のコミット履歴を大胆に書き換えるなら git rebase -i がオススメ2018.08.23
Bundler をシングルファイル Ruby スクリプトで使う方法2018.04.23