2012年11月29日木曜日

テンプレート・エンジン {{ mustache }} を使ってみる

{{ mustache }} というテンプレートエンジンを知っていますか?
http://mustache.github.com/

Google Trendで、Javaで有名なテンプレート・エンジンである Apache Velocity と比較したところ、最近では人気度が上回っているようです。



mustache はHTMLやコンフィグファイル・ソースコードを生成するためのシンプルなテンプレートエンジンで、以下のようないろんな言語をサポートしているようです。
Ruby, JavaScript, Python, Erlang, PHP, Perl, Objective-C, Java, .NET, Android, C++, Go, Lua, ooc, ActionScript, ColdFusion, Scala, Clojure, Fantom, CoffeeScript, D, node.js.

ちなみに、「mustache」とは「口ひげ」という意味で、「{」をタグとして利用したテンプレートということから、「{」を横にしたらひげに見えるから「mustache」と名前が付いたようです。



変数定義
早速どういったもの見てみましょう。以下はマニュアルに載っていたサンプルです。

・テンプレート
Hello {{name}}
You have just won ${{value}}!
{{#in_ca}}
Well, ${{taxed_value}}, after taxes.
{{/in_ca}}

・上記のテンプレートに渡すデータ(hash)をJSONもしくはYAMLで定義します。
{
    "name": "Chris",
    "value": 10000,
    "taxed_value": 10000 - (10000 * 0.4),
    "in_ca": true
}

・結果は以下のように表示されます。
Hello Chris
You have just won $10000!
Well, $6000.0, after taxes.

このテンプレートの「{{」と「}}」で囲まれたタグが、渡したデータ(hash)により変更され、結果として出力されます。上記の例では、{{name}}というタグ部分が、データの"name"の値「Chris」に変更されます。同様に{{value}}タグは、"value"の10000になります。


ちなみに、デフォルトで結果はエスケープされます。(例:「<」や「>」は、「&lt;」や「&gt;」に。)これをエスケープしないためには、ひげを3つにするか(例.{{{tag}}})、「{{&」と「}}」で囲みます。

・テンプレート
{{name}}
{{age}}
{{company}}
{{{company}}}

・データ(hash)
{
  "name": "Chris",
  "company": "<b>GitHub</b>"
}

・結果
Chris
&lt;b&gt;GitHub&lt;/b&gt;
<b>GitHub</b><


条件式やループ
mustacheが、「logic-less templates」というように呼ばれている意味は、どうやらif文やfor/while文などのステートメントが含まれないことからロジックレスという名称が付いているようです。ただし、テンプレート・エンジンでステートメント的なものは必要なので、条件文やループなどがどのように表現されているか説明しますと、「{{#」と「}}」で囲むことで実現できるようです。(ちなみに、ブロックの閉じるタグは「{{/」と「}}」で囲む。)

上記の例ですと、{{#in_ca}}と{{/in_ca}}にあたります。この場合、データ"in_ca"はboolean型なので、if文のように動きます。"in_ca"がtrueなら「Well, ....」が表示され、falseならこの部分が表示されません。(もしくは値が無い場合も表示されません。)

では、ループはというと、これも同様に「{{#」と「}}」で囲みます。ただし、この囲まれたタグの値の型がリストの場合に繰り返されます。以下はサンプルですが、"repo"の値がリストですので、以下のようにリスト分、繰り返されます。

・テンプレート
{{#repo}}
  <b>{{name}}</b>
{{/repo}}

・データ(hash)
{
  "repo": [
    { "name": "resque" },
    { "name": "hub" },
    { "name": "rip" },
  ]
}

・結果
<b>resque</b>
<b>hub</b>
<b>rip</b>

さらに、関数を渡すこともできるようです。これは面白いですね。

・テンプレート
{{#wrapped}}
  {{name}} is awesome.
{{/wrapped}}

・データ(hash)
{
  "name": "Willy",
  "wrapped": function() {
    return function(text) {
      return "<b>" + render(text) + "</b>"
    }
  }
}

・結果
<b>Willy is awesome.</b>

このタグがbooleanでもなく、リストでもない場合に、tagに相当するキー値が存在すれば、以下のようにtrueと同様の動きをするみたいです。

・テンプレート
{{#person?}}
  Hi {{name}}!
{{/person?}}

・データ(hash)
{
  "person?": { "name": "Jon" }
}

・結果
Hi Jon!

また、if文の逆(not if)は以下のように「{{^」と「}}」で囲んで書きます。

・テンプレート
{{#repo}}
  <b>{{name}}</b>
{{/repo}}
{{^repo}}
  No repos
{{/repo}}
Hash:

・データ(hash)
{
  "repo": []
}

・結果
No repos

その他のタグ
あと、コメントは「{{!」と「}}」で囲みます。

別のテンプレートファイルとして定義して読み込みたい場合は、例えばother.mustacheファイルを読み込みたいのであれば、{{>other}}のように「{{>」と「}}」で囲みます。

最後に、「{{」と「}}」以外でテンプレートを作りたい場合、以下のようにテンプレート中で記載することで変更ができます。(この例は、「{{」を「<%」に、「}}」を「%>」に変更)
{{=<% %>=}}

元に戻すには、
<%={{ }}=%>

これをmustache.jsで使うには以下のようなコードで動きます。
var template = 'I'm {{name}}.';
var v = Mustache.to_html(
          template,
          {
            name:"hitocie"
          }
);
console(v);

うーん、結構良くできていますし、Apache Velocityなどと比べると非常にシンプルですね。

今回、ほぼマニュアルの翻訳的な感じになってしまいましたが、ある程度の機能は紹介できたかと思います・・・。

ちなみに、mustacheを拡張したもので、Twitterからオープンソースとして提供されているhogan.jsというものがあります。これは、mustacheの記法で書いたテンプレートをAOT(Ahead Of Time)コンパイルして、JavaScriptに変換するというもので、レンダリングのたびにmustache記法のテンプレートを解析する必要がなく高速に動作するため、WebシステムでJSPなどのように利用できます。


0 件のコメント:

コメントを投稿