テンプレートツールキットマニュアル

職場でTTを使っていた時に少しずつ訳したものです。途中よく分からない所もあって、かなり適当。自動翻訳よりはマシかも、という程度です。
追記・修正歓迎。質問不可。→ しろいわ(public@hakoniwa.net)

オリジナルマニュアル
http://www.template-toolkit.org/docs/plain/Manual/Directives.html
CPAN
http://search.cpan.org/~abw/Template-Toolkit-2.14/

概要

このセクションでは、Template Toolkit全ディレクティブのリファレンスを、使用例と共に提供します。

解説

テンプレート変数へのアクセス

GET

GETは対象の変数の値を表示します。

[% GET foo %]

GETを付けず、変数名だけでも表示可能です。

[% foo %]

変数はドット「.」で区切られた要素をいくつでも持つことができます。
また、それぞれの要素には、引数をカッコ「()」内に指定することが可能です。

[% foo %]
[% bar.baz %]
[% biz.baz(10) %]
...etc...

論理演算子(and,or,not,?:)、数学演算子(+,-,*,/,%,mod,div)を用いた式を使うことができます。

[% template.title or default.title %]
[% score * 100 %]
[% order.nitems ? checkout(order.total) : 'no items' %](式?真:偽)

「div」演算子は除算の整数部分を返します。
「%」と「mod」は除算の余りを返します。
Version1との互換性を持たせるため、「mod」は「%」のエイリアスとして提供されています。

[% 15 / 6 %]  # 2.5
[% 15 div 6 %] # 2
[% 15 mod 6 %] # 3

CALL

CALLはGETに変数の値を評価しますが、結果を表示しません。
CALLは変数をサブルーチンやメソッドに渡す場合など、値を表示する必要が無い場合に有用です。

[% CALL dbi.disconnect %]
[% CALL inc_page_counter(page_count) %]

SET

SETは変数に値を代入したり、新たに一時的な変数を作成したりします。

[% SET title = 'Hello World' %]

SETも省略可能です。[% title = 'Hello World' %]

変数には他の変数、数値、定型文字列('文字列')、文字列("文字列")を格納することができます。
下記のどの場合にも、変数は、内容が評価された後の結果を参照しています。
文中の変数には頭に$を付け、必要があれば、範囲を明確にするために中カッコ{}で変数名をくくります。

[% foo = 'Foo' %] # 定型値 'Foo'
[% bar = foo %] # 変数fooの値
[% cost = '$100' %] # 定型値'$100'
[% item = "$bar: ${cost}.00" %] # 値 "Foo: $100.00"

一つのディレクティブ内で複数タイプの変数に値を割り振ってもかまいません。
その場合、変数は記述した順に評価されます。
以下のように記述できます。

[% foo = 'Foo'
bar = foo
cost = '$100'
item = "$bar: ${cost}.00"
%]

単一タイプの記述も各行にGETを割り振ったように記述できます。

[% ten = 10
twenty = 20
thirty = twenty + ten
forty = 2 * twenty
fifty = 100 div 2
six = twenty mod 7
%]

文字列は'_'でつなげることができます。
Perl5においては'.'が文字列の結合に使用されていましたが、Perl6では、(テンプレートキットのように)'.'がメソッドの 呼び出しに使われ、'_'が文字列の結合に使われるでしょう。
この演算子は、半角スペースで囲む必要があります。

[% copyright = '(C) Copyright' _ year _ ' ' _ author %]

もちろんダブルクォーテーションで文字列をくくることで同様の効果を得ることができます。

[% copyright = "(C) Copyright $year $author" %]

DEFAULT

SETと似ていますが、DEFAULTは(Perlで言えば)現在明らかでない変数・trueでない変数に値を設定するのみです。

[% DEFAULT
name = 'John Doe'
id = 'jdoe'
%]

DEFAULTはとりわけ、共通のテンプレート構成要素において、
デザイン・文言等のデフォルト値を異なった未定義変数に渡すことを保証するので役立ちます。

[% DEFAULT
title = 'Hello World'
bgcol = '#ffffff'
%]
<html>
<head>
<title>[% title %]</title>
</head>
<body bgcolor="[% bgcol %]">

他のテンプレートファイル・ブロックの処理

INSERT

INSERTは外部ファイルのコンテンツを現在の位置へ挿入します。

[% INSERT myfile %]

パースや処理が一切行われないファイルが作成されます。コンテンツ(場合によっては埋め込まれたあらゆるテンプレート命令含む)はそのまま挿入されます。

ファイル名はINCLUDE_PATHディレクトリに関連し表記されます。
ABSOLUTE、RELATIVEオプションをそれぞれ設定すれば、恐らく絶対パス('/'で始まるもの)や相対パス('.'で始まるもの)のファイル名も使用できるでしょう。
これらのオプションはデフォルトでは無効となっています。

  my $template = Template->new({
    INCLUDE_PATH => '/here:/there',
  });
  $template->process('myfile');
 

'myfile':

[% INSERT foo %] # /here/foo を見ると /there/foo が参照されます
[% INSERT /etc/passwd %] # ファイルエラー: ABSOLUTE が設定されていません
[% INSERT ../secret %] # ファイルエラー: RELATIVE が設定されていません

便宜上、ファイル名が英数字・アンダーバー・ドット・スラッシュのみで構成されている限り、
「'」でくくる必要はありません。
上記以外の文字が含まれる場合には、くくる必要があります。

[% INSERT misc/legalese.txt %]
[% INSERT 'dos98/Program Files/stupid' %]

ファイル名を明示するために変数を評価する場合、その変数に$を付記するか、ダブルクォーテーションを用いた文字列の書き換えをする必要があります。

[% language = 'en'
legalese = 'misc/legalese.txt'
%]
[% INSERT $legalese %] # 'misc/legalese.txt'
[% INSERT "$language/$legalese" %] # 'en/misc/legalese.txt'

区切り文字のように「+」を使用することで、複数のファイルを表記できます。
全てのファイル名は全てクォーテーションでくくられるか、全くくくらない必要があります。
変数はダブルクォーテション内に表記します。

[% INSERT legalese.txt + warning.txt %]
[% INSERT "$legalese" + warning.txt %] # くくりが必要

INCLUDE

INCLUDEは他のテンプレートファイルやブロックの出力結果を処理・挿入するために使われます。

[% INCLUDE header %]

もし同じファイル内または現在読み込まれたテンプレート(親テンプレート)内で、表記した名前のブロックが定義されていた場合、それは同じ名前のファイルよりも優先的に使われます。

[% INCLUDE table %] # 下で定義されているブロックを使用
[% BLOCK table %]
<table>
...
</table>
[% END %]

もし、ブロック定義が見つからない場合は、テンプレート名はINCLUDE_PATHのディレクトリにあるファイルか、ABSOLUTE/RELATIVEオプションが付いていれば絶対/相対パスにあるファイルを対象とします。

INCLUDEは、先述のINSERTにより、ファイル名を自動で引用します。
INCLUDE文に、変数にテンプレートの名前を含んでいる時は、$を付記するかダブルクォーテーションでくくる必要があります。

[% myheader = 'my/misc/header' %]
[% INCLUDE myheader %] # 'myheader'
[% INCLUDE $myheader %] # 'my/misc/header'
[% INCLUDE "$myheader" %] # 'my/misc/header'

ファイルに埋め込まれているテンプレートディレクティブは適宜処理されます。
定義されている全ての変数はインクルードされるテンプレートからも利用・参照が可能です。

