DATAトークンと継承
yusukebe氏のListPod::App::Lite::Viewを見ていて良さげだったので真似してみた。
1. Baseとなるクラスを用意しておいて、こいつをuseする
package CMS::Lite::View::Base; use strict; use warnings; use utf8; use Text::MicroTemplate qw(build_mt); sub import { my $pkg = shift; my $caller = caller; { no strict 'refs'; *{"$caller\::pkg"} = sub { $caller }; my @functions = qw/new edit_args template render/; for my $func (@functions) { *{"$caller\::$func"} = \&$func; } } } sub new { bless { __CACHE => undef }, $_[0] } sub edit_args { my $self = shift; my $args = @_ == 1 ? shift : {@_}; } # I want to override this sub template { my $DATA_TOKEN = $_[0]->pkg . "::DATA"; $_[0]->{__CACHE} = do { local $/; <$DATA_TOKEN>; } unless $_[0]->{__CACHE}; } sub render { my $self = shift; my $args = $self->edit_args(@_); build_mt( $self->template )->($args)->as_string; } 1;
2. 上記をuseしたクラスは次のように書ける
package CMS::Lite::View::Head; use strict; use warnings; use utf8; use CMS::Lite::View::Base; 1; __DATA__ ? my $args = shift; <head> <meta http-equiv="content-type" content="text/html; charset=utf8" /> <title><?= $args->{title} ?> | <?= $args->{site_name} ?></title> <meta name="keywords" content="<?= join ', ', @{ $args->{keywords} } ?>" /> <meta name="description" content="<?= $args->{description} ?>" /> <meta name="author" content="<?= $args->{author} ?>" /> <meta name="copyright" content="<?= $args->{copyright} ?>" /> <meta name="robots" content="<?= $args->{robots} ?>" /> <link rel="stylesheet" type="text/css" media="screen" href="<?= $args->{css_file} ?>"/> </head>
3. 次のように実行する
#!/usr/bin/perl use strict; use warnings; use Test::More; use Test::Differences; use CMS::Lite::View::Head; subtest 'basic test' => sub { my $head = CMS::Lite::View::Head->new; isa_ok $head, 'CMS::Lite::View::Head'; my %args = ( title => 'title', site_name => 'site_name', keywords => [qw/some keywords here/], description => 'site description', author => 'okamura', copyright => 'Copyright (C) site name', robots => 'all', css_file => '../common/css/import.css', ); $head->render(%args); # 一回読んどく eq_or_diff $head->render(%args), <<"_EOF_"; <head> <meta http-equiv="content-type" content="text/html; charset=utf8" /> <title>title | site_name</title> <meta name="keywords" content="some, keywords, here" /> <meta name="description" content="site description" /> <meta name="author" content="okamura" /> <meta name="copyright" content="Copyright (C) site name" /> <meta name="robots" content="all" /> <link rel="stylesheet" type="text/css" media="screen" href="../common/css/import.css"/> </head> _EOF_ done_testing; }; done_testing;
困った事
本当はuse baseしたいのですが、このように書くと意図した結果になりません。
sub template { $_[0]->{__CACHE} = do { local $/; <__PACKAGE__::DATA>; } unless $_[0]->{__CACHE}; }
とか
sub template { $_[0]->{__CACHE} = do { local $/; <$_[0]::DATA>; } unless $_[0]->{__CACHE}; }
1つ目は
2つ目は
で、結局use baseあきらめてimport書いて回避したんですが、この理由だけでこう書くのはやだなー。
あと__PACKAGE__に文字列を連結するときどうやるんだっけな。
もう右眼が眼精疲労で苦しいので明日誰かに聞こう…
参考
import周りの処理: http://github.com/nekokak/p5-dbix-skinny/blob/master/lib/DBIx/Skinny.pm
Text::MicroTemplate周り: http://github.com/yusukebe/ListPod-App-Lite/blob/master/lib/ListPod/App/Lite/View.pm
__PACKAGE__ : http://d.hatena.ne.jp/walf443/20100330