サンプルコードは、以下のようになります
example.scm
{{{
(use heieiei)
(use text.html-lite)
(display
(template
(
(title "Test Template")
(items (list 1 2 3 4 5 6))
)
(call-with-input-file "sample.tmpl" port->string)
))
}}}
sample.tmpl
{{{
#import(text.html-lite)
${title | html-escape-string}
#*
以下はループです
そして、これはコメントです
*#
#foreach($item in $items)
#if( $item % 2 == 0)
- $item
#else
- $item
#end
#else
- empty!
#end
}}}
上記を実行した結果が以下となります
(ただし、改行を調整してあります)
{{{
Test Template
}}}
機能解説
リテラルは
- 文字列
- 数値
- リスト
- 真偽値
#set($number = 123) ## 整数
#set($number = -20) ## 整数(負数)
#set($number = 0.4) ## 小数
数値はこんな感じで
#set($string1 = '') ##
#set($string2 = "$string1 world") ## worls
#set($string3 = "${string1 | html-escape-string} world") ## <hello> world
ダブルクォートなら、変数展開やフィルタの適用が行われる。
展開されたくない場合は、シングルクォートを利用する。
#set($list1 = [1, 2, 3, 4, 5])
#set($list2 = [1, $list1, 3, [1,2,3,4,5], 5])
リストのネストも可能。
#set( [$v1, $v2, $v3] = $items)
listを多値のように扱う多重代入の例。
$itemsがlistであった場合、上記の記法を用いることで
展開することができる。
もしlistの長さが変数の数より小さかった場合、
足りない要素は#fが代入される。
変数の表示は
$bar
${bar}
のようになる
変数名の後ろが空白や改行、記号なら
上記の2つの表記は同じ意味となる
ブレース(括弧)は以下のような場合で意味を持つ
#set($hello = 'good by ')
1. $helloworld
2. ${hello}world
例1では変数「$helloworld」を表示しようとする
もし変数「$hello」を表示したければ、空白や改行、記号等で「world」との間を区切るか、
括弧を利用することになる
括弧を利用した場合は例2のようになる
上記例1の場合は、対応する変数「$helloworld」が定義されて無いため、
変数名とみなされなかった「$helloworld」の文字がそのまま表示される
未定義の変数の挙動をかえるには以下のような表記がある
$!hello
$!{hello}
この場合、変数「$hello」が未定義であった場合「$!hello」や「$!{hello}」とそのまま表示されることはなく、
その部分には何も表示されなくなる
スロットの参照には . (ドット)を利用する。
$obj.foo
変数 $obj の指すオブジェクトの持つ foo というスロットを参照する。
これは (slot-ref obj 'foo) とほぼ同義となる
$obj.foo.bar
スロットの参照結果が、さらにスロットを持っている場合、それを連鎖的に参照する例。
#if(条件式)
TRUE
#end
#if(条件式1)
条件式1はTRUE
#elsif(条件式2)
条件式2はTRUE
#elsif(条件式3)
条件式3はTRUE
#else
全部FALSE
#end
イテレータ
#foreach($item in $list)
$item
#end
これは内部的にはgauche.collectionを利用していて、
リストでなくとも、iteratorを実装したオブジェクトなら何でも良い。
#foreach($item in $list)
$item
#else
一度も実行され無かった場合
#end
foreachにelse節があった場合、
ループ節が一度も実行されなかった場合、else節が実行される。
多重代入による要素の展開
{{{
(template
(
(items
(list
'(1 "1st" "foo")
'(2 "2nd" "bar")
'(3 "3rd" "baz")
)))
(call-with-input-file "sample.tmpl" port->string)
)
}}}
## sample.tmpl
{{{
#foreach( [$v1, $v2, $v3] in $items)
$v1
$v2
$v3
#end
}}}
もし、$itemsのそれぞれの要素がlistであった場合、
上記のような記法を用いて、展開することができる。
もしlistの長さが変数の数より小さかった場合、
足りない要素は#fが代入される。
#include($filename)
#include('file.txt')
単純にファイルの内容を挿入するだけ。
#parse($filename)
#parse('file.txt')
ファイルの内容をパース、実行した結果を挿入する。
#includeonce('file.txt')
#parseonce('file.txt')
実行時ではなく、解析時に一度だけ挿入を行う。
ファイル名は文字列リテラル(シングルクォート)でなければならない。
パイプ構文
これはVelocityには無い拡張された文法。
パイプ風のフィルタ構文はTemplate ToolKitやSmartyも採用しており、
さして特徴的な機能というわけでもない(文法は少し異なるが)
${var | filter}
変数 $var に対して、 $filter を適用する。
#filter($filter)
String
#end
#filter から #end までの実行結果に $filter を適用した結果を挿入する。
このように書けば、include結果も$filterが適用されたものになる。
#filter($filter)
#include('file.txt')
#end
${var | filter1 | filter2}
複数フィルタを指定すると、左のものから順に適用される。
2番目以降のフィルタには、前回のフィルタの結果が渡される。
#filter($fitler1 | $filter2 | $filter3)
String
#end
マクロ
#macro(NAME $arg1 $arg2)
#set($sum = $arg1 + $arg2)
引数の合計は${sum}です
#end
マクロの仕様は暫定的。
Velocityでは、展開後に引数の評価が行われるが、
こちらの実装では、評価後の値が引数としてわたる。
この仕様なら、マクロというよりサブルーチンのほうが適切かもしれない。
literal から end までの範囲は、
変数展開やディレクティブの実行を行わない。
#literal
$value
#end
以下のように書けば、#end を範囲内に含めることができる。
#literal(EOT)
$value
#end このendは無効
#EOT
#import(text.template.html-filter)
指定したモジュールを読み込み、
対象モジュールからexportされたものを、
テンプレート内から参照可能にする。
コメントは2種類。
## 一行コメント
#*
複数行コメント
*#
現在のところ、複数行コメントのネストには対応していない。
template関数のオプション
:default-filter
変数表示を行う際に、フィルタを与えなかった場合、
標準で適用されるフィルタを与える。
もしブレース構文で変数にフィルタを与えた場合( ${var | filter} )
その変数にdefault-filterのフィルタは適用されない。
:use-counter
foreach内で変数$countに現在のループの回数を入れる。
標準では使われない。
Velocityから拝借した機能。
:port
template関数は標準では結果を文字列で返すが、
出力ポートを与えると、直接そのポートに結果を書き出す。