[% title = 'Hello World' %]
[% INCLUDE header %]
<body>
...

headerファイル:
<html>
<title>[% title %]</title>

出力結果:
<html>
<title>Hello World</title>
<body>
...

ローカル変数定義はテンプレート名の後に記載でき、存在する変数を一時的にマスキングします。
ディレクティブ中の半角スペースは無視されるので、同じ行、次の行、コメント付きの複数分割された行などに変数定義を追加できます(あなたが望めば)。

[% INCLUDE table %]
[% INCLUDE table title="Active Projects" %]
[% INCLUDE table
title = "Active Projects"
bgcolor = "#80ff00" # 薄黄緑色
border = 2
%]

INCLUDEはテンプレートを処理する前に、全ての変数をローカライズ(コピー)します。
インクルードされたテンプレートに施された変更は、そのテンプレート自体の変数に影響をおよぼすことはありません。

[% foo = 10 %]
foo is originally [% foo %]
[% INCLUDE bar %]
foo is still [% foo %]
[% BLOCK bar %]
foo was [% foo %]
[% foo = 20 %]
foo is now [% foo %]
[% END %]

出力結果: foo is originally 10 foo was 10 foo is now 20 foo is still 10

Technical Note:
スタッシュ(上書きを防ぐため、「INCLUDE」前にコピーされた変数により処理されたもの)のローカライズは単に見かけ上のものです。トップレベルの変数名前空間(ハッシュ)はコピーされますが、他の、より深い構造体(ハッシュ、配列、オブジェクト)のコピーは行われません。従って、ハッシュを参照している変数「foo」は、新しい変数「foo」を作成するためにコピーされますが、その変数は同じハッシュ配列を指し示しています。そのため、もし混合変数(foo.bar)を更新すると、スタッシュのローカライズに無頓着なオリジナルコピーを変更することになります。もし、保存された変数の値にこだわらない、またはインクルードしたテンプレートに任せてしまうのであれば、INCLUDEよりも、ローカライズを行わないために動作の速い「PROCESS」を使うほうが良いかもしれません。

バージョン2.04以降、INCLUDE文に、ローカル変数であるドット付きの変数を記述することができます。しかし、上記で説明したローカライズ問題のために(もし、先述のTechnical Noteを読み飛ばしているなら、戻って読むか、この段落も読み飛ばして下さい)、変数は実際には「ローカル」ではありません。もし変数名の最初の要素が既にハッシュを参照していた場合、その変数の更新は、オリジナルの変数に影響を与えることになります。

[% foo = {
bar = 'Baz'
}
%]

[% INCLUDE somefile foo.bar='Boz' %]
[% foo.bar %] # Boz

このふるまいは予測しにくいものです(将来改良されるでしょう)。もしあなたがそれで何をしているのか、そして問題の変数が明らかになっている(またはいない)のを(そうなることを予期して)確信しているのであれば、この特徴を、強力な「グローバル」データ共有テクニックとして頼ることができるでしょう。そうでなければ、常にシンプルで、よりわかりやすい(ドットを使わない)変数を、INCLUDEその他同様のディレクティブのパラメータとするほうがむしろ良いかもしれません。

もしいくつかのテンプレートを一度に処理したいのであれば、各々の名前(くくられているか、くくられていない名前のみ。くくられていない'$variables'は不可)を、「+」でつなげて記述することができます。INCLUDEは記述通りに処理します。

[% INCLUDE html/header + "site/$header" + site/menu
title = "My Groovy Web Site"
%]

変数のスタッシュは一度だけローカライズされ、テンプレート中の同名の変数は記述通り処理されます。この方法は、いくつかに分かれたINCLUDE文を記述するよりも、わずかに速くなります(変数スタッシュを1回コピーすれば良いだけなので)が、最初のファイル内における変数の変更は、2つ目以降のファイルで参照できてしまうため、完全に「安全」というわけではありません。これはもちろんあなたが望むものかもしれませんが、やはり、それはそうではないかもしれません。

PROCESS

PROCESSはINCLUDEと同様ですが、テンプレート処理の前に、変数のローカライズを行いません。挿入されたテンプレート内の変数へ加えされた変更は、挿入しているテンプレートにおいても参照できます。

[% foo = 10 %]
foo is [% foo %]
[% PROCESS bar %]
foo is [% foo %]
[% BLOCK bar %]
[% foo = 20 %]
changed foo to [% foo %]
[% END %]

出力結果:
foo is 10
changed foo to 20
foo is 20

パラメーターはPROCESS文内で記述されるかもしれませんが、これらもまた参照可能な変更になるでしょう。

[% foo = 10 %]
foo is [% foo %]
[% PROCESS bar foo = 20 %]
foo is [% foo %]
[% BLOCK bar %]
this is bar, foo is [% foo %]
[% END %]

出力結果:
foo is 10
this is bar, foo is 20
foo is 20

テンプレート処理前に変数スタッシュのローカライズ(コピー)を行わないため、PROCESSはINCLUDEよりもわずかに速くなります。INSERTとINCLUDEと同様、第1のパラメーターは、英数字・アンダーバー・ドット・スラッシュのみで構成されている限り、くくる必要がありません。テンプレート名を表示するための変数には明示的にするため、$を先頭に付記します。

[% myheader = 'my/misc/header' %]
[% PROCESS myheader %] # 'myheader'
[% PROCESS $myheader %] # 'my/misc/header'

INCLUDEと同様、複数のテンプレートを「+」で記述でき、順番に処理されます。

[% PROCESS html/header + my/header %]

WRAPPER

ページあるいはページ内のサブセクションに共通のヘッダーおよびフッタを加えるのは珍しいことではありません。例えば以下の通り:

[% INCLUDE section/header
title = 'Quantum Mechanics'
%]
Quantum mechanics is a very interesting subject wish
should prove easy for the layman to fully comprehend.
[% INCLUDE section/footer %]
[% INCLUDE section/header
title = 'Desktop Nuclear Fusion for under $50'
%]

This describes a simple device which generates significant
sustainable electrical power from common tap water by process
of nuclear fusion.
[% INCLUDE section/footer %]

挿入された個々のコンポーネントは、以下の通りです:

section/header:
<p>
<h2>[% title %]</h2>

section/footer:
</p>

WRAPPERはこれをややシンプルにしてくれます。ある出力を生成するために最初に処理される、ENDまでブロックを囲みます。その後、これは変数"content"として指定されたテンプレート・ファイルあるいはBLOCKに渡されます。

[% WRAPPER section
title = 'Quantum Mechanics'
%]
Quantum mechanics is a very interesting subject wish
should prove easy for the layman to fully comprehend.
[% END %]
[% WRAPPER section
title = 'Desktop Nuclear Fusion for under $50'
%]
This describes a simple device which generates significant
sustainable electrical power from common tap water by process
of nuclear fusion.
[% END %]

"section"テンプレートは次のように定義することができます:

<p>
<h2>[% title %]</h2>
[% content %]
</p>

他のブロックのように、WRAPPERを副次的記法で使用することができます:

[% INSERT legalese.txt WRAPPER big_bold_table %]

WRAPPER文には複数のテンプレートを記述することもできます。列挙順に最も外側のラッパーテンプレートから最も深いラッパーテンプレートまで指し示します。
例えば、下記のようなテンプレートブロックを定義します:

[% BLOCK bold %]<b>[% content %]</b>[% END %]
[% BLOCK italic %]<i>[% content %]</i>[% END %]

