Help us understand the problem. What is going on with this article?

D言語で使えるテンプレートエンジン

More than 5 years have passed since last update.

D言語 Advent Calendar 2012の7日目の記事です.自分で実装しておきながら日本語で紹介した記憶もないので,これを気に現状のテンプレートエンジン周りについて書いておきます.

D言語は言語機能としてevalなどを現状提供していないのもあり,テンプレートエンジン界隈は盛んではありません.なので数が少ないです.
今の所存在しているアプローチは以下の4つです

  • logic-lessで値を埋め込むやつ (mustache-d)
  • D言語のコードにしてしまう (diet, 新jade)
  • dmdscriptなど外部の処理系を呼び出す (旧jade)
  • 手で頑張る (web.dなど.そもそもテンプレートエンジンではないが…)

上から見ていきます.

mustache-d

俺が書いてるやつです.mustacheはD言語特有のものではなくて,有名なテンプレートフォーマットです.サイトにもたくさんの言語での実装が載っています.

使い方

READMEにも載ってますが

  • Variables: 値の埋め込み
  • Sections: リストの列挙や分岐
  • Partials: 別ファイルの読み込み
  • Comments: コメント

が使えます.細かく見ると色々書くことが増えるので,必要そうなのを見ていきます.以下のは例として同梱しているbasic.mustacheです:

Hello {{name}}
You have just won ${{value}}!
{{#in_ca}}
Well, ${{taxed_value}}, after taxes.
{{/in_ca}}

{{name}}が値の埋め込みで,nameというキーに対応する値が埋め込まれます.{{#in_ca}}がセクションの中の一つ条件分岐で,in_ca に値があれば{{/in_ca}}までが処理されます.

これに対応するD言語のコードは以下になります.Contextという連想配列っぽいものに値をセットしてレンダリングします:

// string/dstringに対応しているので,自分の使いたい型を指定する.wstringはちょっとPhobosがバギーなので今は未サポート
alias MustacheEngine!(string) Mustache;

Mustache mustache;
auto context = new Mustache.Context; // これに値を入れる

context["name"] = "Chris";
context["value"] = 10000;
context["taxed_value"] = 10000 - (10000 * 0.4);
context.useSection("in_ca"); // useSectionを使うことで条件分岐をする

mustache.render("basic", context)); // renderString("Hello {{name}}", context)とかも出来ます

セクションというのがmustacheでの肝になっていて,キーに対応する値のタイプによって,リストの列挙,条件分岐,コールバック呼び出し,をそれぞれ行います.

例えば,他に同梱しているprojects.mustacheの例では,リストの列挙は以下のようになってます.

{{#projects}}
  <a href="{{url}}" class="block">
    <h2> {{name}} </h2>
    <p> {{description}} </p>
  </a>
{{/projects}}
Mustache mustache;
auto context = new Mustache.Context;

foreach (ref project; projects) {
    auto sub = context.addSubContext("projects"); // リストを列挙するには新たにコンテキストを追加する
    sub["name"]        = project.name;
    sub["url"]         = project.url;
    sub["description"] = project.description;
}

mustache-dでは基本機能は一通り実装してあるので,もう少し知りたい方はDDocやunittestを参照してみてください(Webに上げないと…).フォーマットに関してはmustache本家にドキュメントがあります.

1ファイルでサクッと使えるからか,メールのテンプレート作成など,ちょくちょくユーザがいるようです.

diet

vibe.dが提供しているjadeシンタックスを持つテンプレートエンジンです.他のvibe.dのモジュールに依存しているので,mustacheのように単独で使える状態にはなってません.

dietの特徴は,アプリケーションのコンパイル時に,テンプレートファイルも一緒にコンパイルして,D言語のコードに変換してしまう所です.そのため,実際にレンダリングする時にパースなどの処理が発生せず,またD言語のコードになっているので,mustacheのContextのような中間オブジェクトが必要になりません.

良い例が見つからなかったので,vibe.dのサンプルの中のエラー出力のを引用します.

以下はerror.dtの内容になります:

extends layout

block title
        - auto title = "HTTP error " ~ to!string(error.code);

block body
        p An error has occured. We are really sorry about that!
        p Error description: #{error.message}

これに対するD言語のコードは以下のようになります.render自体はHTTPサーバ側にあるコードで,実質はdietのコードではないんですが,中ではdietのparseDietFile呼んでいるだけです.

void showError(HttpServerRequest req, HttpServerResponse res, HttpServerErrorInfo error)
{
        res.render!("error.dt", req, error);
}

この例を見ると分かるのは,auto titleto!string(error.code)のようにD言語のコードがjadeのコードブロックに直接掛けるのと,renderのテンプレート引数に使われているerrorという変数を,直接テンプレートファイルの中で使えるという所です(templateのaliasパラメータは強力ですね).

基本dietはこんな感じです.mustacheと違ってそもそもD言語のコードが掛けるので,jadeの構文を覚えてしまえば,後はかなり自由に書けるようになってます.実際,static if で分岐している例や,foreachを使っている例も普通にあります.
正直dietだけを別途公開して欲しい所です…

その他

使ったことないやつです.

jade

これは名前の通り,dietと同じjadeのD言語実装ですが,これもoakという謎ライブラリに依存してます.
最初google codeで公開されてたやつはdmdscriptかV8が必要で,今のgithubのもpcreが必要だったりと面倒なので試してないです.後なんかdmdへのパッチみたいなのも同梱しているので,ちょっと大がかりかなと.
dietがあるので,今では正直立ち位置がよく分からんという感じです.

serenity

これ自身はWebフレームワークなんですが,ビューの所にHTMLを出力するクラスみたいなのがあります.DOMベースで,マニュアルでHTMLを生成する感じなので,テンプレートエンジンとは少し違いますね…

misc-stuff-including-D-programming-language-web-stuff

Adamがたくさん公開しているWeb向けモジュール群です.serenityと似たような感じでDOMベースで書いたり,html.dでJSとかCSS辺りも操作出来ますが,これもテンプレートエンジンではないですね…
Adamのサイトはここにあるweb.dとかを使って構築されているらしいですが,使いやすさはよく分からんです.

まとめ

現状俺の知る限り,単独のテンプレートエンジンはmustache-dのみで,他のは何かしらのフレームワークに依存しています.
個人的には本当に必要になった場合には仮想マシンベースのテンプレートエンジンを書きたいと思ってるんですが,まぁ現状mustache-dで困ってないので当分先になりそうです.

次,8日目はまた@ueshitaさんです!

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away