10 December 2005
This post may be outdated due to it was written on 2005. The links may be broken. The code may be not working anymore. Leave comments if needed.
昨日写了点 TT 内置过滤器(Template builtin Filters),现在有兴趣讲讲自己怎么写一个 filter.

昨日说了 filter 分为两种:一种为静态,一种为动态。二者的区别是静态不接受任何参数,如 html, collapse, trim, ucfirst, lower 等,而动态接受参数,如 format('%0.3f'), indent("> ")
而放置 filter 的地方也分为两种,一种是直接放在代码里,另一种是写为 Template::Plugin::Filter 的子类模块。
我打算先讲直接放在代码里的。

Static Filters

静态过滤器是最简单的。我们用个最简单的 filter 来写个 lower/ucfirst 过滤器。
sub ucf {
   my $text = shift;
   $text = ucfirst lc $text;
   return $text;
}
my $tt = Template->new({
FILTERS => {
'ucf' => \&ucf,
'lcf' => sub { lcfirst uc shift; },
},
});
上面就是静态过滤器的两种形式。一种是 subroutine 子程序的引用,一种是匿名子程序。
无论是哪种子程序都接受一个 shift 过来的字符串,然后返回一个 $string.
注册 filters 使用 FILTERS 参数。而 Catalyst 可以这么写:
package Eplanet::V::TT;

use strict;
use base 'Catalyst::View::TT';

__PACKAGE__->config->{FILTERS} = {
   'ucf' => \&ucf,
   'lcf' => sub { lcfirst uc shift; },
};

而 filter 的应用与内置的是一样的。
[% FILTER ucf %]template is great[% END %]
输出 Template is great
[% | lcf %]template is great[% END %]
输出 tEMPLATE IS GREAT

Dynamic Filters

动态的是可以接受参数的。它的注册方法与静态的略微有点不同:
my $tt = Template->new({
FILTERS => {
'ucf' => \&ucf, # our trusty static filter
'cut' => [ \&cut, 1 ], # our dynamic filter
},
});
第一种是我们所熟悉的静态过滤器,而第二种就是动态过滤器。它传递的一个数组引用且第二个参数为 1.
我们所熟悉的静态过滤器还有种写法:
'ucf' => [ \&ucf, 0 ],
这与 'ucf' => \&ucf, 是一样的。

动态过滤器所定义的子程序大致为这样子的:

sub cut {
my ($context, $len) = @_;
return sub {
my $text = shift;
$text = substr($text, 0, $len);
return $text;
}
}
[% | cut(5) %]template is great[% END %]
输出为 templ
动态过滤器里第一个参数 $context 是 Template::Context 的一个对象,这个涉及到 Template 的内核我也不太懂。
第二个参数 $len 这里就是 5.
它返回的必须是一个程序的引用。跟静态的差不多。不过这个返回的子程序引用是个闭包。

这样我们差不多说清楚了 filter 怎么写了,下面说说怎么写一个模块。

Template::Plugin::Filter

package MyTemplate::Plugin::Filter::Textile;

use strict;
use Template::Plugin::Filter;
use base qw(Template::Plugin::Filter);
use Text::Textile;

sub filter {
   my ($self, $text) = @_;
   $text = Text::Textile::textile($text);
   return $text;
}

1;

这是一个标准的写法:use base qw(Template::Plugin::Filter); see Template::Plugin::Filter
然后覆盖它的 filter 子程序。参数为 my ($self, $text) = @_; 返回字符串。一个静态过滤器。
而注册的写法为:
my $tt2 = Template->new({
PLUGIN_BASE => 'MyTemplate::Plugin::Filter'
PLUGINS => {
Textile => 'MyTemplate::Plugin::Filter::Textile',
},
});
因为 Filter 是 Plugin 的一种,所以我们这里设置的是 PLUGINS.
Catalyst 的 ::V::TT 写法类似:
__PACKAGE__->config->{PLUGIN_BASE} = 'MyTemplate::Plugin::Filter';
__PACKAGE__->config->{PLUGINS} = {
   Textile => 'MyTemplate::Plugin::Filter::Textile',
};
而实际用则这么写:
[% USE Textile %]
[% FILTER $Textile %]this is _like_ *so* *cool*[% END %]
效果为:

this is like so cool

Conclusion

这就是大致上一般的 template toolkit filter 的知识。如有错误请指正。Enjoy!


blog comments powered by Disqus