WRAPPER文:

[% WRAPPER bold+italic %]Hello World[% END %]

上の文は下記のような出力を生成します:

<b><i>Hello World</i></b>

BLOCK

BLOCK〜ENDはINCLUDE、PROCESS、WRAPPERによって処理されるテンプレートコンポーネントブロックを定義するために利用できます。

[% BLOCK tabrow %]
<tr><td>[% name %]</td><td>[% email %]</td></tr>
[% END %]
<table>
[% PROCESS tabrow name='Fred' email='fred@nowhere.com' %]
[% PROCESS tabrow name='Alan' email='alan@nowhere.com' %]
</table>

BLOCKは、その定義が同一ファイルに存在する場合には、定義されるより前に利用することができます。BLOCK定義それ自体は何の出力も生成しません。

[% PROCESS tmpblk %]
[% BLOCK tmpblk %] This is OK [% END %]

テンプレート片の出力を得るために匿名のBLOCKを使用することができます。

[% julius = BLOCK %]
And Caesar's spirit, ranging for revenge,
With Ate by his side come hot from hell,
Shall in these confines with a monarch's voice
Cry 'Havoc', and let slip the dogs of war;
That this foul deed shall smell above the earth
With carrion men, groaning for burial.
[% END %]

命名されたブロックのように、ブロックが定義される時、処理される他のテンプレートディレクティブを含むことができます。その後、ブロックによって生成された出力は、変数"julius"に割り当てられます。

匿名BLOCKはブロックマクロの定義にも利用できます。マクロが呼ばれるごとに、囲んでいるブロックが処理されます。

[% MACRO locate BLOCK %]
The [% animal %] sat on the [% place %].
[% END %]
[% locate(animal='cat', place='mat') %] # The cat sat on the mat
[% locate(animal='dog', place='log') %] # The dog sat on the log

条件処理

IF / UNLESS / ELSIF / ELSE

IFとUNLESSは、実行時に該当ブロックの処理をするか無視するために利用できます。

[% IF frames %]
[% INCLUDE frameset %]
[% END %]
[% UNLESS text_mode %]
[% INCLUDE biglogo %]
[% END %]

複数の条件はELSIF、ELSEブロックでつなげられます。

[% IF age < 10 %]
Hello [% name %], does your mother know you're
using her AOL account?
[% ELSIF age < 18 %]
Sorry, you're not old enough to enter
(and too dumb to lie about your age)
[% ELSE %]
Welcome [% name %].
[% END %]

下記の条件記号が利用可能です:

== != < <= > >= && || ! and not

"and"、"or"、"not"は、それぞれ"&&"、"||"、"!"へのエイリアスとして提供されています。

条件は任意で複雑かもしれず、Perlのように同じ優先度で評価されます。明示的に評価順を決定するために、括弧を使用することができます。

# ばかばかしいほど複雑な例
[% IF (name == 'admin' || uid <= 0) && mode == 'debug' %]
I'm confused.
[% ELSIF more > less %]
That's more or less correct.
[% END %]

SWITCH / CASE

SWITCH/CASEは複数の条件結果に分岐するために使用することができます。SWITCHは、最初に与えられた式を予測し、各CASEと比較します。各CASEには一つの値、またはマッチするような値のリストを持たせます。CASEは空の場合や、デフォルトのマッチを明示するために[% CASE %]のように書かれるかもしれません。一つのCASEにマッチすると、CASE間を移動することはありません。

[% SWITCH myvar %]
[% CASE value1 %]
...
[% CASE [ value2 value3 ] %]   # 複数の値
...
[% CASE myhash.keys %]   # 同上
...
[% CASE %]   # デフォルト
...
[% END %]

ループ処理

FOREACH

FOREACHはリスト中から一つずつアイテムを取り出し、ブロック内の処理を行います。

my $vars = {
foo => 'Foo',
items => [ 'one', 'two', 'three' ],
};

テンプレート:
Things:
[% FOREACH thing = [ foo 'Bar' "$foo Baz" ] %]
* [% thing %]
[% END %]

Items:
[% FOREACH i = items %]
* [% i %]
[% END %]

Stuff:
[% stuff = [ foo "$foo Bar" ] %]
[% FOREACH s = stuff %]
* [% s %]
[% END %]

出力結果:
Things:
* Foo
* Bar
* Foo Baz

Items:
* one
* two
* three

Stuff:
* Foo
* Foo Bar

= の代わりに INを使うこともできます。

[% FOREACH crook IN government %]

代入先の変数を明示しないでFOREACHを使用した場合、ハッシュは自動的に参照されます。

[% userlist = [
{ id => 'tom', name => 'Thomas' },
{ id => 'dick', name => 'Richard' },
{ id => 'larry', name => 'Lawrence' },
]
%]
[% FOREACH user IN userlist %]
[% user.id %] [% user.name %]
[% END %]

省略版:

[% FOREACH userlist %]
[% id %] [% name %]
[% END %]

この方法は、すでに存在する変数にハッシュ値を上書きしないよう、ローカライズされた変数を作るということを覚えておいてください。FOREACH文に挿入された、定義、および定義済み変数は最後に破棄されるでしょう。

しかしながら、通常の操作の下では、ループ変数はFOREACHが終了した後もスコープ内に留まります(※:スコープ内の上書きされた変数)。これは変数が隠れたオブジェクト(下記参照)として、またループの最終処理を分析するのに役立ちます。

FOREACHはハッシュ配列におけるエントリを繰り返し通るものとして使えます。ハッシュにおける各々のエントリは、「キー」と「値」を含むハッシュ配列が(キーをベースとした順で)ソートされ、返されます。

[% users = {
tom => 'Thomas',
dick => 'Richard',
larry => 'Lawrence',
}
%]
[% FOREACH u IN users %]
* [% u.key %] : [% u.value %]
[% END %]

Output:

* dick : Richard
* larry : Lawrence
* tom : Thomas

NEXTはFOREACHループの次の繰り返しに処理を移します。

[% FOREACH user IN userlist %]
[% NEXT IF user.isguest %]
   Name: [% user.name %] Email: [% user.email %]
[% END %]

LASTはループを中断する場合に使用されます。BREAKがLASTのエイリアスとして提供されています。

[% FOREACH match IN results.nsort('score').reverse %]
[% LAST IF match.score < 50 %]
[% match.score %] : [% match.url %]
[% END %]

FOREACH文はTemplate::Iteratorモジュールを実装しています。FOREACHのための、オブジェクトへの参照は、「loop」という変数で暗黙裏に利用できます。下記のメソッドはloopオブジェクトで呼び出すことができます。

size() リストの要素数
max() 最後の要素のインデックス (size - 1)
index() 0からmax()のうちの、現在の繰り返し処理のインデックス
count() 1からsize()のうちの、現在の繰り返し処理のカウント(index() + 1)
first() 現在の処理が一番最初の処理であれば真
last() 現在の処理が一番最後の処理であれば真
prev() リストのうち、一つ前のアイテムを返す
next() リストのうち、一つ次のアイテムを返す

詳細はTemplate::Iteratorを参照して下さい。

例:
[% FOREACH item IN [ 'foo', 'bar', 'baz' ] -%]
[%- "<ul>\n" IF loop.first -%]
  <li>[% loop.count %]/[% loop.size %]: [% item %]
[%- "</ul>\n" IF loop.last -%]
[% END %]

出力:
<ul>
<li>1/3: foo
<li>2/3: bar
<li>3/3: baz
</ul>

