Template Toolkitでvirtual methodを追加したいと思ったんですが、ドキュメントを読んでもどうも簡単なやり方が見付からない。仕方がないので最初に下記のようにやりました。
$Template::Stash::LIST_OPS->{ foo } = \&foo;
こうしなけりゃならないのかな?他になにか方法あるのでしょうか…。
追記:はてブでハテナオヤさんが質問してましたが、このエントリで伝えたいことは、vmethodを追加する方法としては、上記の方法やdefine_methodを使うのが正当な方法なのかどうかということと、他の人はどう追加しているのかなという部分になります。
下記のようにインスタンス生成時に追加とかできればいいのに…。
Template->new(STASH => {
LIST_OPS => {
foo => \&foo
}
);
と思ったら、Template::Stash::define_vmethodという関数がありました(podに書いてない?)。これをTemplate::Context::define_vmethod経由で呼ぶことができるようです。例えばスカラの値に対して1文字ずつスペースを空けるvirtual method(仮にadd_spaceとする)を定義したかったら、テンプレート(vmethod_test.tt)を
[% str.add_space %]
としておいて、
my $tt = Template->new();
my $vars = { str => 'chowww,omawww' };
$tt->context->define_vmethod('scalar', 'add_space', sub { join(' ', split('', $_[0])) });
$tt->process('vmethod_test.tt', $vars);
という感じにdefine_vmethodを使ってdefine_vmethod('virtual methodの種類', '名前', このvmethodのコードリファレンス)と定義してやればよい。出力結果は、
c h o w w w , o m a w w w
となります。ちなみにvirtual methodの種類は「scalar」と「item」がSCALARとして、「hash」がHASHとして、「list」と「array」がARRAYとして定義するために用意されているようです。と、ここまで書いたのですがdefine_methodはpodに書いてないから使うべきじゃないのかな…いやでも先頭に「_」は付いてないしプライベートメソッド的でもないんじゃないの?…とかちょと悶々としてみた。。。どうなんだろ?
Sledgeでこれを使いたいなぁと思ったんですが、Sledge::Template::TT::outputまではTTのオブジェクトは作らない仕様となっているため、やるとしたらこれをオーバーライドしたクラスを作るか、一番最初に挙げた例($Template::Stash::LIST_OPS->{ foo }にコードリファレンスを代入)を使う必要があります。