サンプルコードは、以下のようになります 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} }}} 上記を実行した結果が以下となります (ただし、改行を調整してあります) {{{ 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関数は標準では結果を文字列で返すが、 出力ポートを与えると、直接そのポートに結果を書き出す。