Dsl&Builder

2,614 views
2,523 views

Published on

Grails Code Reading 2008/05/22

Published in: Technology
0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,614
On SlideShare
0
From Embeds
0
Number of Embeds
186
Actions
Shares
0
Downloads
19
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

Dsl&Builder

  1. 1. DSL&Builder Grails Code Reading 2008/05/23 上原潤二
  2. 2. DSL <ul><li>対象領域特化型言語 </li></ul><ul><ul><li>楽譜♪ , MML, HTML, VHDL, *.ini, *.property, XAML, XUL, Windows のリソース定義言語 ,GIMP の Script-fu, elisp, AutoLISP, Postscript, アセンブラ ( 機械語記述専用言語 ),.. </li></ul></ul><ul><li>⇔ 汎用言語 </li></ul>
  3. 3. API と DSL <ul><li>             業務特化 </li></ul><ul><li>構文 汎用言語 -> DSL </li></ul><ul><li>語彙 標準API -> ドメインモデル </li></ul>
  4. 4. DSL の利点 <ul><li>文脈の限定 ( 前提の決め・制限 ), 詳細や不要機能の隠蔽による 簡潔性・簡易化 </li></ul><ul><li>高密度 : 変更・レビューが容易 </li></ul><ul><li>高抽象 : インピーダンスギャップ低減 </li></ul><ul><li>Grails では .. </li></ul><ul><ul><li>Groovy 記述部分 (Domain, Contoller, ..) が DSL </li></ul></ul><ul><ul><li>  -> Grails の主たるアドバンテージの源泉の一つ </li></ul></ul>
  5. 5. 内部 DSL <ul><li>言語自身の自己カスタマイズ機能など を駆使して言語上に作り上げるカスタム言語 </li></ul><ul><li>⇔外部DSL(パーサをちゃんと作る) </li></ul><ul><ul><li>作るのが面倒 </li></ul></ul><ul><li>Groovyは内部DSLが得意 </li></ul>
  6. 6. DSL の問題点 <ul><li>新しい言語を覚える必要がある </li></ul><ul><li>言語仕様のドキュメント化が必要 </li></ul><ul><ul><li>最終的にはソースを読む </li></ul></ul>
  7. 7. DSL にべんりな Groovy <ul><li>オペレータオーバーロード </li></ul><ul><li>ルーズステートメント </li></ul><ul><li>AST 変換 </li></ul><ul><li>クロージャ (+MOP) </li></ul><ul><ul><li>Builder ← 今日のメインテーマ </li></ul></ul><ul><li>MOP </li></ul><ul><ul><li>ダイナミックファインダー </li></ul></ul><ul><li>明示的なコンパイルが不要 </li></ul><ul><li>fluent inteface </li></ul><ul><li>日本語メソッド名・クラス名 </li></ul>
  8. 8. Builder とは何か <ul><li>AKA GroovyMarkup </li></ul><ul><li>ツリー型データ構造をクロージャ ( と MOP) を駆使して簡潔に書き下す </li></ul>
  9. 9. 例えばこんな感じ (1)
  10. 10. ビルダー記述の一般構造 <ul><li>< ビルダーオブジェクト> = new なんとかビルダー () </li></ul><ul><li>< ビルダーオブジェクト >.< トップレベルメソッド > { </li></ul><ul><li>メソッド名 ( 属性名 : 属性値 , 属性名 : 属性値 ,...) { </li></ul><ul><li>: </li></ul><ul><li>} </li></ul><ul><li>メソッド名 ( 属性名 : 属性値 , 属性名 : 属性値 ,...) { </li></ul><ul><li>: </li></ul><ul><li>}.. </li></ul><ul><li>} </li></ul>
  11. 11. ビルダー分類学 (1) <ul><li>ビルダー作成支援クラスから継承して作る </li></ul><ul><ul><li>groovy.util.BuilderSupport </li></ul></ul><ul><ul><li>groovy.util.FactoryBuilderSupport </li></ul></ul><ul><li>自前方式 ( 支援クラスを使用しない ) </li></ul>自前方式のものを「ビルダー」と呼べるかはやや?だがここでは「広義のビルダー」としておく。
  12. 12. ビルダー分類学 (2) <ul><li>メソッド名を動的に作る </li></ul><ul><ul><li>MOPで実装 </li></ul></ul><ul><li>メソッド名は静的に定まっている </li></ul><ul><ul><li>静的にメソッドを定義しておく </li></ul></ul><ul><ul><li> or MOPで実装 </li></ul></ul>
  13. 13. ビルダー実例 ConfigSlurper CliBuilder 自前方式 Grails のビルダーたち constraints, UrlMapping, BeanBuilder,WebBeanBuilder, FlowBuilder, HibernateMappingBuilder, HibernateCriteriaBuilder, JSonBuilder FactoryBuilderSupport を継承 -> SwingBuilder, ObjectGraphBuilder, JmxBuilder BuilderSupport を継承 -> MarkupBuilder, DOMBuilder, AntBuilder, SAXBuilder, NodeBuilder 支援クラスを使用 メソッド名静的 メソッド名動的
  14. 14. ビルダーを作ろう! Let's Build a Builder!
  15. 15. ビルダー DSL の基本構造 <ul><li>パターン 1( ビルダーを明示使用 ) </li></ul><ul><ul><li>< ビルダーオブジェクト >.< トップレベルメソッド > { </li></ul></ul><ul><ul><li>メソッド名 ( 属性名 : 属性値 , 属性名 : 属性値 ,...) { </li></ul></ul><ul><ul><li>}.. </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>パターン 2( ごくさりげない DSL) </li></ul><ul><ul><li>static hogehoge = { </li></ul></ul><ul><ul><li>メソッド名 ( 属性名 : 属性値 , 属性名 : 属性値 ,...) { </li></ul></ul><ul><ul><li>}.. </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>パターン 3( スクリプトファイルとして独立 ) </li></ul><ul><ul><li>< トップレベルメソッド > { </li></ul></ul><ul><ul><li>メソッド名 ( 属性名 : 属性値 , 属性名 : 属性値 ,...) { </li></ul></ul><ul><ul><li>}.. </li></ul></ul><ul><ul><li>} </li></ul></ul>
  16. 16. 実例紹介 <ul><li>MarkupBuilder(Groovy) </li></ul><ul><li>UrlMapping Builder(Grails) </li></ul><ul><li>ロボビルダー </li></ul>
  17. 17. MarkupBuilder <ul><li>木は作らない </li></ul><ul><li>ステートマシンで逐次出力 </li></ul>groovy-1.6-beta-1/src/main/groovy/xml/MarkupBuilder.java
  18. 18. BuilderSupport <ul><li>class BuilderSupport ... { </li></ul><ul><li>: </li></ul><ul><li>protected abstract void setParent(Object parent, Object child); </li></ul><ul><li>protected abstract Object createNode(Object name); </li></ul><ul><li>protected abstract Object createNode(Object name, Object value); </li></ul><ul><li>protected abstract Object createNode(Object name, Map attributes); </li></ul><ul><li>protected abstract Object createNode(Object name, Map attributes, Object value); </li></ul><ul><li>} </li></ul>groovy-1.6-beta-1/src/main/groovy/util/BuilderSupport.java
  19. 19. UrlMappingBuilder(1) <ul><li>こういうやつ </li></ul><ul><ul><li>class UrlMappings { </li></ul></ul><ul><ul><li>static mappings = { </li></ul></ul><ul><ul><li>&quot;/$controller/$action?/$id?&quot;{ </li></ul></ul><ul><ul><li>constraints { </li></ul></ul><ul><ul><li>// apply constraints here </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>&quot;500&quot;(view:'/error') </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>  </li></ul>grails-1.0-RC1/src/grails/grails-app/conf/UrlMappings.groovy
  20. 20. UrlMappingBuilder(1) <ul><li>こういうやつ </li></ul><ul><ul><li>class UrlMappings { </li></ul></ul><ul><ul><li>static mappings = { </li></ul></ul><ul><ul><li>&quot;/ $ controller/ $ action?/$id?&quot;{ </li></ul></ul><ul><ul><li>constraints { </li></ul></ul><ul><ul><li>// apply constraints here </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>&quot;500&quot; (view:'/error') </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><li>なんだこれ?文字列? GString? </li></ul>grails-1.0-RC1/src/grails/grails-app/conf/UrlMappings.groovy
  21. 21. UrlMappingBuilder(2) <ul><li>public List evaluateMappings(Closure closure) { </li></ul><ul><li>UrlMappingBuilder builder = new UrlMappingBuilder(); </li></ul><ul><li>closure.setDelegate(builder); // デレゲートをセットしてクロージャを呼ぶ </li></ul><ul><li>closure.call(); </li></ul><ul><li>: </li></ul><ul><li>public Object invokeMethod(String methodName, Object arg) { </li></ul><ul><li>private Object _invoke(String methodName, Object arg, Object delegate) { </li></ul><ul><li>if( methodName.startsWith(SLASH) || isResponseCode) { // スラッシュで始まってる場合分岐 </li></ul><ul><li>: </li></ul><ul><li>public Object getProperty(String name) { </li></ul><ul><li>if(urlDefiningMode) { </li></ul><ul><li>previousConstraints.add(new ConstrainedProperty(UrlMapping.class, name, String.class)); </li></ul><ul><li>return CAPTURING_WILD_CARD; // &quot;(*)&quot; 変数をワイルドカードに置き換え </li></ul><ul><li>} </li></ul><ul><li>else { </li></ul><ul><li>return super.getProperty(name); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>grails-1.0-RC1/src/web/org/codehaus/groovy/grails/web/mapping/DefaultUrlMappingEvaluator.java
  22. 22. 種明かし <ul><li>Groovy は文字列定数がメソッド名になる </li></ul><ul><ul><li>&quot;println&quot;(&quot;hello&quot;); ←OK </li></ul></ul><ul><ul><li>a=&quot;rintln&quot;; “p$a&quot;(&quot;hello&quot;); ←OK </li></ul></ul><ul><li>invokeMethod でキャプチャ可能 </li></ul><ul><li>GString 参照は getProperty でキャプチャ可能 </li></ul>
  23. 23. ビルダーを作ってみよう <ul><li>ロボットを定義するDSL </li></ul><ul><li>sample/ </li></ul>robot { body(texture:&quot;gcrlogo.png&quot;) { head(texture:&quot;earth.jpg&quot;) 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行に対応
  24. 24. TIPS <ul><li>メソッド xxx 呼び出しの括弧を省略したい </li></ul><ul><ul><li>getXxx() というメソッドを定義 ← 手軽 </li></ul></ul><ul><ul><li>getProperty() でちゃんと定義 </li></ul></ul>
  25. 25. まとめ <ul><li>Groovyの簡潔記述能力 </li></ul><ul><li>= Groovy言語機能 + DSL による拡張能力 </li></ul><ul><li>従って、 </li></ul><ul><li>DSL を活用する </li></ul><ul><li>-> Groovyの 真 のパワーを発揮 </li></ul>めんどうな3D処理を DSLでwrap (゚Д゚) ウマー Webアプリ3階層システムを Grailsが提供するDSLでwrap (゚Д゚) ウマー
  26. 26. 参考リンク <ul><li>Groovy DSL roundup </li></ul><ul><ul><li>http://www.warneronstine.com/blog/articles/2008/04/24/groovy-dsl-roundup </li></ul></ul><ul><li>A Groovy DSL from scratch in 2 hours </li></ul><ul><ul><li>http://groovy.dzone.com/news/groovy-dsl-scratch-2-hours </li></ul></ul>

×