以前のものとの互換性を保つため、numberがcountのエイリアスとして提供されていますが、いくつかのバージョンでは好ましくありません。

入れ子となったloopでも、loop変数は正確に深い部分を参照し、その処理の最後には以前の処理の値(たとえばもう一つ外のloop)に戻されるでしょう。

[% FOREACH group IN grouplist;
# loop には group のものが入ります
"Groups:\n" IF loop.first;
FOREACH user IN group.userlist;
# loop には user のものが入ります
"$loop.count: $user.name\n";
END;
# loop には再び group のものが入ります
"End of Groups\n" IF loop.last;
END
%]

「iterator」プラグインもiteratorオブジェクトを明示的に作成するために使うことができます。これは入れ子になったループの中で、内側のループから外側のループへの参照を維持したい場合に役立ちます。iteratorプラグインは「loop」以外の名前のiteratorを作成することができます。詳細はTemplate::Plugin::Iteratorを参照して下さい。

[% USE giter = iterator(grouplist) %]
[% FOREACH group IN giter %]
[% FOREACH user IN group.userlist %]
user #[% loop.count %] in
group [% giter.count %] is
named [% user.name %]
[% END %]
[% END %]

WHILE

WHILEは与えられた条件が真である限り、ブロック内の処理を繰り返します。式にはIFやUNLESSのように任意で複雑なものが可能です。

[% WHILE total < 100 %]
...
[% total = calculate_new_total %]
[% END %]

割り振られた値を評価するために()で囲むことができます。

[% WHILE (user = get_next_user_record) %]
[% user.name %]
[% END %]

NEXTは次の繰り返しを開始するために、BREAKはループを終了させるために、それぞれFOREACHと同様に使用できます。

テンプレートツールキットはWHILEの無限ループを防ぐため、安全装置カウンターを使っています。もしループが1000回を超えた場合、「未定義」例外が投げられ、エラー報告されるでしょう。

WHILE loop terminated (> 1000 iterations)

もし必要であれば、$Template::Directive::WHILE_MAX変数でこの作用をコントロールし、より高い値を設定できます。

フィルター、プラグイン、マクロ、Perl

FILTER

FILTERはブロック出力後の後処理を行うために利用できます。多くのフィルターがテンプレートツールキットによって提供されています。例えば「html」フィルターは < や > や & 文字を、HTMLタグや参照マークと見なされないようにエスケープします。

[% FILTER html %]
HTML text may have < and > characters embedded
which you want converted to the correct HTML entities.
[% END %]

出力:

HTML text may have < and > characters embedded
which you want converted to the correct HTML entities.

FILTERは下記ようにブロックでない文にも適用できます。例えば、

[% INCLUDE mytext FILTER html %]
|(パイプ)はFILTERのエイリアスとして使用できます。

[% INCLUDE mytext | html %]
複数のフィルターを互いにつなげることができ、それらは連続で呼び出されます。

[% INCLUDE mytext FILTER html FILTER html_para %]
または
[% INCLUDE mytext | html | html_para %]

フィルターは「静的」または「動的」にかけられます。静的フィルターは渡されたテキスト文字列を唯一の引数とし、修正したテキストを返す単純なルーチンです。HTMLフィルターが静的フィルターの例で、以下のように実装されています。

  sub html_filter {
      my $text = shift;
      for ($text) {
          s/&/&amp;/g;
          s/</&lt;/g;
          s/>/&gt;/g;
      }
      return $text;
  }
 

動的フィルターはテンプレートから呼ばれた時に明示されている複数の引数を処理します。「repeat」フィルターはそのようなフィルターの例で、入力したテキストを繰り返す回数を示した数字を引数とします。

[% FILTER repeat(3) %]blah [% END %]

出力:

blah blah blah

これらはフィルター「factories」として実装されています。factoryサブルーチンは追加の引数とともにカレントのTemplate::Contextオブジェクトへの参照を経て、実装したフィルターを参照するサブルーチンとして返します。「repeat」フィルターfactoryは以下のように実装されています。

  sub repeat_filter_factory {
      my ($context, $iter) = @_;
      $iter = 1 unless defined $iter;
      return sub {
          my $text = shift;
          $text = '' unless defined $text;
          return join('\n', $text) x $iter;
     }
  }
 

FILTERSオプション(Template::Manual::Configに記述)はTemplateオブジェクトのインスタンス作成時にカスタムフィルターを定義することができます。Template::Contextのdefine_filter()メソッドを使うと、いつでもフィルターを定義することができます。

フィルターを使う時に、エイリアスを割り当てることもできます。これは動的フィルタを同じ設定で何度も使う場合に役立ちます。

[% FILTER echo = repeat(2) %]
Is there anybody out there?
[% END %]
[% FILTER echo %]
Mother, should I build a wall?
[% END %]

出力:

Is there anybody out there?
Is there anybody out there?
Mother, should I build a wall?
Mother, should I build a wall?

FILTERはフィルター名を自動的に認識します。INCLUDEなどのようにフィルター名を$の付いた変数で指定することができます。

[% myfilter = 'html' %]
[% FILTER $myfilter %] # same as [% FILTER html %]
...
[% END %]

テンプレート変数は静的フィルターでも定義することができます。しかし、テンプレートツールキットは自動的に変数に結び付けられたサブルーチンを呼び出し、その戻り値を利用します。従って、上記の例は以下のように実装することが可能です。

      my $vars = {
          myfilter => sub { return 'html' },
      };
 

テンプレート:

[% FILTER $myfilter %] # same as [% FILTER html %]
...
[% END %]

FILTERによって使用されるサブルーチンを参照するテンプレート変数を定義する場合は、フィルター操作を行うことのできるサブルーチンへの参照を返す、サブルーチン(テンプレートツールキットによって自動的に呼ばれる)を作るべきです。この方法で実装される静的フィルターを記します。

     my $vars = {
         myfilter => sub { \&my_filter_sub },
     };
     sub my_filter_sub {
         my $text = shift;
         # do something
         return $text;
     }
 

テンプレート:

[% FILTER $myfilter %]
...
[% END %]

逆に、テンプレートツールキットがサブルーチンではなく、オブジェクトだと思うように、サブルーチンの参照をクラス(どんなクラスでも)へblessすることができます。これは「値を返すためのサブルーチンの呼び出し」を回避する自動魔術になるでしょう。

     my $vars = {
         myfilter => bless(\&my_filter_sub, 'anything_you_like'),
     };
 

テンプレート:

[% FILTER $myfilter %]
...
[% END %]

フィルターはローカルに残ったテンプレート変数と結びついています。すなわち、もしINCLUDEによって読み込まれたテンプレート中のPERLブロックでフィルターを定義した場合、フィルター定義は、そのテンプレートの終わる時点(スタッシュがdeローカライズされ、元の変数の状態が復元される時)までの間のみ存在することになるでしょう。もし、あなたがプロセッサの寿命分存在するフィルター、または追加の動的なフィルターファクトリーを定義したい場合には、カレントのTemplate::Contextオブジェクトにあるdefine_filter()メソッドを呼び出すと良いでしょう。

利用可能なフィルターの完全なリストは、Template::Manual::Filtersを参照してください。説明と、使い方のサンプルがあります。

USE

USEは「プラグイン」拡張モジュールを読み込み・初期化するために使えます。

[% USE myplugin %]

