新しいblogに移行しました

新ブログ "All Yout Bugs Are Belong To Ass" に移行しました!

2011-03-03

[Perl]Router::Simple::Attributeというものをつくったものの、筋が悪い物だった

最近、そろそろ自前のWAFが欲しいと思い始めているのですが、いかんせん設計がまとめきれていないので、作っては棄てを繰り返しています。
そんな中、Router::Simpleを弄っていて、「毎度newするの面倒だなあ。connectって毎度書くのも億劫だしぃ。。。」とか思っちゃって、じゃあAttributeにパス書けるようにしたらどうだろうということで、Router::Simple::Attributeなるものをつくってみました。

使い方

use MyApp;
  use Router::Simple::Attribute;
  
  sub root : Path(/) {
      return 'root';
  }
  
  sub home : Path(/home/:myname) {
      return 'ok, '. shift->{ myname }. '!';
  }
  
  router->do( '/' );              # >>> 'root'
  router->do( '/home/ytnobody' ); # >>> 'ok, ytnobody!'

podをコピってきただけなんですけど、とりあえず簡単に説明。

Pathアトリビュートのついたサブルーチンを作ると、Router::Simple->connect相当のことをやってくれます。アトリビュートオプションには、Router::Simple流のパス文字列を渡してやるといいです。

それから、router()という関数が使えるようになります。こいつはRouter::Simpleのインスタンスを返しますが、これにはdoというメソッドが追加されています。

doメソッドは、Router::Simple::match()の返り値(=HashRef)の要素{code}をコードリファレンスとして実行するものです。
素のRouter::Simpleの場合、
$router->connect( '/path/:user', { code => sub { ... } } )

...

if ( my $p = $router->match( $env ) ) {
    $p->{code}->( ... );
}
else {
    ...
}
こんなふうに { code => sub { ... } } のところとか if文のくだりが若干冗長に感じますが、R::S::Attributeなら、
sub user :Path(/path/:user) { ... }

...

return router->do( $env ) || [ 404, [], ['not-found'] ];
みたいな書き方が可能です。

但し書き

当然ですが、Router::Simpleに処理を追加しているモジュールなので、Router::Simpleより遅いです。
あと、例によってテストが少なく、自分でもまだ実戦投入できていないものなので、信頼性については「?」という具合です。とはいえ、R::S::Attribute自体のコード量は非常に少なく、Router::Simpleが安定しているので、何か問題があったとしても、トレースはしやすいとおもいます。

2011-3-4 追記
どうやら、Plack::Sandbox::*とAttribute::Handlersの相性が悪いらしく、plackupからうまく利用できませんでした。
この辺を調査した時の記録は、こちらの記事に書きました。
一つ言えるのは、Attribute::Handlers や Perl5のアトリビュートを使うのは筋がよろしくないということです。

0 件のコメント: