モダンPerlの世界へようこそ

第43回 Text::Xslate:永続環境に特化したテンプレートエンジン

この記事を読むのに必要な時間:およそ 5.5 分

TTの本体を差し替える

前回はウェブ業界で標準的に使われているTemplate Toolkitをより安全に使うためのカスタマイズ方法をいくつか紹介しました。しばしば批判の対象となってきたエスケープの問題については,TTでも適切な拡張を施せば後発のモジュールと遜色ないか,それ以上に便利に使えることは確認できたかと思います。

ただし,エスケープの仕方ひとつとってもさまざまなやり方があったように,TTは,柔軟である代償として速度面ではかなりの不利を抱えています。

もっとも,不利といってもそれはいまの,しかもかなり規模の大きな現場の視点で見たときの話で,数年前,おもなライバルがHTML::Mason(と,機能面で大きな差があるHTML::Templateだった時代にはTTも十分に高速といえましたし※1)⁠中小規模のサイトではいまでもTTで十分なレスポンスは得られます。

また,かれこれ10年近くもデファクトスタンダードとして君臨してきただけに,TTは,Perlのコードを書く人だけでなく,HTMLやCSSが専門の人や,設計や運用を担当している人の間でもノウハウの蓄積を期待できます。CPAN上での開発は停滞気味とはいえ,基本的な部分はもう十分に枯れていますし,必要に応じて好きなように拡張もできるのですから,現状に特に不満を感じていないのであれば,慣れたTTを使い続けたからといって何の問題もありません。

そのような前提を共有したうえで,たとえばソーシャルゲームのように本当に速度が必要とされる現場や,安価なVPSなど速度はともかく省メモリが求められる環境などで,どうしてもTTの遅さや大きさが問題になってきたときにどうするか,というのが今回のテーマ。

前回はあくまでもTTの枠組みのなかで工夫を重ねてみましたが,今回は,移行コストも考慮して,テンプレートにはなるべく手をつけずに,エンジン部分をまるごと取り替えることで高速化をはかる方法を紹介してみます。

※1
第41回でも紹介したPerl Template Roundupの結果を見ても,項目によって得手不得手はあるものの,TTはおおむねMasonよりも高速という結果が出ています。

Template::Alloy

TTとテンプレートレベルでは(ほぼ)互換性を持つエンジンの例としては,まずポール・シーモンズ(Paul Seamons)氏が2007年5月にリリースしたTemplate::Alloyがあげられます。

これはもともと氏が2003年末に開発を始めたCGI::ExというCGI用のフレームワークに付属していたテンプレートエンジン(CGI::Ex::Template)から派生したもので,当初はTTをそのままベースクラスとして利用していたのですが,2006年5月にリリースされたCGI::Ex 2.0でエンジン部分をまるごと書き換え,TTのテンプレートをそのまま扱える独自のエンジンに生まれ変わりました。

この新しいCGI::Ex::Templateは,ろくにキャッシュのきかない安価なCGI環境などでは,素のTTはもとより,Template::Stash::XSを使って高速化したものよりも速度を稼げるようになったのですが※2)⁠その後,氏が転職とともにTT以外のエンジンも利用するようになり,HTML::Templateなどの記法への対応も追加されたことから,CGI::Ex::Templateは単純にTTを高速化した代用品というより,複数のテンプレートエンジンのインタフェースを共通化したものという扱いを受けるようになります。それを,いかにもCGI環境でしか使えないかのように誤解させる名前空間の中に入れておくのはもったいないということで,議論の末に「合金」という意味の名前をつけて独立させたのがTemplate::Alloyの起源です。

Template::Alloyは,もともとTTから派生したものだけに,基本的な使い方はTTとほとんど変わりません。プラグインについても,TTがインストールされている環境であれば,TTのものをそのまま流用できます。

use strict;
use warnings;
use Template::Alloy;

my $ta = Template::Alloy->new;

$ta->process(\(my $tmpl =<<'TMPL'), {foo => '<"bar">'}) or die $ta->error;
[% USE JavaScript %]
[% foo %]
[% foo | html | js %]
TMPL

毎回htmlフィルタを書くのが面倒であれば,AUTO_FILTERに設定しておけば自動的にフィルタがかかるようになります。自動フィルタを適用したくない項目についてはnoneフィルタをあてておけば素の値を埋め込めます。

my $ta = Template::Alloy->new(AUTO_FILTER => 'html');

Template::Alloyでは,TT2の構文だけでなく,ほかのテンプレートから流用したものを含め,独自に拡張した構文を利用することもできます。

use strict;
use warnings;
use Template::Alloy;
use Template;