プラグインは、特別なオブジェクト指向インターフェースに適合した、正規のPerlモジュールで、テンプレートツールキットによって自動で読み込まれ、使用されます。このインターフェースの詳細と、プラグインの情報はTemplate::Pluginを参照してください。

プラグイン名はフルモジュール名を構築するため、大文字・小文字を区別し、PLUGIN_BASEの値(デフォルト:'Template::Plugin')を付加します。名前中のピリオド','は'::'に変換されるでしょう。

[% USE MyPlugin %] # => Template::Plugin::MyPlugin
[% USE Foo.Bar %] # => Template::Plugin::Foo::Bar

いくつかの標準的なプラグインはテンプレートツールキットに含まれています(Template::Manual::Pluginsを参照してください)。これらは、下記のように表記でき、特定の名前に割り当てられます。

[% USE cgi %] # => Template::Plugin::CGI
[% USE table %] # => Template::Plugin::Table

追加パラメータは、プラグイン名の後に記述でき、それらもまたnew()コンストラクタを通過します。カレントのTemplate::Contextオブジェクトへの参照は、1つ目のパラメータとして常に通過します。

[% USE MyPlugin('foo', 123) %]

上記は下記と同等:

     Template::Plugin::MyPlugin->new($context, 'foo', 123);
 

名前付きのパラメータもたぶん使用可能です。これらはそれぞれインターフェースに呼び出された一般的なコードとして、コンストラクタへの最後のパラメータとする参照によって通過したハッシュとして整理されます。

[% USE url('/cgi-bin/foo', mode='submit', debug=1) %]

上記は下記と同等:

     Template::Plugin::URL->new($context, '/cgi-bin/foo'
                                          { mode => 'submit', debug => 1 });
 

プラグインは様々なデータ型(一般変数、ハッシュ、リスト、コードへの参照)に対応しますが、これは一般にオブジェクト参照となります。メソッドは、オブジェクト(または特定のデータ型に関連あるもの)の下、呼び出されます。

[% USE table(mydata, rows=3) %]
[% FOREACH row = table.rows %]
<tr>
[% FOREACH item = row %]
<td>[% item %]</td>
[% END %]
</tr>
[% END %]

どちらか一方の名前は、恐らく、参照されることのできるものによって、プラグインに提供されるでしょう。

[% USE scores = table(myscores, cols=5) %]
[% FOREACH row = scores.rows %]
...
[% END %]

異なる設定で、複数のプラグインオブジェクトを作るために、このようなアプローチも可能です。この例は、printf関数によるテキスト整形のための、変数と結びついたサブルーチンを作るために、「format」プラグインがどのように使われるかを表しています。

[% USE bold = format('<b>%s</b>') %]
[% USE ital = format('<i>%s</i>') %]
[% bold('This is bold') %]
[% ital('This is italic') %]

出力:

<b>This is bold</b>
<i>This is italic</i>

次の例は、ベース部分と付加クエリから、動的にURLを構築するために「URL」プラグインがどのように使われるかを表しています。

[% USE mycgi = URL('/cgi-bin/foo.pl', debug=1) %]
<a href="[% mycgi %]">...
<a href="[% mycgi(mode='submit') %]">...

出力:

<a href="/cgi-bin/foo.pl?debug=1">...
<a href="/cgi-bin/foo.pl?mode=submit&debug=1">...

「CGI」プラグインは、別のPerlモジュールへデリゲートするものの例です。これはLincoln Stein氏のCGI.pmモジュールの場合です。CGI.pmによって提供されている全てのメソッドはプラグイン経由で利用可能です。

[% USE CGI %]
[% CGI.start_form %]
[% CGI.checkbox_group(name => 'colours',
values => [ 'red' 'green' 'blue' ])
%]
[% CGI.popup_menu(name => 'items',
values => [ 'foo' 'bar' 'baz' ])
%]
[% CGI.end_form %]

Simon Matthews氏は、Tim Bunce氏のDBIモジュール(CPANで利用可能)へのインターフェースを提供する、DBIプラグインを書きました。これはちょっとした例です。

[% USE DBI('DBI:mSQL:mydbname') %]
[% FOREACH user = DBI.query('SELECT * FROM users') %]
[% user.id %] [% user.name %] [% user.etc.etc %]
[% END %]

ツールキットまたは、CPANで配布されているプラグインのさらなる情報はTemplate::Manual::Pluginsを参照してください。

LOAD_PERLオプション(デフォルト無効)は、外部のPerlモジュールが読み込まれた場合のため提供されます。もし、正規のPerlモジュール(すなわち、Template::Plugin::*でないもの、または、いくつかのPLUGIN_BASEと関係するモジュールでないもの)が、オブジェクト指向インターフェスと、new()コンストラクタをサポートしていれば、それらを読み込ませ、自動でインスタンス化させることができます。下記の平凡な例は、IO::Fileモジュールがどのように使われるかを表しています。

[% USE file = IO.File('/tmp/mydata') %]
[% WHILE (line = file.getline) %]
<!-- [% line %] -->
[% END %]

MACRO

MACROは、マクロが呼ばれた時に評価されるディレクティブやディレクティブブロックを、あなたが定義できるようにします。

[% MACRO header INCLUDE header %]

下記のようにマクロを呼び出します。

[% header %]

これは、下記と同等です。

[% INCLUDE header %]

マクロは名前の付いたパラメータを処理できます。これらの値はローカルに残ります。

[% header(title='Hello World') %]

下記と同等です。

[% INCLUDE header title='Hello World' %]

MACRO定義はパラメータ名を含みます。マクロから来た値は、これらローカル変数へ割り当てられます。その他の名前の付いたパラメータはこれらに付随します。

[% MACRO header(title) INCLUDE header %]
[% header('Hello World') %]
[% header('Hello World', bgcol='#123456') %]

下記と同等です。

[% INCLUDE header title='Hello World' %]
[% INCLUDE header title='Hello World' bgcol='#123456' %]

これは別の例で、chunkとjoinという仮想メソッドを使った、3ケタごとにカンマで区切った数字を表示するマクロの定義です。

[% MACRO number(n) GET n.chunk(-3).join(',') %]
[% number(1234567) %] # 1,234,567

MACROは、他のディレクティブより先行して、ディレクティブ構造を定めなければなりません。

[% MACRO header IF frames %]
[% INCLUDE frames/header %]
[% ELSE %]
[% INCLUDE header %]
[% END %]
[% header %]

MACROは単なるBLOCKとして定義されるかもしれません。ブロックはマクロが呼ばれるたびに評価されるでしょう。

[% MACRO header BLOCK %]
...content...
[% END %]
[% header %]

もし、EVAL_PERLオプションを付けた場合、MACROを定義した時も、PERLブロック(下記参照)として定義することができます。

[% MACRO triple(n) PERL %]
my $n = $stash->get('n');
print $n * 3;
[% END -%]

PERL

(高度な読者へ)

PERLは、Perlのコードを含んだブロックの開始を印すために使用することができます。Perlのコードが評価されるために、EVAL_PERLオプションが有効になっていなければなりません。有効でない場合、例外'perl'が「EVAL_PERL not set」メッセージと共に投げられます。

PerlのコードはTemplate::Perlパッケージで評価されます。パッケージ変数$contextが現在のTemplate::Contextオブジェクトへの参照を持ちます。これは、テンプレートツールキットの「他のテンプレートの加工」「プラグインやフィルターの読み込み」その他の機能へアクセスすることができます。詳細はTemplate::Contextを参照してください。

[% PERL %]
print $context->include('myfile');
[% END %]

