Adam L. Davis
The Solution Design Group, Inc.
@adamldavis.com
thesdg.com
Writing
Groovy DSLs
Agenda
●
Command Chains and @NamedParams
●
Operator Overloading
●
Categories, Extension modules
●
Closures, with, delegate, owner
●
propertyMissing, methodMissing
●
Groovy Scripts, GroovyShell
●
Groovy 3.0
●
Common DSLs
Command Chains
●
Command Chains allows parenthesis-free
fluent method calls
●
EX: method(param).then(foo) can be written
method param then foo
@NamedParams
● Mainly to give IDE hints for mapped parameters
● @NamedParams([array of @NamedParam])
● Can optionally tell what type is expected
Task task(@NamedParams([
@NamedParam(value = "name", type = String.class),
@NamedParam(value = "type", type = Class.class),
@NamedParam(value = "doLast", type = Closure.class),
@NamedParam(value = "doFirst", type = Closure.class),
@NamedParam(value = "depends", type = List.class)
]) Map<String, Object> map)
Operator Overloading
Demo 0
Categories, Extension modules
●
Category
– use(YourCategory) { *DSL* }
– YourCategory has static methods, first parameter is
class to decorate
– Unlike using metaclass, allows static compilation
●
Extension Modules!
– Much like Category but everywhere
– Put file in META-INF/groovy/
– “org.codehaus.groovy.runtime.ExtensionModule”
Closures, with, delegate, owner
●
Closures { }
●
object.with { * all methods, properties of object
available here * }
●
Closure.delegate = myThing
●
Closure.owner = myThing
●
method(@DelegatesTo(Foo) Closure param)
– Tells the compiler/IDE the class of the delegate
– Allows for auto-completion (in IntelliJ IDEA)
Demo 1
propertyMissing, methodMissing
●
def propertyMissing(String name): called
whenever something could be a property
reference.
– with/delegate/script-base: allows on the fly reference
of anything.
– propertyMissing(String name, value): assignment.
●
def methodMissing(String name, args):
– Name = name of method
– Args = array of arguments to method (0..n)
Groovy Scripts
●
No class or main(args) needed
●
GroovyShell
●
Ability to customize
– ImportCustomizer
– CompilerConfiguration
– Binding
– Change the script base-class
– Supply a class-loader
Demo 2
Groovy 3.0
●
Lambda expressions and :: supported
●
New operators:
– !in
– !instanceof
– ?=
– ?[x]
Groovy DSLs: JSONBuilder
def json = new groovy.json.JsonBuilder()
def root = json { // call(Closure)
person { // methodMissing( “person”, [Closure] )
firstName 'Adam' //methodMissing( “firstName”, [Adam] )
lastName 'Davis'
address( //methodMissing( “address”, [Map] )
city: 'Orlando',
country: 'USA',
zip: 32765
)
married true
// a list of values
conferences 'JavaOne', 'Gr8conf'
}
}
Groovy DSLs: Gradle
//def task(object)
task myTask //propertyMissing(“myTask”)
task myTask { configure closure }
//methodMissing(“myTask”, [closure])
task myTask(type: SomeType)
//methodMissing(“myTask”, [map])
task myTask(type: SomeType) { configure closure }
//methodMissing(“myTask”, [map,closure])
Groovy DSLs: GrooCSS
‘.myclass’.$ {} // Extension module: String
width 10.em // Extension module: Number
{ width 400.px height 200.px color black }
//Command chains
keyframes ‘flash’ {
10 % { color white }
50 % { color black }
100% { color white }
} // operator overloading
Thanks! Any ?’s
Adam L. Davis
The Solution Design Group, Inc.
@adamldavis.com
github.com/adamldavis/2019-gr8conf
or http://bit.ly/Gr8-2019BG
thesdg.com
This work is licensed under a Creative Commons
Attribution-ShareAlike 3.0 Unported License.
It makes use of the works of Mateus Machado Luna.
Thanks!

