Catalyst::View::ClearSilver を使いこなす
C言語で書かれた超高速なテンプレートエンジンの ClearSilver ですが、Catalyst 界隈ではあまり使われていないようなので、今回は TT では実現されていることを ClearSilver で実現してみます。
- ウェブアプリケーションの国際化
- リクエストパラメータの取得
事前準備
ClearSilver をインストールしておいてください。Perl バインディングも忘れずにインストールしておきます。
MyApp/lib/MyApp/View/CS.pm
ビューは TT とまったく同じ方法で作れます。
# cpan Catalyst::View::ClearSilver $ cd MyApp/script $ ./myapp_create view CS ClearSilver
MyApp/lib/MyApp/I18N/ja.mo
カタログファイルは po から mo に変換しておきます。
$ cd MyApp/lib/MyApp/I18N $ msgfmt -o ja.mo ja.po
MyApp/lib/MyApp/Controller/Root.pm
- カレントディレクトリを File::chdir で一時的に変更しています(これをしないと include 構文が使えません)
- ウェブアプリケーションの国際化のためにカタログファイルを読み込み、$c->stash->{loc} につっこんでいます
- リクエストパラメータを $c->stash->{req_param} につっこんでいます
package MyApp::Controller::Root; use strict; use warnings; use base 'Catalyst::Controller'; use File::chdir; =head2 read_mo($) read_mo: Subroutine to read and parse the MO file Refer to gettext documentation section 8.3 =cut sub read_mo($) { local ($_, %_); my ($MOfile, $len, $FH, $content, $tmpl); $MOfile = $_[0]; # Avild being stupid return unless -f $MOfile && -r $MOfile; # Read the MO file $len = (stat $MOfile)[7]; open $FH, $MOfile or return; # GNU gettext never fails! ^_*' binmode $FH; defined($_ = read $FH, $content, $len) or return; close $FH or return; # Find the byte order of the MO file creator $_ = substr($content, 0, 4); # Little endian if ($_ eq "\xde\x12\x04\x95") { $tmpl = "V"; # Big endian } elsif ($_ eq "\x95\x04\x12\xde") { $tmpl = "N"; # Wrong magic number. Not a valid MO file. } else { return; } # Check the MO format revision number $_ = unpack $tmpl, substr($content, 4, 4); # There is only one revision now: revision 0. return if $_ > 0; my ($num, $offo, $offt); # Number of strings $num = unpack $tmpl, substr($content, 8, 4); # Offset to the beginning of the original strings $offo = unpack $tmpl, substr($content, 12, 4); # Offset to the beginning of the translated strings $offt = unpack $tmpl, substr($content, 16, 4); %_ = qw(); for ($_ = 0; $_ < $num; $_++) { my ($len, $off, $stro, $strt); # The first word is the length of the string $len = unpack $tmpl, substr($content, $offo+$_*8, 4); # The second word is the offset of the string $off = unpack $tmpl, substr($content, $offo+$_*8+4, 4); # Original string $stro = substr($content, $off, $len); # The first word is the length of the string $len = unpack $tmpl, substr($content, $offt+$_*8, 4); # The second word is the offset of the string $off = unpack $tmpl, substr($content, $offt+$_*8+4, 4); # Translated string $strt = substr($content, $off, $len); # Hash it $_{$stro} = $strt; } return \%_; } =head2 end Attempt to render a view, if needed. =cut sub end : Private { my ( $self, $c ) = @_; local $CWD = '/home/hoge/public_html/MyApp/root'; $c->stash->{loc} = &read_mo($CWD . '/../lib/MyApp/I18N/ja.mo'); $c->stash->{req_param} = $c->request->parameters(); $c->view('CS')->process($c); }
MyApp/root/template/sample.cs
テンプレートはこんな感じになります。
<?cs include:"template/header.cs" ?> <h1>TinyURL <?cs var:loc.New ?></h1> <?cs if:create.error ?> <font color="red"><?cs var:create.message ?></font> <?cs /if ?> <form name="tinyurl" method="post" action="/tinyurl/create"> <table> <tr> <td><?cs var:loc.TinyUrl_id ?></td><td><input type="text" name="id" size="25" value="<?cs var:req_param.id ?>"></td> </tr> <tr> <td><?cs var:loc.TinyUrl_disable ?></td><td><input type="text" name="disable" size="25" value="<?cs var:req_param.disable ?>"></td> </tr> <tr> <td><?cs var:loc.TinyUrl_long_url ?></td><td><input type="text" name="long_url" size="25" value="<?cs var:req_param.long_url ?>"></td> </tr> <tr> <td colspan="2" align="center"><input type="submit" name="btn_create" value="<?cs var:loc.Add ?>"></td> </tr> </table> </form> <?cs include:"template/footer.cs" ?>