« ユーザからアイディアを大っぴらに聞くなんてことはできない | メイン | CGI::Applicationでpost_dispatch »

HTML::Template::Plugin::Dotを使ってみた

HTML::TemplateにTTのようなdotでメソッドを呼び出す機能を持たせるHTML::Template::Plugin::Dotを使ってみた。0.06でloop内の動作もよくなってきた感じがするので試してみることにした。

UnixUserの伊藤直也さんの連載の「作って学ぶ、いまどきのWebサービス」を参考に、OpenSearchを利用したアプリケーションを作ってみることにする。
コマンドライン版をまず制作。

my $engine = WWW::OpenSearch->new($osxml);
my $feed = $engine->search($word);
my $tmpl=HTML::Template::Pluggable->new(
	scalarref=>?$template,
	die_on_bad_params=>0,
	loop_context_vars=>1,
	case_sensitive=>1
);
$tmpl->param('result',$feed);

テンプレートは、

<ul>
<!-- TMPL_LOOP NAME=result.items:item -->
<li><!-- TMPL_VAR NAME=item.title ESCAPE=HTML --></li>
<!-- /TMPL_LOOP -->
</ul>

こんな感じ。case_sensitiveをOnにしておくのが吉です。大文字小文字が混じったメッソドを呼び出すには必要です。
ただしこのサンプル。HTML::Templateにpatchを当てないとうまく動かない。LOOPは動くけど中身が入らない。これはHTML::Templateがsubクラスを作りにくい構造になっているためです。しかし、本当にpatchを当てるのは少々面倒なので、HTML::Templateの_parseメソッド650行をコピペして、Perlスクリプト中に埋め込みます。んで上述のpatchを参考に

         = HTML::Template->_new_from_loop(

のあたりを書き換えます。下のようになります。

sub HTML::Template::_parse{
  my $self = shift;
  my $options = $self->{options};
〜〜中略〜〜
	# does _parse() - sub-templates get their parse_stack and
	# param_map fed to them already filled in.
	my $pkg = ref $self; 
	$loop->[HTML::Template::LOOP::TEMPLATE_HASH]{$starts_at}             
           = $pkg->_new_from_loop(
					   parse_stack => $parse_stack,
〜〜中略〜〜
# get rid of filters - they cause runtime errors if Storable tries
  # to store them.  This can happen under global_vars.
  delete $options->{filter};
}

これで動かすことができました。スクリプトはこちらに置きました。

次に、Web版。前述のUnixUserの記事と同じようにCGI::Applicationを使ってみました。。HTML::Template::Plugin::Dotを利用するためのCGI::ApplicationのプラグインCGI::Application::Plugin::HTPluginDotを書いて、HTML::Template::_parseはその中に埋め込んだ。

デモはこちら。

ページがそんなにないのでdispatchを利用しなかったのと、ページ移動のFOREACH部分は実装していません。この部分は別方法を考えるしかないなぁ。
ソースはこちら

ちょっと使えそうな気がした。