CatalystのDispatcherでえらく感動したのでメモ。

Catalystでログ的なウィンドウを出力したい訳です。エラーであるとか処理が完了したとか。

sub moge : Local {
  my($self,$c) = @_;

  if ($some_condition) {
    $c->stash->{info} = 'Some error happen!';
    $c->stash->{template} = 'info.html';
    return
  }
}

みたいな感じだと思うんです。stashにrenderするべきtemplateと値を入れてreturn。
何個もこれをやりたいとなるとこれをMyApp.pmとかに書いたりするわけです。


たとえばこれをrender_infoって名前でメソッドにして、普通に$c->render_infoって呼ぶと戻ってくる訳です。当たり前ですが。

sub MyApp::render_info {
  shift()->detach('/_render_info', \@_);
}

sub MyApp::_render_info : Private {
  # メッセージを表示するルーチン
}

なんてやれば戻ってこないが実現するんですがメソッド二つはどうよ、ということになってうーんとなる訳です。
それでdetachの元があるCatalyst::Dispatcherを見てみたら

sub detach {
    my ( $self, $c, $command, @args ) = @_;
    $c->forward( $command, @args ) if $command;
    die $Catalyst::DETACH;
}

$Catalyst::DETACHってなんだよ、とおもって倣ってdie $Catalyst::DETACHしてみたらstack戻ってない!
値を見てみたら

our $DETACH    = "catalyst_detach\n";

ってあるので定数ですね。

結論:die $Catalyst::DETACHするとそこでDispatcher止まります。それより先に行かないし戻らないみたいです。
throw-catchってこういう風に使うんだ、と感動した。