Top Banner
http://www.flickr.com/photos/iancarroll/5058330466/ Groovy’s Builder Post JavaFX Script!?
44

Groovy's Builder

Jun 23, 2015

Download

Technology

Yasuharu NAKANO

2010-12-20のGlassfish & JavaFX合同勉強会で発表した資料です。
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Groovy's Builder

http://www.flickr.com/photos/iancarroll/5058330466/

Groovy’s BuilderPost JavaFX Script!?

Page 2: Groovy's Builder

Who am I?✓氏名:中野 靖治(a.k.a nobeans)✓所属:NTTソフトウェア株式会社✓ブログ:豆無日記 http://d.hatena.ne.jp/nobeans/

✓主な出没箇所:✓JGGUG(Japan Groovy&Grails User Group)✓ときどき思い出したかのようにjava-ja

Page 3: Groovy's Builder

Ad::GroovyServ✓Groovyスクリプトの実行が超爆速に✓ノーマル:約2秒 → GS:0.1秒以下✓簡単な仕組み✓Groovyインスタンスをサーバとして常駐✓ネイティブクライアント経由でGroovyサーバにスクリプトを転送して、実行

✓http://kobo.github.com/groovyserv/

Page 4: Groovy's Builder

Ad::GExcelAPI✓みんな大好きExcelへのアクセスが超簡単に✓https://github.com/nobeans/gexcelapi

@GrabConfig(systemClassLoader=true) // for GroovyServ@GrabResolver(name="kobo-repo", root="http://github.com/kobo/maven-repo/raw/master/release")@Grab("org.jggug.kobo:gexcelapi:0.2")import org.jggug.kobo.gexcelapi.GExcel

def book = GExcel.open(args[0])def sheet = book[0]

println sheet.A1.valuesheet.A1.value = "New value of A1"

sheet.A_.each{ cell -> println cell.value }sheet._1.each{ cell -> println cell.value }sheet.A1_B6.each{ row -> row.each { cell -> println it.value } }

Page 5: Groovy's Builder

Sample of

JavaFX Script

import  javafx.stage.*;import  javafx.scene.*;import  javafx.scene.shape.*;import  javafx.scene.paint.*;

Stage  {        title:  "Sample  by  JavaFX  Script"        width:  600        height:  450        scene:  Scene  {                fill:  Color.LIGHTSKYBLUE                content:  Rectangle  {                        x:  25,  y:  40                        width:  100,  height:  50                        fill:  Color.RED                }        }}

Page 6: Groovy's Builder

6

Page 7: Groovy's Builder

唐突ですが

Page 8: Groovy's Builder

SwingBuilder✓Groovyに標準バンドル✓SwingのGUI構造を、Groovyのクロージャ風の中括弧記法で表現できる

Page 9: Groovy's Builder

Sample of

Swing-Builder

import  groovy.swing.SwingBuilderimport  java.awt.BorderLayout  as  BL

int  count  =  0new  SwingBuilder().edt  {        frame(                title:'Hello',                size:[600,  450],                show:true        )  {                borderLayout()                textLabel  =  label(                        text:'Sample  of  SwingBuilder',                        constraints:  BL.NORTH                )                button(                        text:  'Click  Me!',                        actionPerformed:  {                                count++                                textLabel.text  =                                  "Clicked  ${count}  time(s)."                                println  "clicked"                        },                        constraints:  BL.SOUTH                )        }}

Page 10: Groovy's Builder

どこかでみたような...

Page 11: Groovy's Builder

重ねて唐突ですが

Page 12: Groovy's Builder

Griffon✓クライアントアプリケーションフレームワーク✓SwingベースのMVCアーキテクチャ✓GroovyのSwingBuilderをフル活用✓Grailsの兄弟分✓アーキテクチャをそのまま踏襲✓プラグイン機構によって機能を拡充✓同一実装コードから Jar, Applet, JWS を生成

http://www.flickr.com/photos/33678919@N07/5239012324/

Page 13: Groovy's Builder

http://www.flickr.com/photos/33678919@N07/5239012324/

from Roadmap