変数$stashは、テンプレート変数を司るトップレベルスタッシュオブジェクトへの参照を持ちます。これを通して、変数の値は、引き出され、またアップデートされます。詳細はTemplate::Stashを参照してください。

[% PERL %]
$stash-$gt;set(foo => 'bar');
print "foo value: ", $stash->get('foo');
[% END %]

出力 foo value: bar

printf()を呼び出しによって、PERLブロックから、出力が生成されます。STDOUTの代わりに、Template::Perl::PERLOUTハンドルが選択(出力バッファに結びつきます)されることに注意してください。

[% PERL %]
print "foo\n"; # OK
print PERLOUT "bar\n"; # OK, 上に同じ
print Template::Perl::PERLOUT "baz\n"; # OK, 上に同じ
print STDOUT "qux\n"; # 間違い!
[% END %]

PERLブロックは、別のテンプレートディレクティブを含むかもしれません。これらは、Perlのコードが評価される前に加工されます。

[% name = 'Fred Smith' %]
[% PERL %]
print "[% name %]\n";
[% END %]

このような、上の例に含まれたPerlのコードは、以下のように評価されます。

print "Fred Smith\n";

PERLブロックからdie()を通って、例外が投げられるかもしれませんが、TRYブロックの中で正しくキャッチされるでしょう。

[% TRY %]
[% PERL %]
die "nothing to live for\n";
[% END %]
[% CATCH %]
error: [% error.info %]
[% END %]

出力: error: nothing to live for

RAWPERL

(超高度な読者へ)

テンプレートツールキットのパーサーは、ソーステンプレートを読み、出力として、Perlのサブルーチンテキストを生成します。そして、それをサブルーチン参照に評価するのに、eval()を使います。このサブルーチンはテンプレートを加工するために呼ばれ、Template Toolkitの機能性にアクセスすることができる、カレントのTemplate::Contextオブジェクトへの参照へ進みます。サブルーチンの参照はキャッシュでき、これ以上パーサーを呼び出すことなく、繰り返しテンプレートを加工することができます。

例えば、このようなテンプレート:

[% PROCESS header %]
The [% animal %] sat on the [% location %]
[% PROCESS footer %]

は、以下のようなPerlサブルーチン定義へと変換されます。

     sub {
         my $context = shift;
         my $stash   = $context->stash;
         my $output  = '';
         my $error;

         eval { BLOCK: {
             $output .=  $context->process('header');
             $output .=  "The ";
             $output .=  $stash->get('animal');
             $output .=  " sat on the ";
             $output .=  $stash->get('location');
             $output .=  $context->process('footer');
             $output .=  "\n";
         } };
         if ($@) {
             $error = $context->catch($@, \$output);
             die $error unless $error->type eq 'return';
         }

         return $output;
     }
 

上の例などのように生成されたPerlコードを調べるには、$Template::Parser::DEBUGパッケージ変数に真の値を設定してください。また、人が読めるようなコード整形をさせるたのに、$Template::Directive::PRETTYにも真の値を設定することができます。生成されたテンプレートサブルーチンのためのソースコードは、コンパイル時にSTDERRに印刷されるでしょう(すなわち、最初に、テンプレートが使用されています)。

$Template::Parser::DEBUG = 1;
$Template::Directive::PRETTY = 1;

...

$template->process($file, $vars)
|| die $template->error(), "\n";

PERL ... END を使えばテンプレートにPerlコードを埋め込むことができます(EVAL_PERLが設定されている場合)が、これはテンプレートサブルーチンが呼ばれるごとに、eval()を使う、ランタイム評価です。これは、本来フレキシブルですが、特にテンプレートが何回も処理されるかもしれない永続的なサーバ環境では効率的ではありません。

RAWPERLは、生成されるPerlサブルーチンテキストへ、直接、統合されたPerlコードを書くことができます。これはコンパイル時に一度だけ評価され、コンパイルされたサブルーチンの一部としてキャッシュされます。これにより、RAWPERLブロックはPERLブロックよりも効率的となります。

ダウンサイドでは、あなたは、より金属(訳者注:低レベルということ?)に近いコーディングをしなければなりません。PERLブロックでは、出力にprint()を呼び出せました。RAWPERLブロックは、そのような贅沢は提供しません。コードは生成されるサブルーチンテキストに直接挿入され、$output変数に付加する規約に従うことになります。

[% PROCESS header %]
[% RAWPERL %]
$output .= "Some output\n";
...
$output .= "Some more output\n";
[% END %]

この例のために生成されたサブルーチンのクリティカルな部分は、このような感じです:

     ...
     eval { BLOCK: {
     $output .=  $context->process('header');
         $output .=  "\n";
         $output .= "Some output\n";
     ...
         $output .= "Some more output\n";
         $output .=  "\n";
     } };
     ...
 

PERLブロックのように、$contextおよび$stashの参照は、あらかじめ定義され、RAWPERLコードで使用するのに有効となっています。

例外処理、フロー制御

TRY / THROW / CATCH / FINAL

(高度な要素)

テンプレートツールキットは完全に機能的で、入れ子にされた例外処理をサポートしています。TRYは対するENDまで続く例外処理範囲を示します。そのブロックの中に発生するどんなエラーも捕らえて、定義された一つのCATCHブロックで扱うことができます。

[% TRY %]
...blah...blah...
[% CALL somecode %]
...etc...
[% INCLUDE someblock %]
...and so on...
[% CATCH %]
An error occurred!
[% END %]

エラーは例外(Template::Exceptionクラスのオブジェクト)として発生し、'type'と'info'という二つのフィールドを持ちます。例外の'type'は、文字列、数値、半角スペース、ピリオドといったあらゆる文字を持つことができ、発生したエラーの種類を提示させるために使用できます。'info'は実際の間違いを示したエラーメッセージを持ちます。CATCHブロックでは、例外オブジェクトはerror変数のエイリアスとされます。'type'と'info'フィールドへはダイレクトにアクセスできます。

[% mydsn = 'dbi:MySQL:foobar' %]
...
[% TRY %]
[% USE DBI(mydsn) %]
[% CATCH %]
ERROR! Type: [% error.type %]
Info: [% error.info %]
[% END %]

出力 ('foobar'という存在しないデータベースを仮定する):

ERROR! Type: DBI
Info: Unknown database "foobar"

'error'変数は、それ自身明示でき、"$type error - $info"の文字列で返されます。

...
[% CATCH %]
ERROR: [% error %]
[% END %]

出力:

ERROR: DBI error - Unknown database "foobar"

それぞれのCATCHブロックは、キャッチすべき固有の例外タイプを指定しているかもしれません。TRYブロックによって投げられる、異なるタイプの例外を扱うために、複数のCATCHブロックを用意できます。先ほどの例のように、タイプ指定の無いCATCHブロックは、捕らえ切れなかった例外をキャッチするデフォルトハンドラです。これは、[% CATCH DEFAULT %]のように記述することもできます。

[% TRY %]
[% INCLUDE myfile %]
[% USE DBI(mydsn) %]
[% CALL somecode %]
...
[% CATCH file %]
File Error! [% error.info %]
[% CATCH DBI %]
[% INCLUDE database/error.html %]
[% CATCH %]
[% error %]
[% END %]

';'で区切ることで、一つのタグ内に複数のディレクティブを記述できることを思い出してください。このように、よりシンプルなCATCHブロックを簡潔に書けるかもしれません:

