口ひげ入門

1.概要

この記事では、https://mustache.github.io/[Mustache]テンプレートに焦点を当て、動的なHTMLコンテンツを作成するためにそのhttps://github.com/spullara/mustache.java[JavaScript API]の1つを使用します。

Moustacheは、HTML、設定ファイルなどの動的コンテンツを作成するための** 論理的なテンプレートエンジンです。

2前書き

簡単に言えば、このエンジンはif-else文やforループをサポートする構文を持っていないので、 logicless として分類されます。

Moustacheテンプレートは \ {\ {}} で囲まれたタグ名で構成され(これは口ひげに似ているため、名前となります)、テンプレートのデータを含むモデルオブジェクトによって支えられています。

3 Mavenの依存関係

テンプレートのコンパイルと実行は、クライアント側とサーバー側の両方の複数の言語でサポートされています。

Javaからテンプレートを処理できるようにするために、Mavenの依存関係として追加できるJavaライブラリを利用します。

Java 8:

<dependency>
    <groupId>com.github.spullara.mustache.java</groupId>
    <artifactId>compiler</artifactId>
    <version>0.9.4</version>
</dependency>

Java 6/7:

<dependency>
    <groupId>com.github.spullara.mustache.java</groupId>
    <artifactId>compiler</artifactId>
    <version>0.8.18</version>
</dependency>

ライブラリの最新版はhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22com.github.spullara.mustache.java%22%20AND%20a%で確認できます。 3A%22コンパイラ%22[Central Mavenリポジトリ]。

4使用法

以下の方法を示す簡単なシナリオを見てみましょう。

  1. 簡単なテンプレートを書く

  2. Java APIを使用してテンプレートをコンパイルする

  3. 必要なデータを入力して実行してください

4.1. 簡単な口ひげのテンプレート

ToDoタスクの詳細を表示するための簡単なテンプレートを作成します。

<h2>{{title}}</h2>
<small>Created on {{createdOn}}</small>
<p>{{text}}</p>

上記のテンプレートでは、中括弧(\ {\ {}})内のフィールドは次のようになります。

  • Javaクラスのメソッドとプロパティ

  • Map オブジェクトのキー

4.2. 口ひげテンプレートのコンパイル

以下のようにテンプレートをコンパイルすることができます。

MustacheFactory mf = new DefaultMustacheFactory();
Mustache m = mf.compile("todo.mustache");

MustacheFactory はクラスパス内の指定されたテンプレートを検索します。この例では、 todo.mustache src/main/resources の下に配置します。

4.3. 口ひげテンプレートの実行

テンプレートに提供されるデータは Todo クラスのインスタンスになります。

public class Todo {
    private String title;
    private String text;
    private boolean done;
    private Date createdOn;
    private Date completedOn;

   //constructors, getters and setters
}

コンパイルしたテンプレートを実行して、以下のようにHTMLを取得できます。

Todo todo = new Todo("Todo 1", "Description");
StringWriter writer = new StringWriter();
m.execute(writer, todo).flush();
String html = writer.toString();

5口ひげのセクションと反復

それでは、ToDoを一覧表示する方法を見てみましょう。リストデータを反復処理するために、Mustacheセクションを利用します。

セクションは、現在のコンテキスト内のキーの値に応じて1回以上繰り返されるコードブロックです。

それは次のようになります。

