http://www.flickr.com/photos/iancarroll/5058330466/ Groovy’s Builder Post JavaFX Script!?
Jun 23, 2015
http://www.flickr.com/photos/iancarroll/5058330466/
Groovy’s BuilderPost JavaFX Script!?
Who am I?✓氏名:中野 靖治(a.k.a nobeans)✓所属:NTTソフトウェア株式会社✓ブログ:豆無日記 http://d.hatena.ne.jp/nobeans/
✓主な出没箇所:✓JGGUG(Japan Groovy&Grails User Group)✓ときどき思い出したかのようにjava-ja
Ad::GroovyServ✓Groovyスクリプトの実行が超爆速に✓ノーマル:約2秒 → GS:0.1秒以下✓簡単な仕組み✓Groovyインスタンスをサーバとして常駐✓ネイティブクライアント経由でGroovyサーバにスクリプトを転送して、実行
✓http://kobo.github.com/groovyserv/
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 } }
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 } }}
6
唐突ですが
SwingBuilder✓Groovyに標準バンドル✓SwingのGUI構造を、Groovyのクロージャ風の中括弧記法で表現できる
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 ) }}
どこかでみたような...
重ねて唐突ですが
Griffon✓クライアントアプリケーションフレームワーク✓SwingベースのMVCアーキテクチャ✓GroovyのSwingBuilderをフル活用✓Grailsの兄弟分✓アーキテクチャをそのまま踏襲✓プラグイン機構によって機能を拡充✓同一実装コードから Jar, Applet, JWS を生成
http://www.flickr.com/photos/33678919@N07/5239012324/
http://www.flickr.com/photos/33678919@N07/5239012324/
from Roadmap
JavaFX Wrappers for the GUI Builders
既にJavaFX用プラグインが存在
http://svn.codehaus.org/griffon/builders/fxbuilder/
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
こ、これは...
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
ほぼ一致
≒
http://www.flickr.com/photos/anirudhkoul/3734360895/
Welcome to
Groovy
協力:JavaFX Scriptファンのみなさん
http://www.flickr.com/photos/iancarroll/5058330466/
Minimum lecture series #65535
Groovyonly for DSL/Builder
DSL✓Domain Specification Language✓外部DSL✓XML、プロパティファイル、独自構文✓内部DSL✓主言語の構文の範囲で表現される✓Groovyには、内部DSLに便利な言語機能がたくさんある(ex. Builder)
Minimum Basic Syntax
✓セミコロン不要(あってもいいけど)✓returnは省略可→最後に評価された値が返る✓“Value: ${value}” と変数を埋め込める✓Mapリテラル [a:“A”, b:“B”, “c-1”:“C”]✓Listリテラル [1, 2, 3, “A”, “B”]
Features for DSL✓Closure✓MOP(Meta Object Programming)✓Builder✓Operator overloading✓AST transformations✓with句✓import文でのasによる別名定義✓GEP-3(多くの場面で括弧を省略できるようになる)✓etc.
Features for DSL✓Closure✓MOP(Meta Object Programming)✓Builder✓Operator overloading✓AST transformations✓with句✓import文でのasによる別名定義✓GEP-3(多くの場面で括弧を省略できるようになる)✓etc.
Features for DSL✓Closure✓MOP(Meta Object Programming)✓Builder✓Operator overloading✓AST transformations✓with句✓import文でのasによる別名定義✓GEP-3(多くの場面で括弧を省略できるようになる)✓etc.
Closuregroovy.lang.Closure closure = { String arg -‐> return "hoge:${arg}"}
// クロージャの評価closure.call(“foo”) //=> “hoge:foo”
// シンタックスシュガー版closure(“foo”) //=> “hoge:foo”
Java8のクロージャとの違いは# が付かないところ(見た目上)
// 引数なし(明示的)
{ -‐> "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
// 丸括弧付き(明示的)
someMethod({ num -‐> num * 2 })
// クロージャの場合は、丸括弧は省略できるsomeMethod { num -‐> num * 2 }
// 他の引数との組合せsomeMethod(arg1, arg2, { num -‐> num * 2 })someMethod(arg1, arg2) { num -‐> num * 2 } //上と等価
Closure as Args
Features for DSL✓Closure✓MOP(Meta Object Programming)✓Builder✓Operator overloading✓AST transformations✓with句✓import文でのasによる別名定義✓GEP-3(多くの場面で括弧を省略できるようになる)✓etc.
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])”
未定義のメソッド呼び出しをフックする
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 = !!"
未定義のプロパティアクセスをフックする
Features for DSL✓Closure✓MOP(Meta Object Programming)✓Builder✓Operator overloading✓AST transformations✓with句✓import文でのasによる別名定義✓GEP-3(多くの場面で括弧を省略できるようになる)✓etc.
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→
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}巻"
}}
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}巻"
}}
Classification of BuilderDynamically
Defined MethodStatically
Defined Method
ExtendsAbstract
Class
ExtendsAbstract
Class
Independent
extendsBuilderSupport
extends FactoryBuilderSupport
MarkupBuilderNodeBuilder
DOMBuilderAntBuilderSAXBuilder
SwingBuilderFxBuilder
ObjectGraphBuilderJmxBuilder
ConfigSlurperCliBuilder
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記述を順に評価していき、見つけた要素に対応するメソッドが呼ばれる
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記述を順に評価していき、見つけた要素に対応するファクトリが呼ばれる
NodeBuilder✓BuilderSupportのサブクラス✓読み込んだDSLをDOM風のノードツリーとして保持
✓独自Builderを作る場合にも便利✓DSLのパーサをNodeBuilderに任せる✓ノードツリーを辿って必要な処理を行う
≪sample≫
DdlBuilderpowered by NodeBuilder
http://www.flickr.com/photos/timothymorgan/75294154/
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
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
Features for DSL✓Closure✓MOP(Meta Object Programming)✓Builder✓Operator overloading✓AST transformations✓with句✓import文でのasによる別名定義✓GEP-3(多くの場面で括弧を省略できるようになる)✓etc.
Summary✓ポストJavaFX Scriptとして、Groovyはいかが?✓Builderで気軽にDSLを作ろう✓NodeBuilder が便利✓GriffonとFxBuilderの今後に注目
Happy BuilderLife!
http://www.flickr.com/photos/ztyx/4601942293/