Ruby例外記述ルールメモ
参考 Effective Ruby 項目22あたり
- 例外クラスは StandardError を継承したクラスから派生させる
class MokoAppError < StandardError; end
class Temp1Error < MokoAppError; end
class Temp2Error < MokoAppError; end
class Temp3Error < MokoAppError; end
- パターン1
- raise 例外クラス名, メッセージ
- rescue は出来る限り絞って指定する
begin
raise Temp1Error, 'aaaaaaa'
rescue Temp1Error => e
# ログを出力させるのか
p e.class, e.message, e.backtrace
# リトライするのか
# retry
# 諦めて更に例外をraiseし、上のスタックに後の処理を任せるのか
# raise # (superみたいに、現在の例外をそのままraiseしてくれる)
# raise OtherError
end
- パターン2
- raise 例外オブジェクト
- 例外オブジェクト生成時に動的にメッセージを変えられる
- 使う場面があるのか疑問
class Temp2Error < MokoAppError
def initialize(msg)
super("This is #{msg}")
end
end
begin
raise Temp2Error.new('message1')
rescue Temp2Error => e
p e.class, e.message, e.backtrace
end
- パターン3
- raise 例外オブジェクト, メッセージ
- 例外オブジェクト生成時に動的に生成したメッセージが上書きされる
- (逆に言うと、上書きすることができる)
- 使う場面があるのか疑問
class Temp3Error < MokoAppError
def initialize(msg)
super("This is #{msg}")
end
end
begin
raise Temp3Error.new('message1'), 'message2'
rescue Temp3Error => e
p e.class, e.message, e.backtrace
end
- 無条件のretryはするな
- リトライ回数を制限し
- 次回までのsleepは指数的に増やせ
- ログにも出してやれ
retries = 0
begin
raise
rescue StandardError
raise if retries >= 3
retries += 1
p "aaaa #{retries}"
sleep(2 ** retries)
retry
end
- ensure節の中では絶対にreturn, next, bread, 外部へのthrowするな
- 全てのエラーを無視するようになる
- ensureで制御フローは操作するな。そうせねばならないなら、それはお前の頭か仕様に問題がある
- ensureにはリソース開放的な処理のみを書け
- RuboCop先生が注意してくれるのでまぁいいかなと思う
begin
aaaaa
ensure
return nil
end
- raise-rescue は制御フローの為に使ってもよいが、分かり易くできるのであれば catch-throw の使用も考える
- 忌避すべき存在じゃないよ
- 安全なgotoだよ
moko =
catch(:homo) do
(3..10).each do |a|
(1..7).each do |b|
throw(:homo, [a, b]) if a == b
end
end
end
p moko