Dsl&Builder
Upcoming SlideShare
Loading in...5
×
 

Dsl&Builder

on

  • 3,668 views

Grails Code Reading 2008/05/22

Grails Code Reading 2008/05/22

Statistics

Views

Total Views
3,668
Views on SlideShare
3,457
Embed Views
211

Actions

Likes
2
Downloads
18
Comments
0

4 Embeds 211

http://d.hatena.ne.jp 114
http://uehaj.hatenablog.com 87
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