Text::Templateを使ってみた

Text::Templateというのを使ってみたのでメモ。

これの特徴は、「テンプレートの記述にPerlをそのまま書ける」ということにあるらしい。

  • 独自のテンプレート言語を覚えなくてよい
  • 記述力が高い

というのがメリット。そのかわり、デメリットとしては

  • 何でも書けるからテンプレートに書きすぎてしまう可能性がある

というのがあるかと思われる。使い方次第だと思うけど。

使い方

基本的な使い方は以下のような感じ。

use strict;
use warnings;
use utf8;
use Encode;
use Text::Template;
use IO::File;

# 日本語を扱うときなどは自分でファイルを開く必要があるっぽい
my $fh_in = new IO::File("template.txt", "r") or die "$!";
$fh_in->binmode(":utf8");

my $template = Text::Template->new(TYPE => 'FILEHANDLE', SOURCE => $fh_in)
  or die "$Text::Template::ERROR";

# 入力はここでcloseして問題ない
$fh_in->close;

# テンプレートで展開される変数
my $name = "名無し";

# テンプレート展開
my $result = $template->fill_in(HASH => {name => $name});

# 出力
if (defined $result) { print encode("utf8", $result); }
else { die "couldn't fill in template : $Text::Template::ERROR"; }

fill_inという関数に与えるnameでテンプレートで展開する用の変数を渡す。テンプレートのファイルはtemplate.txtとした。例えば内容は以下のようになっているとする。

ハロー
{$name} さん!

{}で囲まれている部分にPerlプログラムを記述できる(ただしデリミタの変更は可能らしい)。この例の場合は、$nameが展開されて以下のような出力が得られる。

ハロー
名無し さん!

一応だけど、ここでそれぞれのファイルの文字コードはutf8。

関数を使う

テンプレートから関数を使うことも出来る。最初の例のfill_in関数の引数のHASHで関数を渡せばよい。

# 関数を渡す
my $result = $template->fill_in(HASH => {name => $name,
                                         hello => \&hello});

sub hello {
  my $name = shift;
  return "ハロー $name さん。";
}

テンプレートファイル(template.txt)には以下のように書く。

{hello($name)}

クラスを使う

テンプレートにクラスのオブジェクトを渡すことも出来る。普通に変数を渡すのとは違い、参照渡しをするのがポイント。

# サンプルのクラス
package Sample;

use strict;
use warnings;
use utf8;

sub new {
  my ($class) = @_;
  my $self = { NAME => "" };
  bless $self, $class;
  return $self;
}

sub set_name {
  my ($self, $name) = @_;
  $self->{NAME} = $name;
}

sub hello {
  my $self = shift;
  return "ハロー $self->{NAME} さん。";
}

package main;

use strict;
use warnings;
use utf8;
use Encode;
use Text::Template;
use IO::File;

# 日本語を扱うときなどは自分でファイルを開く必要があるっぽい
my $fh_in = new IO::File("template.txt", "r") or die "$!";
$fh_in->binmode(":utf8");

my $template = Text::Template->new(TYPE => 'FILEHANDLE', SOURCE => $fh_in)
  or die "$Text::Template::ERROR";

# 入力はここでcloseして問題ない
$fh_in->close;

# テンプレートで展開される変数
my $name = "名無し";

my $sample = new Sample;

# テンプレート展開。オブジェクトを渡す
my $result = $template->fill_in(HASH => {name => $name,
                                         sample => \$sample});

# 出力
if (defined $result) { print encode("utf8", $result); }
else { die "couldn't fill in template : $Text::Template::ERROR"; }

テンプレートファイルには以下のように書く。

{$sample->set_name($name); $sample->hello}

クラスを使う2

fill_inするところで、クラスが使えるようになっていれば、テンプレートの中でクラスをnew出来る。つまり、テンプレートファイルに以下のように書けるということ。

{$obj = new Sample; $obj->set_name($name); $obj->hello}

どうもここまでくると、テンプレートでやり過ぎてしまっているような感は拭えないが、使いどころはあるかもしれない。

だいたいこんな感じ。あと以下のようなところが分かってないが気になっている。気が向いたら調べる。

  • テンプレート側とプログラム側の名前空間の扱い方
  • 後ろの改行を消すやり方はあるか?(M4のdnl的なもの)