{{#todo}}
<!-- Other code -->
{{/todo}}

セクションはポンド(#)で始まりスラッシュ(/)で終わります。各記号の後には、セクションのレンダリングの基礎として使用される値を持つキーが続きます。

以下は、キーの値に応じて発生する可能性があるシナリオです。

5.1. 空でないリストまたは偽ではない値を持つセクション

セクションを使用するテンプレート todo-section.mustache を作成しましょう。

{{#todo}}
<h2>{{title}}</h2>
<small>Created on {{createdOn}}</small>
<p>{{text}}</p>
{{/todo}}

このテンプレートを実際に見てみましょう。

@Test
public void givenTodoObject__whenGetHtml__thenSuccess()
  throws IOException {

    Todo todo = new Todo("Todo 1", "Todo description");
    Mustache m = MustacheUtil.getMustacheFactory()
      .compile("todo.mustache");
    Map<String, Object> context = new HashMap<>();
    context.put("todo", todo);

    String expected = "<h2>Todo 1</h2>";
    assertThat(executeTemplate(m, todo)).contains(expected);
}

ToDoを一覧表示するための別のテンプレート todos.mustache を作成しましょう。

{{#todos}}
<h2>{{title}}</h2>
{{/todos}}

そしてそれを使って仕事のリストを作成します。

@Test
public void givenTodoList__whenGetHtml__thenSuccess()
  throws IOException {

    Mustache m = MustacheUtil.getMustacheFactory()
      .compile("todos.mustache");

    List<Todo> todos = Arrays.asList(
      new Todo("Todo 1", "Todo description"),
      new Todo("Todo 2", "Todo description another"),
      new Todo("Todo 3", "Todo description another")
    );
    Map<String, Object> context = new HashMap<>();
    context.put("todos", todos);

    assertThat(executeTemplate(m, context))
      .contains("<h2>Todo 1</h2>")
      .contains("<h2>Todo 2</h2>")
      .contains("<h2>Todo 3</h2>");
}

5.2. 空の List または False または Null 値を持つセクション

todo-section.mustache null 値でテストしましょう。

@Test
public void givenNullTodoObject__whenGetHtml__thenEmptyHtml()
  throws IOException {
    Mustache m = MustacheUtil.getMustacheFactory()
      .compile("todo-section.mustache");
    Map<String, Object> context = new HashMap<>();
    assertThat(executeTemplate(m, context)).isEmpty();
}

同様に、空のリストで todos.mustache をテストします。

@Test
public void givenEmptyList__whenGetHtml__thenEmptyHtml()
  throws IOException {
    Mustache m = MustacheUtil.getMustacheFactory()
      .compile("todos.mustache");

    Map<String, Object> context = new HashMap<>();
    assertThat(executeTemplate(m, context)).isEmpty();;
}

6. 反転セクション

  • インバーテッドセクションは、キーが存在しない** 、 false null の値、または空のリストのいずれかに基づいて一度だけレンダリングされるセクションです。

言い換えれば、これらはセクションがレンダリングされないときにレンダリングされます。

以下に示すように、これらはキャレット(^)で始まり、スラッシュ(/)で終わります。

{{#todos}}
<h2>{{title}}</h2>
{{/todos}}
{{^todos}}
<p>No todos!</p>
{{/todos}}

空のリストを指定した場合の上記のテンプレート:

@Test
public void givenEmptyList__whenGetHtmlUsingInvertedSection__thenHtml()
  throws IOException {

    Mustache m = MustacheUtil.getMustacheFactory()
      .compile("todos-inverted-section.mustache");

    Map<String, Object> context = new HashMap<>();
    assertThat(executeTemplate(m, context).trim())
      .isEqualTo("<p>No todos!</p>");
}

7. ラムダ

口ひげセクションのキーの 値は、関数またはラムダ式 にすることができます。そのような場合、完全なラムダ式は、セクション内のテキストをラムダ式へのパラメータとして渡すことによって呼び出されます。

テンプレート todos-lambda.mustache を見てみましょう。

{{#todos}}
<h2>{{title}}{{#handleDone}}{{doneSince}}{{/handleDone}}</h2>
{{/todos}}

handleDone キーは、次に示すようにJava 8のラムダ式に解決されます。

public Function<Object, Object> handleDone() {
    return (obj) -> done ?
      String.format("<small>Done %s minutes ago<small>", obj) : "";
}

上記のテンプレートを実行して生成されたHTMLは次のとおりです。

<h2>Todo 1</h2>
<h2>Todo 2</h2>
<h2>Todo 3<small>Done 5 minutes ago<small></h2>

8結論

この入門記事では、セクション、反転セクション、およびラムダを使用して口ひげのテンプレートを作成する方法について説明しました。そして、関連データを提供することによって、Java APIを使用してテンプレートをコンパイルして実行しました。

以下のような、Moustacheにはもう少し高度な機能があります。

  • 同時実行になる値としてcallableを提供する

評価 ** コレクションの最初、最後、インデックスを取得するために DecoratedCollection を使う

要素 ** 与えられたテキストとテンプレートにデータを与える invert API

そして、いつものように、この完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/mustache[over Github]で利用可能です。