Template::Toolkitでutf-8を扱う

Perlutf-8って、何かと面倒くさいのね。前に使ってたのは5年ぐらい前に共用サーバでcgi書いてたぐらいだから全く把握してなかった。

まず判断が付かないのが、use utf8;した方がいいのかどうか。全部utf-8な環境では最初にuse utf8;しておくのが吉とdankogaiも言ってる。確かにマルチバイト文字列の長さを見たり、正規表現を通すには指定しておいた方がよさげ。でも、周りのライブラリがついてこなかったりして困る。

DBIで直接DBを叩いている古いスクリプトを移行したら、DBから取ってきたデータが文字化ける。DBIx::Classで取ってくるようにして、utf8_columns指定したら解決した。ただ、この状態でDB内のデータがどうなっているかとか、他のスクリプトとの連携がどうなるかは確認できていないので要調査。

DBからデータを拾ってくるのはよしとして、Template::Toolkitとの連携でまた問題発生ですよ。1枚のテンプレートで処理する場合は、「Template::Toolkitとutf8 - NO LIMIT Is. はてな支部」を参考に、

my $tt = Template->new(EVAL_PERL => 1);
$tt->process($c->{template}, $c->{stash}) || die $tt->error()."\n";

てな具合にコードを書いて、テンプレートに

[% RAWPERL %]use utf8;[% END %]

を書いてやれば解決したんだけど、TTのインスタンスを作る時にPROCESSでレイアウト(下地)に使うテンプレートを指定すると、レイアウト側のマルチバイト文字が化けるという現象に遭遇しました。use utf8;の指定をレイアウト側に書いても、EVAL_PERLがそこまで届いていないらしく動いてくれません。

どうしたものかと調べていたら、紫色の何かを口に押し付けたgeekが書いたTemplate::Provider::Encodingを使えばいいっぽい。ついにmiyagawaさんのお世話になる日が来たのね。

use utf8;
my $tt = Template->new(
    LOAD_TEMPLATES => [ Template::Provider::Encoding->new(INCLUDE_PATH => 'templates') ],
    STASH          => Template::Stash::ForceUTF8->new,
    PROCESS        => $c->{layout},
);
$tt->process($c->{template}, $c->{stash}) || die $tt->error()."\n";

こうしてやれば、テンプレート側でuse utf8;とか指定しなくても、全てうまい具合にやってくれました。解決。TTのコンストラクタの引数を工夫すればEVAL_PERLも通せるかも知れないけど、この方がきれいだよね。

Perlは過去の資産が豊富だけど、ググって出てくる情報が何年も前の情報だったりして、今もそれが正しいのか(時代の潮流に合っているのか)というところが不安になる。CGI.pmは出来るだけ使う方向で書いてるけど、それって大丈夫なの?とか。id:naoya氏のWEB+DB PRESSでの連載や、takesakoさんのPart1 正しいPerl/CGIの書き方:ITproぐらいしかまとまった「今」を伝える物は拾えてなくて、なかなか難儀してます。Perl系のFeedも拾い始めてはいるけど、継続的にやっていかないと感覚を身につけるのは難しいね。とにかく書きまくるしかないか。