こんにちは、河野です。
chatty_error というgemを作ってみました。
chatty_error
独自の例外クラスのエラーメッセージを、ロケールファイルから設定できるようになるライブラリです。
エラークラスをインスタンス化する時、エラーメッセージを設定するのが面倒だ!という問題を解決します。
chattyという単語に、
chatty: 【形】話し好きな、〔文章や話し方が〕くだけた
という意味があるようなので、chatty_errorと名付けました。
作った背景
ある案件で、独自の例外クラスを作ったのですが、例外をraise するときに以下のようにしていました。
| 1 2 | # とんでもないことが起きた raise MyError.new(I18n.t('my_error.tondemonai_kotoga_okita')) | 
他のところでは、違うメッセージを
| 1 2 | # 不正なアクセスかもしれない raise MyError.new(I18n.t('my_error.huseina_akusesu_kamo_sirenai')) | 
また別のところでは、
| 1 2 | # 処理の手順がおかしい raise MyError.new(I18n.t('my_error.tezyunga_okasii')) | 
という感じで、同じエラーでもメッセージを変えることがありました。
理想を言えば細かく例外クラスを作った方が良さそうなのですが、とりあえずこんな感じで対応していたのです。
で、色んなところで、MyErrorをraiseする度に、I18nを呼び出さないといけません。
これは何かモヤモヤする~ということで、chatty_error の登場です。
使い方
Gemのインストール
まずはgemを使えるようにします。bundlerの場合です。
| 1 2 | # Gemfile gem 'chatty_error' | 
bundleを実行します。
| 1 | $ bundle | 
これで、ChattyErrorというモジュールが使用できるようになります。
原因を設定
さて、chatty_error では原因に対してメッセージを設定するという方針を採っています。なので、独自の例外クラスでは原因を設定する必要があります。caused_by を使用します。
MyErrorの例だと、以下のようになります。
| 1 2 3 4 5 6 | # my_error.rb class MyError < StandardError   include ChattyError   caused_by :terrible_thing_happend, :unauthorized_access, :wrong_procedure end | 
「とんでもないことが起きた」「不正なアクセス」「間違った手順」という例外が起きる原因を定義しています。
メッセージを設定
次に、原因に対応するエラーメッセージを設定します。
| 1 2 3 4 5 6 7 | # ja.yml ja:   chatty_errors:     my_error:       terrible_thing_happend: "とんでもないことが起きた!!!"       unauthorized_access: "不正なアクセスだ!!!"       wrong_procedure: "順番間違ってる" | 
例外の呼び出し方
raiseの時には、
| 1 2 3 | raise MyError.terrible_thing_happend raise MyError.unauthorized_access raise MyError.wrong_procedure | 
という感じで、簡単に呼び出せます。
MyErrorのインスタンス化とともに、エラーメッセージも設定されます。ついでに、cause に原因に相当するシンボルが設定されます。
| 1 2 3 | error = MyError.unauthorized_access error.message # => 不正なアクセスだ!!! error.cause   # => :unauthorized_access | 
ロケールファイルの書き方
ロケールファイルに設定するキーは、「chatty_errors.クラス階層.原因」になります。
仮に以下のような定義になっていたら、
| 1 2 3 4 5 6 7 8 9 10 11 12 | # deep.rb module A   module B     module C       class Deep < StandardError         include ChattyError         caused_by :deeper       end     end   end end | 
ロケールファイルは
| 1 2 3 4 5 6 7 8 | # ja.yml ja:   chatty_errors:     a:       b:         c:           deep:             deeper: "階層深い…" | 
となります。
デフォルト設定
ロケールファイル上のデフォルトスコープと、キーが一致しなかった場合のデフォルトメッセージを設定することができます。
| 1 2 3 4 5 6 7 8 9 10 11 | # my_error.rb class MyError < StandardError   include ChattyError   configure do |c|     c.default_scope = 'techscore'     c.default_message = 'エラーだよ'   end   caused_by :terrible_thing_happend, :unauthorized_access, :wrong_procedure end | 
デフォルトスコープを変更しているので、ロケールファイルは以下のようになります。
| 1 2 3 4 5 6 7 | # ja.yml ja:   techscore:     my_error:       terrible_thing_happend: "とんでもないことが起きた!!!"       unauthorized_access: "不正なアクセスだ!!!"       wrong_procedure: "順番間違ってる" | 
エラーメッセージの決定
エラーメッセージの決定は以下優先順位になります。
1. デフォルトスコープ、クラス階層、メソッド名から決定されるキーと対応するロケールファイル上のメッセージ
2. 'デフォルトスコープ.default_message' というキーと対応するロケールファイル上のメッセージ
3. configureで設定した、default_message に設定されているメッセージ
ちょっとした活用例
Railsの場合ですが、ApplicationControllerの中で rescue_fromを使用しています。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class ApplicationController < ActionController::Base   rescue_from MyError, :with => :my_error_handle   def my_error_handle(exception)     case exception.cause     when :unauthorized_access       logger.warn([exception.message].join("\n"))     else       logger.error([exception.message].join("\n"))     end     render 'errors/500', :status => '500 Internal Server Error', :layout => 'errors/application'   end end | 
MyErrorのcauseによって、ログレベルを変えるという処理です。他にも色々と使いどころはあると思います。
リンク
以上です。

 
						