JavaFX Wrappers for the GUI Builders

Page 14: Groovy's Builder

既にJavaFX用プラグインが存在

http://svn.codehaus.org/griffon/builders/fxbuilder/

Page 15: Groovy's Builder

Sample of

FX-Builder

import  griffon.builder.fx.FxBuilder

import  javafx.stage.*import  javafx.scene.*import  javafx.scene.shape.*import  javafx.scene.paint.*

new  FxBuilder().edt  {        stage(                title:  "Sample  by  FxBuilder  of  Groovy",                width:  600,                height:  450,                scene:  scene(fill:  Color.$LIGHTSKYBLUE)  {                        rectangle(                                x:  25,  y:  40,                                width:  100,  height:  50,                                fill:  Color.$RED                        )                }        )}

http://griffon.codehaus.org/FxBuilder+Plugin

Page 16: Groovy's Builder

こ、これは...

Page 17: Groovy's Builder

import  griffon.builder.fx.FxBuilder

import  javafx.stage.*import  javafx.scene.*import  javafx.scene.shape.*import  javafx.scene.paint.*

new  FxBuilder().edt  {        stage(                title:  "Sample  by  FxBuilder  of  Groovy",                width:  600,                height:  450,                scene:  scene(fill:Color.$LIGHTSKYBLUE){                        rectangle(                                x:  25,  y:  40,                                width:  100,  height:  50,                                fill:  Color.$RED                        )                }        )}

import  javafx.stage.*;import  javafx.scene.*;import  javafx.scene.shape.*;import  javafx.scene.paint.*;

Stage  {        title:  "Sample  by  JavaFX  Script",        width:  600        height:  450        scene:  Scene  {                fill:  Color.LIGHTSKYBLUE                content:  Rectangle  {                        x:  25,  y:  40                        width:  100,  height:  50                        fill:  Color.RED                }        }}

FxBuilder

ほぼ一致

Page 18: Groovy's Builder

http://www.flickr.com/photos/anirudhkoul/3734360895/

Welcome to

Groovy

協力:JavaFX Scriptファンのみなさん

Page 19: Groovy's Builder

http://www.flickr.com/photos/iancarroll/5058330466/

Minimum lecture series #65535

Groovyonly for DSL/Builder

Page 20: Groovy's Builder

DSL✓Domain Specification Language✓外部DSL✓XML、プロパティファイル、独自構文✓内部DSL✓主言語の構文の範囲で表現される✓Groovyには、内部DSLに便利な言語機能がたくさんある(ex. Builder)

Page 21: Groovy's Builder

Minimum Basic Syntax

✓セミコロン不要(あってもいいけど)✓returnは省略可→最後に評価された値が返る✓“Value:  ${value}” と変数を埋め込める✓Mapリテラル [a:“A”, b:“B”, “c-1”:“C”]✓Listリテラル [1, 2, 3, “A”, “B”]

Page 22: Groovy's Builder

Features for DSL✓Closure✓MOP(Meta Object Programming)✓Builder✓Operator overloading✓AST transformations✓with句✓import文でのasによる別名定義✓GEP-3(多くの場面で括弧を省略できるようになる)✓etc.

Page 23: Groovy's Builder

Features for DSL✓Closure✓MOP(Meta Object Programming)✓Builder✓Operator overloading✓AST transformations✓with句✓import文でのasによる別名定義✓GEP-3(多くの場面で括弧を省略できるようになる)✓etc.

Page 24: Groovy's Builder

Features for DSL✓Closure✓MOP(Meta Object Programming)✓Builder✓Operator overloading✓AST transformations✓with句✓import文でのasによる別名定義✓GEP-3(多くの場面で括弧を省略できるようになる)✓etc.

Page 25: Groovy's Builder

Closuregroovy.lang.Closure  closure  =  {  String  arg  -­‐>        return  "hoge:${arg}"}

//  クロージャの評価closure.call(“foo”)    //=>  “hoge:foo”

//  シンタックスシュガー版closure(“foo”)              //=>  “hoge:foo”

Java8のクロージャとの違いは# が付かないところ(見た目上)

