2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Closure Templates 2.4の新機能 - パラメータの型チェック

Posted at

2014年4月にリリースされたClosure Templates 2.4では、いくつかの面白い新機能が追加されています。
今回はテンプレートのパラメータの型チェック機能について紹介します。

Closure Templatesの基本的な使い方についてはこちらをご覧ください。

{@param}

今までのClosure Templatesでは、テンプレート内で使用するパラメータをコメントに記述する必要がありました。

hello.soy
/**
 * @param name
 */
{template .render}
  Hello, {$name}!
{/template}

Closure Templates 2.4では、コメントではなくテンプレートの記法としてパラメータを記述することができるようになりました。(このときコメントの@paramは不要です)
そしてパラメータ名の後ろに型を指定することができます。

hello.soy
/**
 */
{template .render}
  {@param name: string}
  Hello, {$name}!
{/template}

指定できる型としては、stringやintなどのプリミティブ型をはじめとして list, map, union, recordなどがあります。
詳しくは公式ドキュメントをご覧ください。

型を指定すると、テンプレートファイルのコンパイル時と、レンダリングの実行時に型のチェックがおこなわれるようになります。
それぞれどのようなチェックがおこなわれるのかみてみましょう。

コンパイル時の型チェック

これまでのClosure Templatesでは、テンプレート内で使用しているパラメータをコメントに書いていなかったり、逆にコメントに書いてあるパラメータがテンプレート内で使われていないと、テンプレートファイルのコンパイル時にエラーが発生しました。
Closure Templates 2.4では、さらに型が一致しているかどうかのチェックもコンパイル時におこなってくれるようになりました。

たとえば、以下のように.parentstring型のnameという変数を、.childint型のパラメータに渡すようなテンプレートを書いてみます。

hello.soy
{namespace example.templates.hello}

/**
 * parent template
 */
{template .parent}
  {@param name: string}
  {call .child}
    {param name: $name /}
  {/call}
{/template}

/**
 * child template
 */
{template .child}
  {@param name: int}
  Hello, {$name}!
{/template}

このテンプレートファイルを次のようにコンパイルします。

SoyTofu tofu = SoyFileSet.builder()
    .add(new File("hello.soy"))
    .build()
    .compileToTofu();

すると型が一致していないというエラーになります。いい感じですね。

com.google.template.soy.base.SoySyntaxException: In file hello.soy:8, template example.templates.hello.parent: Argument type mismatch: cannot call template parameter 'name' with type 'int' with value of type 'string'

また、次のテンプレートファイルのようにint型のパラメータのプロパティにアクセスしようとしたり、record型のパラメータの存在しないプロパティにアクセスしようとした場合もコンパイルエラーになります。

property.soy
{namespace example.templates.property}

/**
 */
{template .render}
  {@param x: int}
  {@param y: [a: int, b:int]}

  // コンパイルエラー
  {{$x.a}}

  // OK
  {{$y.a + $y.b}}

  // コンパイルエラー
  {{$y.c}}
{/template}

でも、次のようにstring型に対して数値演算しようとしてもコンパイルエラーにはならず、実行時エラーになります。ここはもう少し頑張って欲しいところですね。

operate.soy
{namespace example.templates.operate}

/**
 */
{template .render}
  {@param x: string}
  {@param y: int}

  // コンパイルエラーにならず、実行時エラーになる
  x * y = {{$x * $y}}

{/template}

実行時の型チェック

続いて実行時の型チェックの挙動についてみてみましょう。

まずは、次のようにstring型のパラメータを持つテンプレートを定義します。

hello.soy
{namespace example.templates.hello}

/**
 * hello template
 */
{template .render}
  {@param name: string}
  Hello, {$name}!
{/template}

このテンプレートのnameパラメータに文字列を与えてレンダリングしてみます。

SoyMapData data = new SoyMapData("name", "World");
String output = tofu.newRenderer("example.templates.hello.render")
    .setData(data)
    .render();

これは問題なくレンダリングされます。

次にnameパラメータに数値を与えてレンダリングしてみます。

SoyMapData data = new SoyMapData("name", 1234);
String output = tofu.newRenderer("example.templates.hello.render")
    .setData(data)
    .render();

このコードを実行すると次のような例外が発生してレンダリングに失敗します。
ちなみにJavaScriptで実行した場合も、assertにより例外が発生します。

com.google.template.soy.tofu.SoyTofuException: Parameter type mismatch: attempt to bind value '1234' to parameter 'name' which has declared type 'string'.
	at example.templates.hello.render(hello.soy:5)

まとめ

テンプレートのパラメータの型チェック機能を利用すれば、テンプレートファイルの不具合に早く気づくことができるようになるでしょう。
積極的に利用していきたい機能です。

なお、今回利用したサンプルコードはGitHubにもアップしてあります。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?