2回目. ここでは実は "Convention over Configuration" の実態が実は, grails がインタプリタ (メタオブジェクト) の集合になっていることだというのが分かる. ではいってみよう...
プラグイン定義クラスの規約を決めているやつは, 実はここにいる.
org.codehaus.groovy.grails.plugins.GrailsPlugin
Java インタフェースだが, スーパーインタフェースは Spring Framework の中にある ApplicationContextAware
. ApplicationContextAware
を実装するクラスは Spring Framework の恩恵を得ることができる, ととりあえずは思っておく.
GrailsPlugin には「規約」に相当する (≒ Java Interface に相当する), つまりプラグイン定義クラスで def すべきプロパティが文字列として定義されている. 例えばString DO_WITH_DYNAMIC_METHODS = doWithDynamicMethods;
String WATCHED_RESOURCES = watchedResources;
String EVICT = evict;
// ......
また実装クラスはそれらプロパティへのアクセッサを定義しなさい, となっている. 例えばvoid doWithWebDescriptor(GPathResult webXml);
String getName();
String getVersion();
// .......
つまり GrailsPlugin の実装クラスは, プラグイン定義クラスのインタプリタなのだ!
GrailsPlugin を実装しているのは
org.codehaus.groovy.grails.plugins.AbstractGrailsPlugin
で, つまりプラグイン定義クラスのインタプリタのひな形というわけ. これはさらに AbstractGrailsClass
のサブクラスになっている. AbstractGrailsClass
は Grails 全体で使われる汎用インタプリタのひな形だ. AbstractGrailsClass
のサブクラスには他に DefaultGrailsDomainClass
などがあるが, これはドメイン・クラス定義クラスのインタプリタということになる.
org.codehaus.groovy.grails.plugins.DefaultGrailsPlugin
は AbstractGrailsPlugin
を具体化したもの, つまりデフォルトのプラグイン定義クラス・インタプリタと言える. この中身を見てみると, new するときには対象となるプラグイン定義クラス (例えば WicketGrailsPlugin
) が渡される. これがつまりインタプリタに与えられるプログラムということになる. このプログラムのシンタックスは前述の GrailsPlugin
が決めているわけだ.
だから, プラグイン定義クラスに定義されていない変数 application
が出現したとしても, それをどうするかはインタプリタの都合次第ということになる. インタプリタの中を見てみると application
という変数には GrailsApplication
が入っている (doWithRuntimeConfiguration() メソッド内). 他にもこのクロージャの中では manager, plugin, parentCtx, resolver
という変数が使えることが分かる.GrailsApplication
は多分 Grails アプリケーションのファサードだろうと想像がつく. けど, これが実際にどんな変数とメソッドを持っているかは, GrailsApplication
の JavaDoc のようなドキュメントかソース・コードを見ないと分からない. そこが Grails の弱点だとは思う. つまりインタプリタの世界 (Java) とプログラムの世界 (Groovy/Grails) が分離している. だから何かしようと思うと二つの世界を行ったり来たりしなければならないことになる. Lisp や Smalltalk だとこの二つの世界は同じ言語で記述され, かつ優秀な開発/デバグ環境が存在するのだが...
ちなみにここで「インタプリタ」と呼んでいるものは「メタオブジェクト」と呼び変えてもよい. オブジェクトの挙動を決めているオブジェクトだから.
続く...