2014年4月にリリースされたClosure Templates 2.4では、いくつかの面白い新機能が追加されています。
今回はテンプレートのパラメータの型チェック機能について紹介します。
Closure Templatesの基本的な使い方についてはこちらをご覧ください。
{@param}
今までのClosure Templatesでは、テンプレート内で使用するパラメータをコメントに記述する必要がありました。
/**
* @param name
*/
{template .render}
Hello, {$name}!
{/template}
Closure Templates 2.4では、コメントではなくテンプレートの記法としてパラメータを記述することができるようになりました。(このときコメントの@param
は不要です)
そしてパラメータ名の後ろに型を指定することができます。
/**
*/
{template .render}
{@param name: string}
Hello, {$name}!
{/template}
指定できる型としては、stringやintなどのプリミティブ型をはじめとして list, map, union, recordなどがあります。
詳しくは公式ドキュメントをご覧ください。
型を指定すると、テンプレートファイルのコンパイル時と、レンダリングの実行時に型のチェックがおこなわれるようになります。
それぞれどのようなチェックがおこなわれるのかみてみましょう。
コンパイル時の型チェック
これまでのClosure Templatesでは、テンプレート内で使用しているパラメータをコメントに書いていなかったり、逆にコメントに書いてあるパラメータがテンプレート内で使われていないと、テンプレートファイルのコンパイル時にエラーが発生しました。
Closure Templates 2.4では、さらに型が一致しているかどうかのチェックもコンパイル時におこなってくれるようになりました。
たとえば、以下のように.parent
でstring
型のname
という変数を、.child
のint
型のパラメータに渡すようなテンプレートを書いてみます。
{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
型のパラメータの存在しないプロパティにアクセスしようとした場合もコンパイルエラーになります。
{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
型に対して数値演算しようとしてもコンパイルエラーにはならず、実行時エラーになります。ここはもう少し頑張って欲しいところですね。
{namespace example.templates.operate}
/**
*/
{template .render}
{@param x: string}
{@param y: int}
// コンパイルエラーにならず、実行時エラーになる
x * y = {{$x * $y}}
{/template}
実行時の型チェック
続いて実行時の型チェックの挙動についてみてみましょう。
まずは、次のようにstring
型のパラメータを持つテンプレートを定義します。
{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にもアップしてあります。