[% TRY %]
...
[% CATCH file; "File Error! $error.info" %]
[% CATCH DBI; INCLUDE database/error.html %]
[% CATCH; error %]
[% END %]

または:

[% TRY %]
...
[% CATCH file ;
"File Error! $error.info" ;
CATCH DBI ;
INCLUDE database/error.html ;
CATCH ;
error ;
END
%]

DBIプラグインは(既に明白で無いなら)'DBI'型の例外を投げます。ここに捕らえられる他の'file'型の例外があります。

'file'エラーは、ファイルを見つけられない場合や、読み込みに失敗した場合、テンプレートツールキットによって、自動的に投げられ、INCLUDE、PROCESS、INSERT、WRAPPERディレクティブによってリクエストされたファイルをパース、加工します。もし、上の例にある'myfile'が見つからない場合、[% INCLUDE myfile %]文は、[% CATCH file %]ブロックで捕らえられた'file'例外を立て、出力を生成します:

File Error! myfile: not found

DEFAULTオプション(デフォルトで無効)でテンプレートファイルを見つけることができない時に使用されるデフォルトファイルを指定できることを覚えておいて下さい。存在しないファイルがリクエストされた時に起こされるファイル例外を防げます(もちろん、DEFAULTファイルが存在しない、ということが無い限り)。ファイルがいったん見つけらてからのエラー(すなわち、読み込みエラー、パースエラー)は通常のファイル例外として上げられるでしょう。

捕らえきれなかった例外(すなわち、TRYブロックでデフォルトのCATCHを書かなかった場合)は、たぶん、複数のテンプレートの向こうで入れ子にさせられた、直近のTRYブロックによってキャッチされるでしょう。もしエラーが、どのレベルでも捕らえられなければ、加工は中断され、Templateのprocess()メソッドは偽の値で呼び出し元に返るでしょう。関連するTemplate::Exceptionオブジェクトはerror()メソッドを呼ぶことで、検出できます。

[% TRY %]
...
[% TRY %]
[% INCLUDE $user.header %]
[% CATCH file %]
[% INCLUDE header %]
[% END %]
...
[% CATCH DBI %]
[% INCLUDE database/error.html %]
[% END %]

この例では、内側のTRYブロックは最初のINCLUDE文が予期した通り動くことを保障するために使用されました。挿入したいテンプレートの名前を供給するために変数user.headerを使いますが、それが存在しないテンプレートの名前や、無効なテンプレートディレクティブを含んでいても、可能です。もしINCLUDEが'file'エラーで失敗した場合、それを内側のブロックでCATCHし、デフォルトの'header'ファイルを代わりにINCLUDEします。外側のTRYブロックの範囲で発生した、あらゆるDBIエラーは、対応するCATCHブロックでキャッチされ、'database/error.html'が加工されるでしょう。挿入されたテンプレートは、全ての現在定義されているテンプレート変数を受け継ぎ、これらのエラーファイルはありがたいことに'error'変数として、現在発生した例外に対する情報を検出するためにアクセスできます。

'database/error.html':

<h2>Database Error</h2>
A database error has occurred: [% error.info %]

FINALブロックも記述することができます。これはTRYやCATCHの結果に関わらず実行されます。もし例外がキャッチされなかった場合には、FINALブロックは、直近のブロックや呼び出し元に返る前に実行されます。

[% TRY %]
...
[% CATCH this %]
...
[% CATCH that %]
...
[% FINAL %]
All done!
[% END %]

TRYブロックからの出力は例外が起こるポイントまで完全なままにされます。例えば、このようなテンプレートは:

[% TRY %]
This gets printed
[% THROW food 'carrots' %]
This doesn't
[% CATCH food %]
culinary delights: [% error.info %]
[% END %]

下記のような出力を生成します:

This gets printed
culinary delights: carrots

CLEARは、TRYブロックで作られた出力を消すために、CATCHやFINALブロックで使用できます。

[% TRY %]
This gets printed
[% THROW food 'carrots' %]
This doesn't
[% CATCH food %]
[% CLEAR %]
culinary delights: [% error.info %]
[% END %]

出力:

culinary delights: carrots

例外の型は、各々のレベルが、よくあるドット演算子で分割された階層型です。'DBI.connect'例外は'DBI'エラーの、より特定された種類です。同様に'myown.error.barf'は'myown.error'型(これ自身が'myown'エラー)の、より特定された種類です。'DBI'や'myown.error'のような一般的な例外を明示したCATCHハンドラは、明示的に定義されていない限り、同じ接頭語を持っている型もキャッチするでしょう。定義されたCATCHハンドラの順番は無関係であることに注意してください。より特定のハンドラは、より一般的、またはデフォルトのそれよりも、優先して例外を捕らえるでしょう。

[% TRY %]
...
[% CATCH DBI ;
INCLUDE database/error.html ;
CATCH DBI.connect ;
INCLUDE database/connect.html ;
CATCH ;
INCLUDE error.html ;
END
%]

この例では、'DBI.connect'エラーは自分自身のハンドラを持ち、より一般的な'DBI'ブロックは、その他のDBI、DBI.*エラーのために使用されます。デフォルトハンドラは、その他の全てのエラーをキャッチします。

テンプレート中でTHROWを使うことで、例外を発生させられます。第一引数(クォーテーションでくくる必要はありません。INCLUDEなどと同じです)は例外型で、その後に、関連するくくられた文字列、変数、のような値のエラーメッセージ、がそれに続きます。

[% THROW food "Missing ingredients: $recipe.error" %]

[% THROW user.login 'no user id: please login' %]

[% THROW $myerror.type "My Error: $myerror.info" %]

エラー情報フィールドに簡単なメッセージ以上のものを投げたいのであれば、THROWディレクティブに追加のパラメーターを記述することも可能です。

[% THROW food 'eggs' 'flour' msg='Missing Ingredients' %]

この場合、errorの'info'フィールドは、名前のついた引数(この場合、'msg' => 'Missing Ingredients')と、引数のリストを持った'args'(この場合、'eggs'と'flour')を持つ、ハッシュ配列となります。errorの'type'フィールドは変わらず、'food'にセットされます。

[% CATCH food %]
[% error.info.msg %]
[% FOREACH item = error.info.args %]
* [% item %]
[% END %]
[% END %]

これは、このような出力となります:

Missing Ingredients
* eggs
* flour

[% error.info.args.n %]のように、個々の引数を追記する場合、'info'ハッシュは、便利なショートカットのような、引数を直接参照するキーを持ちます。

[% error.info.0 %] # 右に同じ [% error.info.args.0 %]

例外は、テンプレート変数や定義されたプラグイン・その他の拡張へ、Perlコードからも投げることができます。例外が発生すると、Template::Exceptionオブジェクトを引数として参照する、die()が呼ばれます。そして、これはコードが呼び出されたところから、あらゆる囲まれたTRYブロックによってもキャッチされるでしょう。

     use Template::Exception;
     ...
     my $vars = {
     foo => sub {
         # ... do something ...
         die Template::Exception->new('myerr.naughty',
                                         'Bad, bad error');
         },
     };
 

テンプレート:

[% TRY %]
...
[% foo %]
...
[% CATCH myerr ;
"Error: $error" ;
END
%]

出力:

Error: myerr.naughty error - Bad, bad error

必要であれば、'info'フィールドもまた、別のオブジェクトやデータ構造を参照できます。

     die Template::Exception->new('myerror', {
     module => 'foo.pl',
     errors => [ 'bad permissions', 'naughty boy' ],
     });
 

