Perl製の小悪魔テンプレートエンジン「Text::PSTemplate」

 

小悪魔はうそです。Perl製のテンプレートエンジンを再発明しました。「Text::PSTemplate」です。

ひたすら変数や関数を書き込むのがメインのテンプレートエンジンです。ore_blog_ore_format_list1(category => 'fuck')みたいなアプリ固有の関数を作って、制御構造はそっちでやるのが手っ取り早いと思ってます。とはいえ、コアプラグインってものがあって、if文、each文、switch文、if_in_array文などの制御構文、ファイルのinclude、Django風テンプレート継承などの機能も使えます。あと、PHPのテンプレートエンジンDwooの機能を少しだけ移植してみたサンプルプラグインもあります。

PurePerlで依存モジュールもたぶんClass::C3くらいです依存モジュール特になし。少なくともPerl5.8.8以降では動きます。5年前から使ってますがアルファバージョンです。APIは変更するかもしれません。POD書きかけ。

以下、テンプレートの書式。

Masonっぽいタグが基本なので、エディタのMasonモードで開くといい感じにハイライトしてくれます。なお、デリミタは変更可能です。

<% ... %>

変数。

<% $var %>

関数。

<% html_escape($var) %>

関数の引数はPerlのまんまです。プラグインの設計次第で配列やファットカンマもいけます。

<% your_func($var, 'something') %>
<% your_func(name1 => $var, name2 => 'something') %>

関数は入れ子にできます。内側には&が必要。

<% your_func(&your_func($var)) %>

if文。関数はブロック内でも使え、外側のスコープの変数は継承され、内側から参照できます。

<% if_equals($var, 1)<<THEN,ELSE %>
    <% $var %> is 1.
<% THEN %>
    <% your_func($var2) %>
<% ELSE %>

構文と言っても、中身は単なる関数です。関数内でタグに後続するブロックを取得するAPIがあるので、それを使用すれば何となく制御構文っぽい感じに見えます。ちなみにブロックの名前は処理内容には無関係で、出現順だけが意味を持ちます。今のところ。

<% your_control($var)<<FOO,BAR %>
    block argument1
<% FOO %>
    block argument2
<% BAR %>

ファイル挿入。includeは入れ子にでき、例によって変数は継承されます。

<% include('path/to/file.txt') %>

テンプレート内に書かれたパス名はデフォルトではそのままPerlのopenに渡されますが、ファイル名の整形のためのコールバックをロジック側で指定することができるので、例えば、常に現在のテンプレートからの相対パスで指定できるようにしたり、基底ディレクトリを指定したり、.htmlは省略可にしたり、予めファイルの有無をチェックしたり、などできます。

テンプレート継承構文。Djangoのドキュメントを真似た例です。

こちらがbase.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <link rel="stylesheet" href="style.css" />
    <title><% placeholder('title')<<DEFAULT %>My amazing site<% DEFAULT %></title>
</head>

<body>
    <div id="sidebar">
        <% placeholder('sidebar')<<DEFAULT %>
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
        <% DEFAULT %>
    </div>

    <div id="content">
        <% placeholder('content')<<DEFAULT %><% DEFAULT %>
    </div>
</body>
</html>

extends構文で継承します。

<% extends('base.html')<<EXTENDS %>
    <% block('title')<<BLOCK %>My amazing blog<% BLOCK %>
    <% block('content')<<BLOCK %>
    <% each($blog_entries, 'entry')<<ENTRIES %>
        <h2><% $entry->{title} %></h2>
        <p><% $entry->{body} %></p>
    <% ENTRIES %>
    <% BLOCK %>
<% EXTENDS %>

下記はif_equals文を含むプラグインの実装例です。引数とブロック指定の2ウェイのインターフェースです。

package SomeModule;
use strict;
use warnings;
use base qw(Text::PSTemplate::PluginBase);
use Text::PSTemplate;

    sub if_equals : TplExport {

        my ($self, $target, $value, $then, $else) = @_;

        my $tpl = Text::PSTemplate->new;

        if ($target eq $value) {
            if ($then) {
                return $then;
            } elsif (my $inline = Text::PSTemplate::inline_data(0)) {
                return $tpl->parse($inline);
            }
        } else {
            if ($else) {
                return $else;
            } elsif (my $inline = Text::PSTemplate::inline_data(1)) {
                return $tpl->parse($inline);
            }
        }
        return;
    }

PluginBaseを継承するとTplExportアトリビュートを指定できるようになります。TplExportなサブルーチンはテンプレート関数と一対一に対応します。if文などの制御構文も実際はサブルーチンなので同じです。また、PluginBaseは同梱のClass::FileCacheable::Liteというクラスを継承していて、関数毎にファイルキャッシュをすることもできます。db_record_listなんて関数を作ったらFileCacheableアトリビュートを付与するとよいです。

このプラグインは下記のようにアクティベートできます。

use Text::PSTemplate::Plugable;
use SomePlugin; # 必要なくなった

my $tpl = Text::PSTemplate::Plugable->new;
$tpl->plug('SomePlugin',''); # 第二引数で名前空間を指定できます
my $parsed = $tpl->parse_file('path/to/file');

基底クラスのText::PSTemplateを継承したPlugableがプラグイン機能を拡張した使いやすいクラスなので、通常これを使います。

Perl製の小悪魔テンプレートエンジン「Text::PSTemplate」」への2件のフィードバック

  1. ピンバック: Mojoliciousにウェブ制作をデプロイする- jamadam weblog2

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です