ziguzagu.org

Catalyst::Helper::View::TTSite と TT の AutoWrapper

Catalyst::Helper::View::TTSite を使ってみたら、雛形のテンプレートで TT の WRAPPER がみたことがない使われ方をしていたので、調べてみたら TT の Automatic Wrapper という仕組みだった、という話。

今までの自分の TT の使い方。

普段自分が Web アプリなんかで TT を使う時の使い方は、header.tt と footer.tt とか作って、tt_process で指定するテンプレがそいつらを含めてるという、↓のような感じ。

header.tt。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>[% title %]</title>
</head>
<body>

footer.tt。

<div id="footer">&copy; 2006 ziguzagu</div>
</body>
</html>

で、コントローラーで指定するテンプレ、index.tt とかをこう。

[% INCLUDE header.tt title="タイトル" %]

<p>なかみ</p>

[% INSERT footer.tt %]

これはこれで、header.tt / footer.tt の再利用が出来るのはいい。ただ、

  • 各テンプレート内でHTMLの開始タグと終了タグの対応がとれてない
  • ベースになるテンプレート全部で同じ INCLUDE や PROCESS / INSERT を書く必要がある

とかいったあたりがあんまり美しくないなぁ、とは思ってたり。でもそこで思考停止…。

そこで、AutoWrapper。

TT のインスタンスを作るときに、PRE_PROCESS や POST_PROCESS オプションにテンプレートを指定するのと同じ形で、WRAPPER オプションに一番外側になるテンプレートを指定すると、tt_process で生成される出力が、WRAPPER で指定したテンプレの content になる、というのが TTSite の雛形をみて知った。

たとえば、

wrapper.pl

#!/usr/bin/perl
use strict;
use warnings;
use Template;

my $tt = Template->new({
    WRAPPER => 'wrapper.tt',
});
$tt->process('content.tt');

というのを作って、wrapper.tt には HTML の全体像を記述。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>[% template.title %]</title>
</head>
<body>
[% content %]
</body>
<div class="footer">&copy; 2006 ziguzagu</div>
</html>

content.tt には、[% content %] に入れたい部分を記述。

[% META title = 'Wrapper Test' %]
<p>Hello Wrapper!!</p>

で、実行した結果は、こうなる。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Wrapper Test</title>
</head>
<body>

<p>Hello Wrapper!!</p>

</body>
<div class="footer">&copy; 2006 ziguzagu</div>
</html>

META が実はいい感じ(METAもほとんど使ったこと無かった…)。

WRAPPER を入れ子にしてみる。

WRAPPER は複数テンプレートを入れ子にも出来る。

wrapper.tt をこんな風に。

<!-- BEGIN auto wrapper -->
[% content WRAPPER html.tt + inner.tt %]
<!-- END auto wrapper -->

親テンプレの html.tt。

<!-- BEGIN html.tt -->
<title>
[% template.title %]
</title>

<content>
[% content -%]
</content>
<!-- END html.tt -->

これの content に、次に指定した inner.tt が入る。

inner.tt。

<!-- BEGIN inner.tt -->
[% content %]
<!-- END inner.tt -->

inner.tt の content には、tt_process で指定した content.tt が入ってくる。 で、結果はこうなる。

<!-- BEGIN auto wrapper -->
<!-- BEGIN html.tt -->
<title>
Wrapper Test
</title>

<content>
<!-- BEGIN inner.tt -->

<p>Hello Wrapper!!</p>

<!-- END inner.tt -->
</content>
<!-- END html.tt -->

<!-- END auto wrapper -->

content をどんどん入れ子に。いいね。

ということは

個別のページ専用の分岐とかを META とかの指定でうまい具合にやれば、無駄な毎回同じテンプレ INCLUDE とかなくなるような気がする。。。

ちなみに、↓の本の Chapter.2 に、『Using an Automatic Wrapper Template』という項がしっかりあって、ちゃんと解説されているという事実。ttree 使ったサンプルとかも。TTSite 使うまでは目もくれなかった。。。

Perl Template Toolkit: Scalable Templating for the Web