dsl&builder

26
DSL&Builder Grails Code Reading 2008/05/23 上上上上

Upload: junji-uehara

Post on 13-Jan-2015

2.356 views

Category:

Technology


0 download

DESCRIPTION

Grails Code Reading 2008/05/22

TRANSCRIPT

Page 1: Dsl&Builder

DSL&Builder

Grails Code Reading

2008/05/23

上原潤二

Page 2: Dsl&Builder

DSL■対象領域特化型言語

■ 楽譜♪ , MML, HTML, VHDL, *.ini, *.property, XAML, XUL, Windows のリソース定義言語 ,GIMP の Script-fu, elisp, AutoLISP, Postscript,アセンブラ ( 機械語記述専用言語 ),..

■ ⇔ 汎用言語

Page 3: Dsl&Builder

API と DSL            業務特化

■ 構文 汎用言語 → DSL

■ 語彙 標準 API → ドメインモデル

Page 4: Dsl&Builder

DSL の利点■ 文脈の限定 ( 前提の決め・制限 ),

詳細や不要機能の隠蔽による簡潔性・簡易化

■ 高密度 : 変更・レビューが容易■ 高抽象 : インピーダンスギャップ低減■ Grails では ..

■ Groovy 記述部分 (Domain, Contoller, ..) が DSL

  → Grails の主たるアドバンテージの源泉の一つ

Page 5: Dsl&Builder

内部 DSL■ 言語自身の自己カスタマイズ機能など

を駆使して言語上に作り上げるカスタム言語

■ ⇔ 外部 DSL( パーサをちゃんと作る )■ 作るのが面倒

■ Groovy は内部 DSL が得意

Page 6: Dsl&Builder

DSL の問題点■ 新しい言語を覚える必要がある■ 言語仕様のドキュメント化が必要

■ 最終的にはソースを読む

Page 7: Dsl&Builder

DSL にべんりな Groovy■ オペレータオーバーロード■ ルーズステートメント■ AST 変換■ クロージャ (+MOP)

■ Builder ← 今日のメインテーマ■ MOP

■ ダイナミックファインダー■ 明示的なコンパイルが不要■ fluent inteface■ 日本語メソッド名・クラス名

Page 8: Dsl&Builder

Builder とは何か■ AKA GroovyMarkup

■ ツリー型データ構造をクロージャ ( と MOP)を駆使して簡潔に書き下す

Page 9: Dsl&Builder

例えばこんな感じ (1)

Page 10: Dsl&Builder

ビルダー記述の一般構造< ビルダーオブジェクト> = new なんとかビルダー ()

< ビルダーオブジェクト >.< トップレベルメソッド > {

メソッド名 ( 属性名 : 属性値 , 属性名 : 属性値 ,...) {

:

}

メソッド名 ( 属性名 : 属性値 , 属性名 : 属性値 ,...) {

:

}..

}

Page 11: Dsl&Builder

ビルダー分類学 (1)■ ビルダー作成支援クラスから継承して作

る■ groovy.util.BuilderSupport■ groovy.util.FactoryBuilderSupport

■ 自前方式 ( 支援クラスを使用しない )

自前方式のものを「ビルダー」と呼べるかはやや ? だがここでは「広義のビルダー」としておく。

Page 12: Dsl&Builder

ビルダー分類学 (2)■ メソッド名を動的に作る

■ MOP で実装■ メソッド名は静的に定まっている

■ 静的にメソッドを定義しておく  or MOP で実装

Page 13: Dsl&Builder

ビルダー実例メソッド名動的 メソッド名静的

支援クラスを使用

BuilderSupport を継承→ MarkupBuilder, DOMBuilder, AntBuilder, SAXBuilder, NodeBuilder

FactoryBuilderSupport を継承→ SwingBuilder, ObjectGraphBuilder, JmxBuilder

自前方式 ConfigSlurperCliBuilder

Grails のビルダーたち constraints, UrlMapping, BeanBuilder,WebBeanBuilder, FlowBuilder, HibernateMappingBuilder, HibernateCriteriaBuilder, JSonBuilder

Page 14: Dsl&Builder

ビルダーを作ろう!Let's Build a Builder!

Page 15: Dsl&Builder

ビルダー DSL の基本構造■ パターン 1( ビルダーを明示使用 )

< ビルダーオブジェクト >.< トップレベルメソッド > { メソッド名 ( 属性名 : 属性値 , 属性名 : 属性値 ,...) { }..}

■ パターン 2( ごくさりげない DSL)static hogehoge = { メソッド名 ( 属性名 : 属性値 , 属性名 : 属性値 ,...) { }..}

■ パターン 3( スクリプトファイルとして独立 )< トップレベルメソッド > { メソッド名 ( 属性名 : 属性値 , 属性名 : 属性値 ,...) { }..}

Page 16: Dsl&Builder

実例紹介■ MarkupBuilder(Groovy)

■ UrlMapping Builder(Grails)

■ ロボビルダー

Page 17: Dsl&Builder

MarkupBuilder■ 木は作らない■ ステートマシンで逐次出力