my $tmpl =<<'TMPL';
[%# Alloyでは複数の範囲を指定できます -%]
[% FOR i IN [1..2, 4..5] -%]
  [%- i -%]
[% END -%]
TMPL

my $ta = Template::Alloy->new;
my $tt = Template->new;

$ta->process(\$tmpl) or die $ta->error;
$tt->process(\$tmpl) or die $tt->error; # エラー

その他,細かな挙動の違いについてはTemplate::Alloy::TTのドキュメントに詳しく説明されています。また,一般的な使い方についても,Template::Alloyのドキュメントだけ読めばわかるくらいしっかりまとめられているので,TTにあまりなじみがなくても移行は楽です。

リポジトリやメーリングリストが公開されていないなど,サポート面にはやや難もありますが,2011年1月にリリースされた1.016ではセキュリティを高めるために上で紹介したAUTO_FILTERの設定が追加されるなど,作者氏のレスポンスは悪くないようですから,用途があうなら使ってみるのもよいでしょう。

※2
その成果はTemplate::Parser::CETというTTの拡張としてTT本家にも還元されています(CETはCGI::Ex::Templateの略です)⁠なお,CGI::Ex::Template/Template::Alloyにはさらに速度を稼ぐためにXS版も存在しているのですが,これはその後の開発で互換性が失われたようで,現在は正しく動作しません。

Template::Tiny

この文脈では,アダム・ケネディ(Adam Kennedy)氏が2009年末にリリースしたTemplate::Tinyの名前があがることもあります。これは::Tinyシリーズの常として,いろいろと制限の厳しい環境用に必要最小限のコードでTTの機能(のごく一部)を再実装しようというもので,正味のコードは200行ほどしかありませんから取り回しは簡単ですし,例によって非永続環境では素のTTや,場合によってはTemplate::Alloyよりも高速になることもあるのですが,繰り返し実行したときの性能劣化が激しく,永続環境ではTTほどの性能は出ませんし,何よりテンプレートの制約が大きすぎるため,TTの長所がほとんど生きてこないのが泣き所。ドット構文を使って複雑なデータ構造やオブジェクトをそのまま埋め込めるのはよいのですが,なにしろテンプレートレベルではHTML用のフィルタひとつかかりませんので,埋め込みたい値はあらかじめ自分でエスケープしてやらなければなりません。興味深い実装ではあるものの,::Tinyシリーズの常として,よほどの事情がなければ使う理由はないといってもよいでしょう。

Text::Xslate

gfxこと藤吾郎氏のText::Xslateについては,2010年のYAPC::Asiaなどでも紹介がありましたし,gihyo.jpでもWEB+DB PRESSの連載記事が公開されているので,すでにご存じの方も多いことでしょう。Xslateは,標準ではKolonと呼ばれる独自のテンプレート言語を使うようになっていますが,初期化時に設定を変えることでTTとかなり親和性の高い環境を作ることもできます。

use strict;
use warnings;
use Text::Xslate;
my $tx = Text::Xslate->new(
    syntax => 'TTerse',
    module => ['Text::Xslate::Bridge::TT2Like'],
);

TTerseというのはText::Xslateに同梱されているText::Xslate::Syntax::TTerseというTT風の構文をサポートするためのモジュールで,あまり複雑なことをしないのであればこれだけでも足りるのですが,TTerseはTTの仮想メソッドをそれほど多くはサポートしていないので,たいていはCPANからText::Xslate::Bridge::TT2Likeというモジュールをインストールして,TT風の仮想メソッドを追加してやる必要があります※3)⁠

※3
類似のモジュールにText::Xslate::Bridge::TT2というものもありますが,こちらは仮想メソッドの実行にTemplate Toolkitのモジュール群を使うため,場合によっては実行速度が半減してしまうので要注意です。

著者プロフィール

石垣憲一(いしがきけんいち)

あるときは翻訳家。あるときはPerlプログラマ。先日『カクテルホントのうんちく話』(柴田書店)を上梓。最新刊は『ガリア戦記』(平凡社ライブラリー)。

URLhttp://d.hatena.ne.jp/charsbar/

コメント

  • モダンPerlよりもモダン?

    進化を禁じられたモダンPerlはそのうちPerlに追い越されてしまう、ということになるんですかね?

    Commented : #2  半可通 (2012/07/27, 12:48)

  • フリーソフトウェアって何だっけ?

    「モダンPerl」というものはオリジナルのソフトウェア開発やその成果の公開を禁止するものなのですか?もしそうだとするならば、自由を求めるひとはモダンPerlでない、ただのPerlを使うと思います。

    Commented : #1  ひげおやじ (2012/02/24, 01:15)

コメントの記入