Page 26: Groovy's Builder

//  引数なし(明示的)

{  -­‐>  "hoge"  }.call()                              //=>  "hoge"

//  引数あり(型省略)

{  num  -­‐>  "hoge:${num}"  }.call(123)  //=>  "hoge:123"

//  引数あり(複数)

{  num,  String  id,  option  -­‐>        return  "hoge:${num}:${id}:${option}"}.call(123,  “0A”,  “X”)                          //=>  "hoge:123:0A:X"

//  暗黙引数のit

{  "hoge:${it}"  }.call(123)                  //=>  "hoge:123"

Args of Closure

Page 27: Groovy's Builder

//  丸括弧付き(明示的)

someMethod({  num  -­‐>  num  *  2  })

//  クロージャの場合は、丸括弧は省略できるsomeMethod  {  num  -­‐>  num  *  2  }

//  他の引数との組合せsomeMethod(arg1,  arg2,  {  num  -­‐>  num  *  2  })someMethod(arg1,  arg2)  {  num  -­‐>  num  *  2  }  //上と等価

Closure as Args

Page 28: Groovy's Builder

Features for DSL✓Closure✓MOP(Meta Object Programming)✓Builder✓Operator overloading✓AST transformations✓with句✓import文でのasによる別名定義✓GEP-3(多くの場面で括弧を省略できるようになる)✓etc.

Page 29: Groovy's Builder

MOP::methodMissingclass  MopSample  {        def  methodMissing(String  name,  args)  {                println  "Method:  $name($args)"        }}def  sample  =  new  MopSample()

sample.hoge()//  =>  “Method:  hoge([])”

sample.foo(123,  456)//  =>  “Method:  foo([123,  456])”

未定義のメソッド呼び出しをフックする

Page 30: Groovy's Builder