テンプレートでは:

[% TRY %]
...
[% CATCH myerror %]
[% error.info.errors.size or 'no';
error.info.errors.size == 1 ? ' error' : ' errors' %]
in [% error.info.module %]:
[% error.info.errors.join(', ') %].
[% END %]

出力を生成:

2 errors in foo.pl:
bad permissions, naughty boy.

die()を、沢山存在するPerlコードの一般的な一つの文字列と共に呼び出すこともできます。これは自動的に'undef'(未定義の値、ということではなく'undef'というリテラル文字列)タイプの例外に変換されます。もし、文字列が新しい行と共に終了しなければ、Perlはよくある「 at $file line $line」メッセージを付加します。

     sub foo {
     # ... do something ...
     die "I'm sorry, Dave, I can't do that\n";
     }
 

もし、スコープ内にカレントのTemplate::Contextを持つプラグインや拡張コードを書いている場合(これがあなたとって何の意味も無いのであれば、あなたは安全にこのセクションを飛ばすことができます)、例外をcontextのthrow()メソッドで呼び出すこともできます。それを'undef'タイプの例外を作るため、($type, $info)のペアのパラメーター、または単に$info文字列を参照するTemplate::Exceptionオブジェクトへ投げることができます。

     $context->throw($e);        # exception object
     $context->throw('Denied');  # 'undef' type
     $context->throw('user.passwd', 'Bad Password');
 

NEXT

NEXTはFOREACHやWHILEループの次の繰り返しを始めるために使えます。

[% FOREACH user = userlist %]
[% NEXT IF user.isguest %]
Name: [% user.name %] Email: [% user.email %]
[% END %]

LAST

LASTはFOREACHやWHILEループを終了させるために使えます。

[% FOREACH user = userlist %]
Name: [% user.name %] Email: [% user.email %]
[% LAST IF some.condition %]
[% END %]

BREAKもLASTのエイリアスとして使用することができます。

RETURN

RETURNは、現在のテンプレートの加工を中止し、それが呼び出されたテンプレートまで戻り、そのINCLUDE、PROCESS、WRAPPER文の後から直ちに加工を再開させるために使用できます。もしテンプレートが存在しない場合、Templateのprocess()メソッドは、それを呼び出したコードへtrue値で返ります。

Before
[% INCLUDE half_wit %]
After

[% BLOCK half_wit %]
This is just half...
[% RETURN %]
...a complete block
[% END %]

出力:

Before
This is just half...
After

STOP

STOPは、プロセッサに対し、テンプレートをこれ以上加工することなく、礼儀正しく終了させるよう合図を出すために使用することができます。これは、計画された中止であり、Templateのprocess()メソッドは呼び出し元にtrue値で返ります。テンプレートの合図は、これは、テンプレートがディレクティブに従って、その中で正常に加工されたことを示しています。

[% IF something.terrible.happened %]
[% INCLUDE fatal/error.html %]
[% STOP %]
[% END %]
[% TRY %]
[% USE DBI(mydsn) %]
...
[% CATCH DBI.connect %]
<p>Cannot connect to the database: [% error.info %]</p>
<br>
We apologise for the inconvenience. The cleaning lady
has removed the server power to plug in her vacuum cleaner.
Please try again later.
</p>
[% INCLUDE footer %]
[% STOP %]
[% END %]

CLEAR

CLEARは現在のブロックの出力バッファをクリアするために使用できます。これはTRYブロックから生成される、エラーが発生したポイントまでの出力をクリアするのに一般的に最も使用されています。

[% TRY %]
blah blah blah # これは通常、そのままです
[% THROW some 'error' %] # 誤りのポイント
...
[% CATCH %]
[% CLEAR %] # TRYの出力をクリア
[% error %] # エラー文の表示
[% END %]

その他

META

METAは簡単なメタデータ項目をテンプレート中で定義させるのに使用できます。これらはテンプレートがパースされる時評価され、そういうものとして簡単な値を持つだけであるかもしれません(例えば、META変数に他の変数値を補間することはできません)。

[% META
title = 'The Cat in the Hat'
author = 'Dr. Seuss'
version = 1.23
%]

'template'変数は、処理されるメインテンプレートの参照を含んでいます。これらのメタデータ項目はテンプレートの属性として検索されるかもしれません。

<h1>[% template.title %]</h1>
<h2>[% template.author %]</h2>

'name'と'modtime'のメタデータ項目は、各テンプレートに、それらの名前と、エポックからの経過秒数を修正時間として含め、自動的に定義されます。

[% USE date %] # 時間の整形のため、Dateプラグインを使用
...
[% template.name %] last modified
at [% date.format(template.modtime) %]

PRE_PROCESSとPOST_PROCESSオプションで、全てのテンプレートに共通のヘッダー・フッターを付けることができます。これらのテンプレートが、メインテンプレートからの参照メタデータ項目にヘッダーとフッターを許容して、加工される時、'template'参照は正しく定義されます。

     $template = Template->new({
     PRE_PROCESS  => 'header',
     POST_PROCESS => 'footer',
     });
     $template->process('cat_in_hat');
 

header:

<html>
<head>
<title>[% template.title %]</title>
</head>
<body>

cat_in_hat:

[% META
title   = 'The Cat in the Hat'
author = 'Dr. Seuss'
version = 1.23
year   = 2000
%]
The cat in the hat sat on the mat.

footer:

<hr>
&copy; [% template.year %] [% template.author %]
</body>
</html>

上記の例から生成される出力:

<html>
<head>
<title>The Cat in the Hat</title>
</head>
<body>
The cat in the hat sat on the mat.
<hr>
&copy; 2000 Dr. Seuss
</body>
</html>

TAGS

TAGSは、それぞれのテンプレートファイルでSTART_TAG値と、END_TAG値を設定するために使用できます。

[% TAGS <+ +> %]
<+ INCLUDE header +>

TAGSは、命名されたTAG_STYLEも使用できます。

[% TAGS html %]
<!-- INCLUDE header -->

詳細は、TAGSとTAG_STYLEの設定オプションを参照してください。

DEBUG

DEBUGは、テンプレート中のデバッグメッセージを有効にしたり無効にしたりするために使用できます。DEBUG設定オプションは、あらゆる効果も持つために、DEBUG_DIRSを含めて、設定する必要があります。もしDEBUG_DIRSが設定されていない場合、パーサーは自動的に全てのDEBUG文を無視し、取り除きます。

DEBUGは、続くポイントからのデバッグメッセージを有効または無効にするために'on'、'off'パラメーターと共に使用できます。有効になっている場合、生成された出力中の、それぞれのディレクティブの出力は、ファイルを示すコメント、行、元のディレクティブテキストを、前に置いて出力されるでしょう。

[% DEBUG on %]
ディレクティブデバッグオン (DEBUGオプションが真であると仮定)
[% DEBUG off %]
ディレクティブデバッグオフ

'format'パラメーターはデバッグメッセージのフォーマットを変更するために使用できます。

[% DEBUG format '<!-- $file line $line : [% $text %] -->' %]

著作者

Andy Wardley <abw@andywardley.com>

http://www.andywardley.com/

バージョン

Template Toolkit バージョン2.12 2004年1月12日リリース

コピーライト

Copyright (C) 1996-2004 Andy Wardley. All Rights Reserved.
Copyright (C) 1998-2002 Canon Research Centre Europe Ltd.

このモジュールはフリーソフトであり、Perl自体と同じ条件の下、再配布や修正も行うことができます。