第7回Gotanda.rb
もう何回目か数えるのもめんどくさくなってきましたが、今日もひたすら前回の続きをしてました。
Rackの上で書いていると、
def action return not_found if cond1 return not_found if cond2 return not_found if cond3 [ 200, { 'Content-Type' => 'text/plain' }, 'Found' ] end def not_found [404, { 'Content-Type' => 'text/plain' }, 'Not Found' ] end
みたいなコードを書きたくなるときがありますが、not_foundメソッドを呼ぶときは必ずreturnを呼ばないとそこで処理が終らずに下の処理が実行されてしまいます。
ここまではまぁ当たり前の話なのですが、cond1, cond2, cond3までチェックするという部分が複数のアクションで共通だったりするとメソッドにくくりたくなります。
def check return not_found if cond1 return not_found if cond2 return not_found if cond3 end def action1 check [ 200, {'Content-Type' => 'text/plain' }, 'Found' ] end def action2 check return not_found if cond4 [ 200, {'Content-Type' => 'text/plain' }, 'Found' ] end
こういうふうにしたときに、not_foundは大域脱出できるようなメソッドとして作ってないと、action1では200が結果として返ってしまいます。
ということでこんなふうにしてみました。
class ActionError < Exception; end class NotFound < ActionError; end def action check [ 200, {'Content-Type' => 'text/plain' }, 'Found' ] rescue ActionError => e e.message end def not_found! raise NotFound, [ 404, { 'Content-Type' => 'text/plain' }, 'Not Found' ] end
例外オブジェクトは文字列を渡すことになっているのですが、いちおうそれ以外も渡せるのを利用してます。
前似たようなことをやろうとしたときに、例外だと何かに引っかかってcatch..throw方式を試していた記憶があるんですが、ちょっと思い出せないのと、throwはSymbolで投げるので、内部的に使ってるライブラリとかとsymbolが万が一被るとやっかいなことになりそうなので、例外方式がよいのかなといった感じです。
not_found!とメソッド名をふつうのメソッドのフローとは違うとわかるようにしています。(キモいと言われそうですが、本当はNotFoundにしようかと思っていたのですが、NotFoundだけだと定数と解釈されてしまうのでNotFound()とカッコをつけないといけなくて、目立つのでそれでもいいかなと思ったのですが慣習に従ってみた次第です)