• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Dsl&Builder
 

Dsl&Builder

on

  • 3,579 views

Grails Code Reading 2008/05/22

Grails Code Reading 2008/05/22

Statistics

Views

Total Views
3,579
Views on SlideShare
3,370
Embed Views
209

Actions

Likes
2
Downloads
18
Comments
0

4 Embeds 209

http://d.hatena.ne.jp 114
http://uehaj.hatenablog.com 85
http://www.slideshare.net 9
http://reader.livedoor.com 1

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Dsl&Builder Dsl&Builder Presentation Transcript

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