Tatsumaki ライクな micro WAF "Lanky" を作ってみた
Twiggy を使う場合は Tatsumaki があって簡単に書けるけれども Starman / Starlet 使うときにも似たようにかけたらいいなぁ、ということで似たように書けるものを作ってみました。
モデルは実装してないので(どの ORM を使うかは TIMTOWTDI でどれ採用すべきか迷ったので)正確には WAF ではないと思うのだけれど、とりあえず Tatsumaki と似たことはできるようにしたつもりです。なにか意見いただけると嬉しいです
https://github.com/punytan/Lanky
Tatsumaki のように全部ひとつのファイルに突っ込むことも出来るし、別々のファイルに分割して書けるようにもしてあります。
t/02_app をみてもらえるとすぐわかると思うんですが、下記のように書けるようになっております。
ひとつのファイルで書く場合
errordoc, htdocs, template ディレクトリを準備して、
$ tree . |-- errordoc | `-- 404 |-- htdocs | |-- favicon.ico | |-- foo.htlm | `-- static | `-- index.html |-- template | `-- foo.xt `-- united.t
united.t
こんな風に書いたり、
use strict; package RootHandler; use parent 'Lanky::Handler'; use Data::Dumper; sub get { my ($self) = @_; my $body = $self->render('foo.xt', {foo => 'testing'}); my $res = $self->request->new_response(200); $res->content_type('text/html'); $res->body($body); $res->finalize; } 1; package LoginHandler; use parent 'Lanky::Handler'; use Data::Dumper; sub get { my ($self) = @_; my $body = $self->render('foo.xt', {foo => 'testing'}); my $res = $self->request->new_response(200); $res->content_type('text/html'); $res->body($body); $res->finalize; } 1; package main; use Test::More; use Plack::Test; use HTTP::Request::Common; use File::Spec; use File::Basename; use Lanky; use Plack::Builder; my $basedir = File::Basename::dirname(__FILE__); my $lanky = Lanky->new( application => [ '/' => 'RootHandler', '/login' => 'LoginHandler', ], template => [ path => ["$basedir/template"], cache => 1, cache_dir => File::Spec->tmpdir, ], errordoc_path => "$basedir/errordoc", render_encoding => 'utf8', ); my $app = builder { enable "Plack::Middleware::Static", path => sub { s{^/(?:(favicon\.ico)|static/)}{$1||''}e }, root => "$basedir/htdocs/"; $lanky->to_app; }; test_psgi $app, sub { my $cb = shift; my $res = $cb->(GET "/"); is $res->content, "testingいろはにほへと\n"; $res = $cb->(GET "/login"); is $res->content, "testingいろはにほへと\n"; $res = $cb->(GET "/xxx"); is $res->content, "みつからないよ!\n"; is $res->code, 404; }; done_testing;
別々のファイルに書く場合
lib ディレクトリを作って @INC に ./lib を突っ込んで、
$ tree . |-- errordoc | `-- 404 |-- htdocs | |-- favicon.ico | |-- foo.htlm | `-- static | `-- index.html |-- lib | `-- MyApp | `-- C | |-- Login.pm | `-- Root.pm |-- template | `-- foo.xt `-- divided.t
divided.t
こんな風に書いて、 MyApp::C::Root で上と同じように use parent 'Lanky::Handler'; してやれば、 $self から諸々呼べるようになっています
use strict; use Test::More; use Plack::Test; use HTTP::Request::Common; use File::Spec; use File::Basename; use lib File::Basename::dirname(__FILE__) . "/lib"; use Lanky; use Plack::Builder; my $basedir = File::Basename::dirname(__FILE__); my $lanky = Lanky->new( application => [ '/' => 'MyApp::C::Root', '/login' => 'MyApp::C::Login', ], template => [ path => ["$basedir/template"], cache => 1, cache_dir => File::Spec->tmpdir, ], errordoc_path => "$basedir/errordoc", render_encoding => 'utf8', ); my $app = builder { enable "Plack::Middleware::Static", path => sub { s{^/(?:(favicon\.ico)|static/)}{$1||''}e }, root => "$basedir/htdocs/"; $lanky->to_app; }; test_psgi $app, sub { my $cb = shift; my $res = $cb->(GET "/"); is $res->content, "testingいろはにほへと\n"; $res = $cb->(GET "/login"); is $res->content, "testingいろはにほへと\n"; $res = $cb->(GET "/xxx"); is $res->content, "みつからないよ!\n"; is $res->code, 404; }; done_testing;