Builderというのは、Groovyのとても特徴的な機能だと思います。たとえば、MarkupBuilder。
new MarkupBuilder().root { a( a1:'one' ) { b { mkp.yield( '3 < 5' ) } c( a2:'two', 'blah' ) } }
こんなんを書くと、
<root> <a a1='one'> <b>3 < 5</b> <c a2='two'>blah</c> </a> </root>
こんなのが表示されます。
でこれは何なのか? いったい何が起きているのでしょうか。
いっけん、root,a,b,cというメソッドを呼び出していますが、それらのメソッドはあらかじめ存在しているわけではありません。なのに呼び出している。実行もできている。なぜそんなことが成立するかというと、Groovyが、その「メソッド呼び出し」をメタレベルで検出し、メソッド呼び出し以外の行為をさせるからです。なにをさせるかというと、XMLのようなツリーデータ構造の構築をさせるのです。
つまりこれは詐欺みたいなものです。
何を言ってるかわからねーと思うが、メソッド呼び出しのつもりだったのに、ツリーを構築しちまったッ!!!*1
どんなツリーかというと、メソッド名を要素型(タグ名)に、引数クロージャをタグの内容に、名前引数を属性の指定と解釈するようなXMLのツリーを構築します。
a(...) { }の「{ }」のところが引数のクロージャですね。クロージャ引数として渡されるクロージャは、ツリー構築の過程で実行(call)されるのですが、このクロージャも「メソッド呼びだしのつもりがツリー構築しちまった」という詐欺的条件の元で実行されます。再帰的にcallされていくイメージ。
さて、もう1つだけトピック。
b { mkp.yield( '3 < 5' ) }
の「mkp.yield」とはなんでしょうか(とid:odashinsukeさんが疑問を呈されていました)っていうことですが、これはおまじないということで良いでしょう。XMLの地の文ていうか文字列のコンテンツとして「3<5」を埋め込む指定です。詳しくはこちら。
あとは余談。普通に考えるとここは以下のように書きたいですよね。
b { '3 < 5' }
MarkupBuilderの中に文字列定数があらわれたら、それをコンテンツと扱って欲しいです。欲しいぞう。その方が自然です。でもこれはGroovyの仕様上*2できない。なぜかというと、GroovyのMOPはメソッド呼び出しを検知してそれをすりかえる(invokeMethod)という真似はできるのですが、あるいはプロパティ参照を置き換えるとかもできる(getProperty)のですが、定数リテラルの存在を検知する仕組みがないからです。この制限は、LispBuilderを作ったときにはまりました。
そういうことでした。
BuilderはとてもGroovyらしい機能です。