MOP::propertyMissingclass  MopSample  {        def  propertyMissing(String  name)  {  //  for  getter                println  "Property:  $name"        }        def  propertyMissing(String  name,  value)  {  //  for  setter                println  "Property:  $name  =  $value"        }}sample  =  new  MopSample2()

sample.hoge              //=>  "Property:  hoge"sample.bar                //=>  "Property:  bar"sample.baz  =  "!!"  //=>  "Property:  baz  =  !!"

未定義のプロパティアクセスをフックする

Page 31: Groovy's Builder

Features for DSL✓Closure✓MOP(Meta Object Programming)✓Builder✓Operator overloading✓AST transformations✓with句✓import文でのasによる別名定義✓GEP-3(多くの場面で括弧を省略できるようになる)✓etc.

Page 32: Groovy's Builder

ex. MarkupBuilderdef  writer  =  new  StringWriter()def  builder  =  new  groovy.xml.MarkupBuilder(writer)builder.books  {        book(published:"2010-­‐12-­‐20")  {                author  "nobeans"                title    "Groovyビルダ入門"

       }        3.times  {                book  "Groovy伝説  第${it+1}巻"

       }}println  writer.toString()

<books>    <book  published='2010-­‐12-­‐20'>        <author>nobeans</author>        <title>Groovyビルダ入門</title>

   </book>    <book>Groovy伝説  第1巻</book>

   <book>Groovy伝説  第2巻</book>

   <book>Groovy伝説  第3巻</book>

</books>

←Describe here

Format as Xml→

Page 33: Groovy's Builder

Basic Theory of Builder

✓builderのbooksメソッドに、1つのクロージャを引数として渡している

✓booksメソッドでクロージャを評価すると...

builder.books  {        book(published:"2010-­‐12-­‐20")  {                author  "nobeans"                title    "Groovyビルダ入門"

       }        3.times  {                book  "Groovy伝説  第${it+1}巻"

       }}

Page 34: Groovy's Builder

Basic Theory of Builder

✓bookメソッドが呼ばれると...✓(a) メソッド未定義なのでmethodMissingが呼ばれる✓(b) “book”用に登録されたFactoryが呼ばれる

builder.books  {        book(published:"2010-­‐12-­‐20")  {                author  "nobeans"                title    "Groovyビルダ入門"

       }        3.times  {                book  "Groovy伝説  第${it+1}巻"

       }}

Page 35: Groovy's Builder

Classification of BuilderDynamically

Defined MethodStatically

Defined Method

ExtendsAbstract

Class

ExtendsAbstract

Class

Independent

extendsBuilderSupport

extends FactoryBuilderSupport

MarkupBuilderNodeBuilder

DOMBuilderAntBuilderSAXBuilder

SwingBuilderFxBuilder

ObjectGraphBuilderJmxBuilder

ConfigSlurperCliBuilder

Page 36: Groovy's Builder

BuilderSupportpublic  abstract  class  BuilderSupport  ...  {      //  ...snip...      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);      //  ...snip...}

✓SAXパーサ風✓必要なcreateNodeメソッドなどをオーバライドしておく✓DSL記述を順に評価していき、見つけた要素に対応するメソッドが呼ばれる

Page 37: Groovy's Builder

FactoryBuilderSupportpublic  class  SwingBuilder  extends  FactoryBuilderSupport  {        //  ...snip...        def  registerSupportNodes()  {                registerFactory("action",  new  ActionFactory())                registerFactory("actions",  new  CollectionFactory())                registerFactory("map",  new  MapFactory())                registerFactory("imageIcon",  new  ImageIconFactory())                registerFactory("buttonGroup",  new  ButtonGroupFactory())                addAttributeDelegate(ButtonGroupFactory.&buttonGroupAttributeDelegate)                //  ...snip...        }        //  ...snip...}

✓DSL要素とそれに対する個別のファクトリをあらかじめ登録しておく

✓DSL記述を順に評価していき、見つけた要素に対応するファクトリが呼ばれる

Page 38: Groovy's Builder

NodeBuilder✓BuilderSupportのサブクラス✓読み込んだDSLをDOM風のノードツリーとして保持

✓独自Builderを作る場合にも便利✓DSLのパーサをNodeBuilderに任せる✓ノードツリーを辿って必要な処理を行う

Page 39: Groovy's Builder

≪sample≫

DdlBuilderpowered by NodeBuilder

http://www.flickr.com/photos/timothymorgan/75294154/

Page 40: Groovy's Builder

CREATE  TABLE  book  (        id  INTEGER,        title  TEXT,        published  TIMESTAMP,        author  INTEGER)CREATE  TABLE  author  (        id  INTEGER,        name  TEXT)

def  writer  =  new  StringWriter()new  DdlBuilder(writer).scheme  {    book  {        id                type:int        title          type:String        published  type:Date        author        type:int    }    author  {        id                type:int        name            type:String    }}println  writer.toString()

Usage

Page 41: Groovy's Builder

class  DdlBuilder  {        def  writer        DdlBuilder(writer)  {  this.writer  =  writer  }        def  scheme(Closure  cls)  {                new  NodeBuilder().scheme(cls).each  {  table  -­‐>                        writer.println  "CREATE  TABLE  ${table.name()}  ("                        writer.println  table.collect  {  col  -­‐>                                "        ${col.name()}  ${type(col.attribute('type'))}"                        }.join(",\n")                        writer.println  ")"                }        }        private  type(clazz)  {                switch  (clazz)  {                        case  String:  return  "TEXT"                        case  int:        return  "INTEGER"                        case  Date:      return  "TIMESTAMP"                        default:                            throw  new  RuntimeException("unsupported  type:  $clazz")                }        }}

Code

Page 42: Groovy's Builder

Features for DSL✓Closure✓MOP(Meta Object Programming)✓Builder✓Operator overloading✓AST transformations✓with句✓import文でのasによる別名定義✓GEP-3(多くの場面で括弧を省略できるようになる)✓etc.

Page 43: Groovy's Builder

Summary✓ポストJavaFX Scriptとして、Groovyはいかが?✓Builderで気軽にDSLを作ろう✓NodeBuilder が便利✓GriffonとFxBuilderの今後に注目

Page 44: Groovy's Builder

Happy BuilderLife!

http://www.flickr.com/photos/ztyx/4601942293/