テンプレートエンジンを作ろう!
テンプレートエンジンとは何か
テンプレートエンジンとはデータとテンプレートを受け取って組み合わせたものを出力するライブラリ
最近だとMustacheとかHoganとかHandlebarsとかUnderscoreとかが使われることが多い
それ以外にも簡単なので自作されることも
(ぶっちゃけこれでもいい)
function template (template, param) {
return template.replace(/{{(.+)}}/g, function (all, name) {
return param[name] || '';
});
}
「じゃあなんで作るの?」
「じゃあなんで作るの?」
- 簡単な言語実装ができる
- TDDと相性がいい
- 文字列処理の練習になる
簡単な言語実装ができる
簡単な言語実装ができる
- テンプレートとはいえロジックが入るなら中はある種のプログラム
- ちゃんとしたプログラムを作るのは大変だけど、テンプレートエンジンなら簡単だし使い道もある
(「その言語どこで使うの?問題」が少ない)
TDDと相性がいい
TDDと相性がいい
- テンプレートエンジンは入力と出力が明確化しやすい(テンプレート文字列と置換え用変数をもらって組み合わせた結果を返す)
- 処理が基本的に同期処理なのでテストしやすい
- どういう機能が必要か先読みがしやすいので、先にテストを書いてからコードを書きやすい(UnitTestではなくTDDを行いやすい)
文字列処理の練習になる
文字列処理の練習になる
- ツールとして使うなら文字列処理はできたほうがいい
(csvの中身解析してhtmlに書きだすとか)
- テンプレートエンジンは文字列処理が中心になるので練習にも
作り方
基本的な型は「テンプレート文字列と置き換え用objectを受け取って結果を返す」
(テンプレート文字列をコード上にどう保持するかという問題もあるけど)
ざっくりこんな感じ
function template (tmpl, param) {
var result = '';
while (true) {
// tmpl === 'aaa{{bbb}}ccc'
var match = tmpl.match(/([\s\S]+?)\{\{([\s\S]*?)\}\}([\s\S]+)/);
if (!match) return result;
// result === 'aaa'
result += match[1];
// element === 'bbb'
var element = match[2];
// tmpl === 'ccc'
tmpl = match[3];
}
return result;
}
あとはテンプレートの仕様をどうするかで難易度は変わる
仕様例
- objectの入れ子へどうアクセスするか
({ "hoge" : { "huga" : "foo" } }へどうアクセスする?)
- エスケープはどうするか
(基本的に自動エスケープがおすすめだけど、"エスケープしない"指定はどうする?)
仕様例
- フィルタはどうするか
(1000 -> 1,000的なもの。複数指定したい場合どうする?エスケープの一種にする方法も)
- ループをどう表現するか
({ "hoge" : [1, 2, 3] }に対応するか?)
- デバッグはどうするか
(テンプレート内にエラーがあった場合にどう出力するか)
仕様例
- {{}}等の区切り文字は変更できるようにするか
(ブロック周りも考えると結構指定項目多い)
- 変数参照とブロックの構文はどうするか
(ループや入れ子や条件分岐をどうするか)
- 条件分岐の変数比較はどうするか
(変数とリテラルの比較と変数同士の比較をどう区別するか)
仕様例
- 広域変数はどう管理するか
(ローカル変数と広域変数で参照方法を分けるか?)
- テンプレート上で変数設定は行うか
(便利ではあるがかなりロジックが入ることになる)
「実際実用になるか」
既存のテンプレートエンジンでいいものがない場合は自作でも結構使える
テンプレートエンジンはテストがそのままドキュメントになるので後で混乱することは少ない
ただ、最近はわりといいのが出てきたのでそっちを使うほうがいいかも
ご清聴ありがとうございました