Writing Groovy DSLs

  • 1.
    Adam L. Davis TheSolution Design Group, Inc. @adamldavis.com thesdg.com Writing Groovy DSLs
  • 2.
    Agenda ● Command Chains and@NamedParams ● Operator Overloading ● Categories, Extension modules ● Closures, with, delegate, owner ● propertyMissing, methodMissing ● Groovy Scripts, GroovyShell ● Groovy 3.0 ● Common DSLs
  • 3.
    Command Chains ● Command Chainsallows parenthesis-free fluent method calls ● EX: method(param).then(foo) can be written method param then foo
  • 4.
    @NamedParams ● Mainly togive IDE hints for mapped parameters ● @NamedParams([array of @NamedParam]) ● Can optionally tell what type is expected Task task(@NamedParams([ @NamedParam(value = "name", type = String.class), @NamedParam(value = "type", type = Class.class), @NamedParam(value = "doLast", type = Closure.class), @NamedParam(value = "doFirst", type = Closure.class), @NamedParam(value = "depends", type = List.class) ]) Map<String, Object> map)
  • 5.
  • 6.
  • 7.
    Categories, Extension modules ● Category –use(YourCategory) { *DSL* } – YourCategory has static methods, first parameter is class to decorate – Unlike using metaclass, allows static compilation ● Extension Modules! – Much like Category but everywhere – Put file in META-INF/groovy/ – “org.codehaus.groovy.runtime.ExtensionModule”
  • 8.
    Closures, with, delegate,owner ● Closures { } ● object.with { * all methods, properties of object available here * } ● Closure.delegate = myThing ● Closure.owner = myThing ● method(@DelegatesTo(Foo) Closure param) – Tells the compiler/IDE the class of the delegate – Allows for auto-completion (in IntelliJ IDEA)
  • 9.
  • 10.
    propertyMissing, methodMissing ● def propertyMissing(Stringname): called whenever something could be a property reference. – with/delegate/script-base: allows on the fly reference of anything. – propertyMissing(String name, value): assignment. ● def methodMissing(String name, args): – Name = name of method – Args = array of arguments to method (0..n)
  • 11.
    Groovy Scripts ● No classor main(args) needed ● GroovyShell ● Ability to customize – ImportCustomizer – CompilerConfiguration – Binding – Change the script base-class – Supply a class-loader
  • 12.
  • 13.
    Groovy 3.0 ● Lambda expressionsand :: supported ● New operators: – !in – !instanceof – ?= – ?[x]
  • 14.
    Groovy DSLs: JSONBuilder defjson = new groovy.json.JsonBuilder() def root = json { // call(Closure) person { // methodMissing( “person”, [Closure] ) firstName 'Adam' //methodMissing( “firstName”, [Adam] ) lastName 'Davis' address( //methodMissing( “address”, [Map] ) city: 'Orlando', country: 'USA', zip: 32765 ) married true // a list of values conferences 'JavaOne', 'Gr8conf' } }
  • 15.
    Groovy DSLs: Gradle //deftask(object) task myTask //propertyMissing(“myTask”) task myTask { configure closure } //methodMissing(“myTask”, [closure]) task myTask(type: SomeType) //methodMissing(“myTask”, [map]) task myTask(type: SomeType) { configure closure } //methodMissing(“myTask”, [map,closure])
  • 16.
    Groovy DSLs: GrooCSS ‘.myclass’.${} // Extension module: String width 10.em // Extension module: Number { width 400.px height 200.px color black } //Command chains keyframes ‘flash’ { 10 % { color white } 50 % { color black } 100% { color white } } // operator overloading
  • 17.
    Thanks! Any ?’s AdamL. Davis The Solution Design Group, Inc. @adamldavis.com github.com/adamldavis/2019-gr8conf or http://bit.ly/Gr8-2019BG thesdg.com
  • 18.
    This work islicensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. It makes use of the works of Mateus Machado Luna. Thanks!