TT で custom filter (1)

前回書いたように undef 問題のため VMethods 期を越えて,FILTER 期に突入しました(順番が逆な気もします)。

sub empty_str {
  return '(未入力)' if $_ eq '';
  $_;
}

# [% FILTER empty_str %] hogehoge [% END %]
# [% 'hogehoge' | empty_str %]

このような自分独自のフィルタを使うためにはどのようにすればよいのか。Template::Manual::Config の POD の Plugins and Filters の項に書いてあります。

  1. Template の生成オプションとして FILTERS => {} を指定する
  2. Template::Context::define_filter() でフィルタを指定する
  3. filter ファクトリクラスを作って LOAD_FILTERS で指定する

1. Template の生成オプションとして FILTERS => {} を指定する

my $tt = Template->new({
  FILTERS => {
    'empty_str' => \&empty_str,
  },
});

# same configuration for Template::Context
my $ttc = Template::Context->new({
  LOAD_FILTERS => [
    Template::Filters->new({
      FILTERS => {
        'empty_str' => \&empty_str,
      },
    }),
  ],
});

このようにしてやります。後段の Template::Context バージョンを見て頂くとわかるとおり,標準 filter ファクトリクラスの Template::Filters が強力なために,そこで吸収しているのです(内的には)。

ひとつひとつフィルタを指定していくのがめんどくさいという方には,TOMYHERO さん作の,Template::Filters::LazyLoader があります。これは,指定したモジュール以下の階層のフィルタサブルーチンを自動的に読み込んでフィルタとして登録してくれるというとても意欲的なモジュールです。私はそこまで lazy じゃないので残念ながら使いませんが(すいません)。

2. Template::Context::define_filter() でフィルタを指定する

すでに生成した Template コンテキストに対してフィルタを登録することができます。

$tt->context->define_filter('empty_str', \&empty_str, 0);  # as static filter

フレームワークによって Template オブジェクトはすでに生成されているよ,という方はこちらのほうが使いやすいかもしれません。最後の 0 は static filter であれば省略することができます。
内的には LOAD_FILTERS のチェインに順番に store() を試みています。

3. filter ファクトリクラスを作って LOAD_FILTERS で指定する

これがニッチでマニアックで有用性低いのですが,個人的には面白いと思うやりかたです。長くなってきたので残念ですが次回に続きます。