groovy-1.6-beta-1/src/main/groovy/xml/MarkupBuilder.java

Page 18: Dsl&Builder

BuilderSupportclass BuilderSupport ... { : protected abstract void setParent(Object parent, Object child); protected abstract Object createNode(Object name); protected abstract Object createNode(Object name, Object value); protected abstract Object createNode(Object name, Map attributes); protected abstract Object createNode(Object name, Map attributes,

Object value);}

groovy-1.6-beta-1/src/main/groovy/util/BuilderSupport.java

Page 19: Dsl&Builder

UrlMappingBuilder(1)■ こういうやつ

class UrlMappings { static mappings = { "/$controller/$action?/$id?"{ constraints { // apply constraints here } } "500"(view:'/error') }}

 

grails-1.0-RC1/src/grails/grails-app/conf/UrlMappings.groovy

Page 20: Dsl&Builder

UrlMappingBuilder(1)■ こういうやつ

class UrlMappings { static mappings = { "/$controller/$action?/$id?"{ constraints { // apply constraints here } } "500"(view:'/error') }}

■ なんだこれ?文字列? GString?

grails-1.0-RC1/src/grails/grails-app/conf/UrlMappings.groovy

Page 21: Dsl&Builder

UrlMappingBuilder(2)public List evaluateMappings(Closure closure) { UrlMappingBuilder builder = new UrlMappingBuilder(); closure.setDelegate(builder); // デレゲートをセットしてクロージャを呼ぶ closure.call(); :public Object invokeMethod(String methodName, Object arg) { private Object _invoke(String methodName, Object arg, Object delegate) { if(methodName.startsWith(SLASH) || isResponseCode) { // スラッシュで

始まってる場合分岐 :public Object getProperty(String name) { if(urlDefiningMode) { previousConstraints.add(new ConstrainedProperty(UrlMapping.class, nam

e, String.class)); return CAPTURING_WILD_CARD; // "(*)" 変数をワイルドカードに置き

換え } else { return super.getProperty(name); }}

grails-1.0-RC1/src/web/org/codehaus/groovy/grails/web/mapping/DefaultUrlMappingEvaluator.java

Page 22: Dsl&Builder

種明かし■ Groovy は文字列定数がメソッド名になる

"println"("hello"); ←OK

a="rintln"; “p$a"("hello"); ←OK

■ invokeMethod でキャプチャ可能■ GString 参照は getProperty でキャプチャ

可能

Page 23: Dsl&Builder

ビルダーを作ってみよう■ ロボットを定義する DSL

■ sample/robot { body(texture:"gcrlogo.png") { head(texture:"earth.jpg") arm(x:-0.25){} leg(dummy:0) }}

TransformGroup createArm(x, y, armLength, armWidth, dx=0, dy=0, dz=0, tx=null) { def trans = transformGroupBase() def shoulder = new Sphere(0.15f, Primitive.GENERATE_TEXTURE_COORDS | Primitive.GENERATE_NORMALS | Primitive.ENABLE_GEOMETRY_PICKING, createAppearance(tx)) def idou = new Transform3D(); idou.setTranslation(new Vector3d(x , y, 0)) def kaitenX = new Transform3D(); kaitenX.rotX(Math.PI*dx) def kaitenY = new Transform3D(); kaitenY.rotY(Math.PI*dy) def kaitenZ = new Transform3D(); kaitenZ.rotZ(Math.PI*dz) idou.mul(kaitenX); idou.mul(kaitenY); idou.mul(kaitenZ) trans.setTransform(idou); trans.addChild(shoulder) def trans2 = transformGroupBase(false) def arm = new Cylinder(0.1f, armLength as float, Primitive.GENERATE_TEXTURE_COORDS | Primitive.GENERATE_NORMALS | Primitive.ENABLE_GEOMETRY_PICKING, createAppearance(tx)) def idou2 = new Transform3D() idou2.setTranslation(new Vector3d(0, -armLength/2, 0)) trans2.setTransform(idou2) trans2.addChild(arm); trans.addChild(trans2) ; return trans }

以下のコードが1行に対応

Page 24: Dsl&Builder

TIPS■ メソッド xxx 呼び出しの括弧を省略した

い■ getXxx() というメソッドを定義 ← 手軽■ getProperty() でちゃんと定義

Page 25: Dsl&Builder

まとめ■ Groovy の簡潔記述能力 = Groovy 言語機能 + DSL による拡張能力■ 従って、DSL を活用する

→ Groovy の真のパワーを発揮

めんどうな 3D 処理をDSL で wrap

( ゚ Д ゚ ) ウマー

Web アプリ3階層システムをGrails が提供する DSL で wrap

( ゚ Д ゚ ) ウマー

Page 26: Dsl&Builder

参考リンク■ Groovy DSL roundup

■ http://www.warneronstine.com/blog/articles/2008/04/24/groovy-dsl-roundup

■ A Groovy DSL from scratch in 2 hours■ http://groovy.dzone.com/news/groovy-dsl-scra

tch-2-hours