SlideShare a Scribd company logo
DSL’ing YOUR
@alotor
@alotor @alotor
Alonso Torres
Domain-specific
Languages
a Domain Specific Language
is a programming language that offers,
through appropriate notations and
abstractions, expressive power focused on a
particular problem domain.
a Domain Specific Language
is a programming language that offers,
through appropriate notations and
abstractions, expressive power focused on a
particular problem domain.
Expressive abstractions and notations
for a particular problem
A code snippet is worth a
thousand images
Configuration
log4j.main = {
error 'org.codehaus.groovy.grails.web.servlet',
'org.codehaus.groovy.grails.web.pages',
'org.codehaus.groovy.grails.web.sitemesh',
'org.codehaus.groovy.grails.web.mapping.filter',
'org.codehaus.groovy.grails.web.mapping',
'org.codehaus.groovy.grails.commons',
'org.codehaus.groovy.grails.plugins',
'org.codehaus.groovy.grails.orm.hibernate',
'org.springframework',
'org.hibernate',
'net.sf.ehcache.hibernate'
debug 'myapp.core',
}
class User {
...
static constraints = {
login size: 5..15, blank: false, unique: true
password size: 5..15, blank: false
email email: true, blank: false
age min: 18
}
}
Expressive API
def results = Account.createCriteria() {
between "balance", 500, 1000
eq "branch", "London"
or {
like "holderFirstName", "Fred%"
like "holderFirstName", "Barney%"
}
maxResults 10
order "holderLastName", "desc"
}
Specific notations
class MathSpec extends Specification {
def "maximum of two numbers"() {
expect:
Math.max(a, b) == c
where:
a | b || c
3 | 5 || 5
7 | 0 || 7
0 | 0 || 0
}
}
User’s input
apply plugin: 'groovy'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenLocal()
jcenter()
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.1'
testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'
testCompile 'junit:junit:4.11'
}
How cool is that?
But only “them”
can do those things
1. Closures
2. Builders
3. Open Classes
4. AST
5. Script
TOC
0. Groovy “sugar”
▸ Optional parentheses
GROOVY NICETIES
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.1'
testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'
testCompile 'junit:junit:4.11'
}
dependencies({
compile('org.codehaus.groovy:groovy-all:2.4.1')
testCompile('org.spockframework:spock-core:0.7-groovy-2.0')
testCompile('junit:junit:4.11')
})
▸ Optional parentheses
▸ Getter / setters
GROOVY NICETIES
sourceCompatibility = 1.8
targetCompatibility = 1.8
void setSourceCompatibility(version) {
...
}
void setTargetCompatibility(version) {
...
}
def sourceVersion = script.sourceCompatibility
def targetVersion = script.targetCompatibility
def getSourceCompatibility() {
...
}
def getTargetCompatibility() {
...
}
▸ Optional parentheses
▸ Getter / setters
▸ Operator overloading
GROOVY NICETIES
Operator Method
+ a.plus(b)
- a.minus(b)
* a.multiply(b)
/ a.div(b)
% a.mod(b)
** a.power(b)
| a.or(b)
& a.and(b)
^ a.xor(b)
Operator Method
a[b] a.getAt(b)
a[b] = c a.putAt(b, c)
<< a.leftShift(b)
>> a.rightShift(b)
++ a.next()
-- a.previous()
+a a.positive()
-a a.negative()
~a a.bitwiseNegative()
▸ Optional parentheses
▸ Getter / setters
▸ Operator overloading
▸ Keyword arguments
GROOVY NICETIES
def myKeyArgs(Map keyargs=[:], String value1, String value2) {
...
}
myKeyArgs("value1", "value2")
myKeyArgs("value1", "value2", cache: true)
myKeyArgs("value1", "value2", drop: 20, take: 50)
▸ Optional parentheses
▸ Getter / setters
▸ Operator overloading
▸ Keyword arguments
▸ Closure arguments
GROOVY NICETIES
def myClosureArg(String value1, String value2, Closure cls=null) {
...
}
myClosureArg("value1", "value2")
myClosureArg("value1", "value2") {
println ">> Calling inside closure"
}
▸ Optional parentheses
▸ Getter / setters
▸ Operator overloading
▸ Keyword arguments
▸ Closure arguments
▸ Command chaining
GROOVY NICETIES
take 2.pills of chloroquinine after 6.hours
take(2.pills).of(chloroquinine).after(6.hours)
paint(wall).with(red, green).and(yellow)
paint wall with red, green and yellow
given({}).when({}).then({})
given { } when { } then { }
Now, let’s talk business
1. Closure DSL’s
▸ DSL inside a closure
CLOSURE DSL’s
emailService.send {
from 'grumpy@cat.com'
to 'keyboard@cat.com'
subject 'Check this video out!'
body {
p 'Really awesome!'
}
}
▸ DSL inside a closure
CLOSURE DSL’s
emailService.send {
from 'grumpy@cat.com'
to 'keyboard@cat.com'
subject 'Check this video out!'
body {
p 'Really awesome!'
}
}
Method invocation.
Where are these
methods?
▸ this
▸ owner
▸ delegate
GROOVY CLOSURES CONTEXT
Three objects handle
the closure context
▸ this
▸ owner
▸ delegate
GROOVY CLOSURES CONTEXT
Normaly handles the
context (default)
▸ this
▸ owner
▸ delegate
GROOVY CLOSURES CONTEXT
Only changes for
nested closures
▸ this
▸ owner
▸ delegate
GROOVY CLOSURES CONTEXT
Can be changed!
▸ The handler will be called
CLOSURE DSL’s
class EmailHandler {
void from(String value) { }
void to(String value) { }
void subject(String value) { }
void body(Closure body) { }
Map buildData() { }
}
▸ Set the handler as delegate
CLOSURE DSL’s
def send(Closure dsl) {
def handler = new EmailHandler()
def code = cls.rehydrate(handler, null, null)
code.resolveStrategy = Closure.DELEGATE_ONLY
code.call()
def emailData = handler.buildData()
}
▸ Set the handler as delegate
CLOSURE DSL’s
def send(Closure dsl) {
def handler = new EmailHandler()
def code = cls.rehydrate(handler, null, null)
code.resolveStrategy = Closure.DELEGATE_ONLY
code.call()
def emailData = handler.buildData()
}
delegate owner this
▸ Set the handler as delegate
CLOSURE DSL’s
def send(Closure dsl) {
def handler = new EmailHandler()
def code = cls.rehydrate(handler, null, null)
code.resolveStrategy = Closure.DELEGATE_ONLY
code.call()
def emailData = handler.buildData()
}
Disable unexpected
interactions
▸ Set the handler as delegate
CLOSURE DSL’s
def send(Closure dsl) {
def handler = new EmailHandler()
def code = cls.rehydrate(handler, null, null)
code.resolveStrategy = Closure.DELEGATE_ONLY
code.call()
def emailData = handler.buildData()
}
Call the NEW closure
▸ Set the handler as delegate
CLOSURE DSL’s
def send(Closure dsl) {
def handler = new EmailHandler()
def code = cls.rehydrate(handler, null, null)
code.resolveStrategy = Closure.DELEGATE_ONLY
code.call()
def emailData = handler.buildData()
}
The handler now
contains the data
▸ All closure’s method/properties calls will
call a delegate
▸ Build around the delegate and then
retrieve the data
CLOSURE DSL’s
2. Groovy Builders
▸ Problem: Complex nested structures
BUILDER DSL’s
def bookshelf = builder.bookshelf {
author("George R. R. Martin") {
books {
"A Game Of Thrones" {
pages 1000
characters 57
houses {
stark {
motto "Winter is comming"
}
}
}
}
}
}
▸ Problem: Complex nested structures
BUILDER DSL’s
def bookshelf = builder.bookshelf {
author("George R. R. Martin") {
books {
"A Game Of Thrones" {
pages 1000
characters 57
houses {
stark {
motto "Winter is comming"
}
}
}
}
}
}
Delegate HELL
▸ Groovy provides support for this type of
DSL
▸ groovy.util.BuilderSupport
BUILDER DSL’s
▸ Defines a tree-like structure
BUILDER DSL’s
class BinaryTreeBuilderSupport extends BuilderSupport {
def createNode(def name, Map attributes, def value) {
new Container(name: name,
attributes: attributes,
value: value)
}
void setParent(def parent, def child) {
parent.items.push(child)
}
...
}
▸ Defines a tree-like structure
BUILDER DSL’s
class BinaryTreeBuilderSupport extends BuilderSupport {
def createNode(def name, Map attributes, def value) {
new Container(name: name,
attributes: attributes,
value: value)
}
void setParent(def parent, def child) {
parent.items.push(child)
}
...
}
Create Nodes
▸ Defines a tree-like structure
BUILDER DSL’s
class BinaryTreeBuilderSupport extends BuilderSupport {
def createNode(def name, Map attributes, def value) {
new Container(name: name,
attributes: attributes,
value: value)
}
void setParent(def parent, def child) {
parent.items.push(child)
}
...
}
Define parent-children
relationship
▸ Profit
BUILDER DSL’s
def bookshelf = builder.bookshelf {
author("George R. R. Martin") {
books {
"A Game Of Thrones" {
...
}
...
}
}
}
println bookshelf.items[0].items[0].items.name
>>> [“A Game of Thrones”, ...]
▸ You can use the BuilderSupport when you
have complex tree-like structures
▸ Only have to create nodes and
relationships between them
BUILDER DSL’s
3. Open Classes
▸ Groovy “standard” types can be extended
OPEN CLASSES DSL’s
Integer.metaClass.randomTimes = { Closure cls->
def randomValue = (new Random().nextInt(delegate)) +1
randomValue.times(cls)
}
Adding the method
“randomTimes” to ALL
the Integers
▸ Groovy “standard” types can be extended
OPEN CLASSES DSL’s
Integer.metaClass.randomTimes = { Closure cls->
def randomValue = (new Random().nextInt(delegate)) +1
randomValue.times(cls)
}
delegate has the
Integer’s value
▸ Groovy “standard” types can be extended
OPEN CLASSES DSL’s
Integer.metaClass.randomTimes = { Closure cls->
def randomValue = (new Random().nextInt(delegate)) +1
randomValue.times(cls)
}
Repeat a random
number of times the
closure
▸ Groovy “standard” types can be extended
OPEN CLASSES DSL’s
Integer.metaClass.randomTimes = { Closure cls->
def randomValue = (new Random().nextInt(delegate)) +1
randomValue.times(cls)
}
10.randomTimes {
println "x"
}
▸ Allows us to create nice DSL’s
OPEN CLASSES DSL’s
def order = buy 10.bottles of "milk"
▸ Allows us to create nice DSL’s
OPEN CLASSES DSL’s
def order = buy 10.bottles of "milk"
Integer.metaClass.getBottles = {
return new Quantity(quantity: delegate, ontainer: "bottle")
}
4. AST Transformations
▸ Problem: The language isn’t flexible
enough for your taste
AST DSL’s
class MathSpec extends Specification {
def "maximum of two numbers"() {
expect:
Math.max(a, b) == c
where:
a | b || c
3 | 5 || 5
7 | 0 || 7
0 | 0 || 0
}
}
▸ Problem: The language isn’t flexible
enough for your taste
AST DSL’s
class MathSpec extends Specification {
def "maximum of two numbers"() {
expect:
Math.max(a, b) == c
where:
a | b || c
3 | 5 || 5
7 | 0 || 7
0 | 0 || 0
}
}
What???!!!!
▸ With AST’s you can modify the language
on compile time
▸ BUT you have to respect the syntax
AST DSL’s
AST DSL’s
where:
a | b || c
3 | 5 || 5
7 | 0 || 7
0 | 0 || 0
Bit-level OR Logical OR
▸ We can do the same
AST DSL’s
class Main {
@SpockTable
def getTable() {
value1 | value2 | value3 || max
1 | 2 | 3 || 3
2 | 1 | 0 || 2
2 | 2 | 1 || 2
}
public static void main(def args) {
def tableData = new Main().getTable()
assert tableData['value1'] == [1, 2, 2]
}
}
▸ We can do the same
OPEN CLASSES DSL’s
class Main {
@SpockTable
def getTable() {
value1 | value2 | value3 || max
1 | 2 | 3 || 3
2 | 1 | 0 || 2
2 | 2 | 1 || 2
}
public static void main(def args) {
def tableData = new Main().getTable()
assert tableData['value1'] == [1, 2, 2]
}
}
Local AST
▸ What kind of transformation we want?
AST DSL’s
def getTable() {
value1 | value2 | value3 || max
1 | 2 | 3 || 3
2 | 1 | 0 || 2
2 | 2 | 1 || 2
}
def getTablePostAST() {
[
value1 : [1, 2, 2],
value2 : [2, 1, 2],
value3 : [3, 0, 1],
max : [3, 2, 2]
]
}
AST DSL’s
▸ Have to convert from one AST to the other
AST DSL’s
void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
MethodNode method = (MethodNode) nodes[1]
def existingStatements = ((BlockStatement)method.code).statements
def headers = processTableHeaders(existingStatements[0])
def mapToSet = processTableBody(headers, existingStatements[1..-1])
def mapExpression = createMapStatement(mapToSet)
existingStatements.clear()
existingStatements.add(mapExpression)
}
▸ Have to convert from one AST to the other
AST DSL’s
void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
MethodNode method = (MethodNode) nodes[1]
def existingStatements = ((BlockStatement)method.code).statements
def headers = processTableHeaders(existingStatements[0])
def mapToSet = processTableBody(headers, existingStatements[1..-1])
def mapExpression = createMapStatement(mapToSet)
existingStatements.clear()
existingStatements.add(mapExpression)
}
Retrieves all the
method statements
▸ Have to convert from one AST to the other
AST DSL’s
void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
MethodNode method = (MethodNode) nodes[1]
def existingStatements = ((BlockStatement)method.code).statements
def headers = processTableHeaders(existingStatements[0])
def mapToSet = processTableBody(headers, existingStatements[1..-1])
def mapExpression = createMapStatement(mapToSet)
existingStatements.clear()
existingStatements.add(mapExpression)
}
The first will be the
header of our table
▸ Have to convert from one AST to the other
AST DSL’s
void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
MethodNode method = (MethodNode) nodes[1]
def existingStatements = ((BlockStatement)method.code).statements
def headers = processTableHeaders(existingStatements[0])
def mapToSet = processTableBody(headers, existingStatements[1..-1])
def mapExpression = createMapStatement(mapToSet)
existingStatements.clear()
existingStatements.add(mapExpression)
}
The rest will be the
different values for
the table body
▸ Have to convert from one AST to the other
AST DSL’s
void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
MethodNode method = (MethodNode) nodes[1]
def existingStatements = ((BlockStatement)method.code).statements
def headers = processTableHeaders(existingStatements[0])
def mapToSet = processTableBody(headers, existingStatements[1..-1])
def mapExpression = createMapStatement(mapToSet)
existingStatements.clear()
existingStatements.add(mapExpression)
}
With this values we
create new code for
this method body
▸ Have to convert from one AST to the other
AST DSL’s
void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
MethodNode method = (MethodNode) nodes[1]
def existingStatements = ((BlockStatement)method.code).statements
def headers = processTableHeaders(existingStatements[0])
def mapToSet = processTableBody(headers, existingStatements[1..-1])
def mapExpression = createMapStatement(mapToSet)
existingStatements.clear()
existingStatements.add(mapExpression)
}
Delete all the old
one
▸ Have to convert from one AST to the other
AST DSL’s
void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
MethodNode method = (MethodNode) nodes[1]
def existingStatements = ((BlockStatement)method.code).statements
def headers = processTableHeaders(existingStatements[0])
def mapToSet = processTableBody(headers, existingStatements[1..-1])
def mapExpression = createMapStatement(mapToSet)
existingStatements.clear()
existingStatements.add(mapExpression)
}
Replace with the
new code
▸ Try your DSL syntax on groovyConsole
▸ Check the “source” AST and the “target”
AST
▸ Think about how to convert from one to
another
AST DSL’s
No magic involved ;-)
5. Scripting
▸ All these techniques with external scripts
SCRIPTING DSL’s
apply plugin: 'groovy'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenLocal()
jcenter()
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.1'
testCompile 'junit:junit:4.11'
}
▸ All these techniques with external scripts
SCRIPTING DSL’s
apply plugin: 'groovy'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenLocal()
jcenter()
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.1'
testCompile 'junit:junit:4.11'
}
Properties
Method calls
▸ Script binding to a map
SCRIPTING DSL’s
def binding = new Binding(
apply: { Map args -> println args},
repositories: { Closure dsl -> println "repositories"},
dependencies: { Closure dsl -> println "dependencies" }
)
def shell = new GroovyShell(binding)
shell.evaluate(new File("build.gradle"))
▸ We want a state for these methods
SCRIPTING DSL’s
class MyGradle {
void apply(Map toApply) {
...
}
void repositories(Closure dslRepositories) {
...
}
void dependencies(Closure dslDependencies) {
...
}
}
▸ Script binding to an object
SCRIPTING DSL’s
def configuration = new CompilerConfiguration()
configuration.setScriptBaseClass(DelegatingScript.class.getName())
def shell = new GroovyShell(new Binding(),configuration)
def script = shell.parse(new File("build.gradle"))
script.setDelegate(new MyGradle())
script.run()
▸ Script binding to an object
SCRIPTING DSL’s
def configuration = new CompilerConfiguration()
configuration.setScriptBaseClass(DelegatingScript.class.getName())
def shell = new GroovyShell(new Binding(),configuration)
def script = shell.parse(new File("build.gradle"))
script.setDelegate(new MyGradle())
script.run()
Type of Script
▸ Script binding to an object
SCRIPTING DSL’s
def configuration = new CompilerConfiguration()
configuration.setScriptBaseClass(DelegatingScript.class.getName())
def shell = new GroovyShell(new Binding(),configuration)
def script = shell.parse(new File("build.gradle"))
script.setDelegate(new MyGradle())
script.run()
Set our delegate
▸ Default imports
SCRIPTING DSL’s
def configuration = new CompilerConfiguration()
def imports = new ImportCustomizer()
imports.addStaticStar('java.util.Calendar')
configuration.addCompilationCustomizers(imports)
▸ Default imports
SCRIPTING DSL’s
def configuration = new CompilerConfiguration()
def imports = new ImportCustomizer()
imports.addStaticStar('java.util.Calendar')
configuration.addCompilationCustomizers(imports)
import static from java.util.Calendar.*
▸ Apply AST Transformations
SCRIPTING DSL’s
def configuration = new CompilerConfiguration()
def ast = new ASTTransformationCustomizer(Log)
configuration.addCompilationCustomizers(ast)
▸ Apply AST Transformations
SCRIPTING DSL’s
def configuration = new CompilerConfiguration()
def ast = new ASTTransformationCustomizer(Log)
configuration.addCompilationCustomizers(ast)
AST to apply inside the script
▸ Sanitize user input
SCRIPTING DSL’s
def configuration = new CompilerConfiguration()
def secure = new SecureASTCustomizer()
secure.methodDefinitionAllowed = false
configuration.addCompilationCustomizers(secure)
▸ Sanitize user input
SCRIPTING DSL’s
def configuration = new CompilerConfiguration()
def secure = new SecureASTCustomizer()
secure.methodDefinitionAllowed = false
configuration.addCompilationCustomizers(secure)
We don’t allow method
definitions in the script
1. Closures
2. Builders
3. Open Classes
4. AST
5. Script
Go ahead!
DSL your Groovy
@alotor @alotor
THANKS!

More Related Content

What's hot

functional groovy
functional groovyfunctional groovy
functional groovyPaul King
 
Polyglot Programming in the JVM
Polyglot Programming in the JVMPolyglot Programming in the JVM
Polyglot Programming in the JVMAndres Almiray
 
Fantastic DSL in Python
Fantastic DSL in PythonFantastic DSL in Python
Fantastic DSL in Python
kwatch
 
GR8Conf 2009: What's New in Groovy 1.6? by Guillaume Laforge
GR8Conf 2009: What's New in Groovy 1.6? by Guillaume LaforgeGR8Conf 2009: What's New in Groovy 1.6? by Guillaume Laforge
GR8Conf 2009: What's New in Groovy 1.6? by Guillaume Laforge
GR8Conf
 
Logic programming a ruby perspective
Logic programming a ruby perspectiveLogic programming a ruby perspective
Logic programming a ruby perspective
Norman Richards
 
Grooscript gr8conf
Grooscript gr8confGrooscript gr8conf
Grooscript gr8conf
GR8Conf
 
Designing with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf IndiaDesigning with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf India
Naresha K
 
concurrency with GPars
concurrency with GParsconcurrency with GPars
concurrency with GPars
Paul King
 
groovy & grails - lecture 3
groovy & grails - lecture 3groovy & grails - lecture 3
groovy & grails - lecture 3
Alexandre Masselot
 
Turtle Graphics in Groovy
Turtle Graphics in GroovyTurtle Graphics in Groovy
Turtle Graphics in Groovy
Jim Driscoll
 
GPars (Groovy Parallel Systems)
GPars (Groovy Parallel Systems)GPars (Groovy Parallel Systems)
GPars (Groovy Parallel Systems)
Gagan Agrawal
 
Gpars concepts explained
Gpars concepts explainedGpars concepts explained
Gpars concepts explained
Vaclav Pech
 
Declarative Internal DSLs in Lua: A Game Changing Experience
Declarative Internal DSLs in Lua: A Game Changing ExperienceDeclarative Internal DSLs in Lua: A Game Changing Experience
Declarative Internal DSLs in Lua: A Game Changing ExperienceAlexander Gladysh
 
Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012
aleks-f
 
Oleksii Holub "Expression trees in C#"
Oleksii Holub "Expression trees in C#" Oleksii Holub "Expression trees in C#"
Oleksii Holub "Expression trees in C#"
Fwdays
 
Expression trees in C#
Expression trees in C#Expression trees in C#
Expression trees in C#
Oleksii Holub
 
Polyglot Grails
Polyglot GrailsPolyglot Grails
Polyglot Grails
Marcin Gryszko
 
Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! aleks-f
 
core.logic introduction
core.logic introductioncore.logic introduction
core.logic introduction
Norman Richards
 
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...Paul King
 

What's hot (20)

functional groovy
functional groovyfunctional groovy
functional groovy
 
Polyglot Programming in the JVM
Polyglot Programming in the JVMPolyglot Programming in the JVM
Polyglot Programming in the JVM
 
Fantastic DSL in Python
Fantastic DSL in PythonFantastic DSL in Python
Fantastic DSL in Python
 
GR8Conf 2009: What's New in Groovy 1.6? by Guillaume Laforge
GR8Conf 2009: What's New in Groovy 1.6? by Guillaume LaforgeGR8Conf 2009: What's New in Groovy 1.6? by Guillaume Laforge
GR8Conf 2009: What's New in Groovy 1.6? by Guillaume Laforge
 
Logic programming a ruby perspective
Logic programming a ruby perspectiveLogic programming a ruby perspective
Logic programming a ruby perspective
 
Grooscript gr8conf
Grooscript gr8confGrooscript gr8conf
Grooscript gr8conf
 
Designing with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf IndiaDesigning with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf India
 
concurrency with GPars
concurrency with GParsconcurrency with GPars
concurrency with GPars
 
groovy & grails - lecture 3
groovy & grails - lecture 3groovy & grails - lecture 3
groovy & grails - lecture 3
 
Turtle Graphics in Groovy
Turtle Graphics in GroovyTurtle Graphics in Groovy
Turtle Graphics in Groovy
 
GPars (Groovy Parallel Systems)
GPars (Groovy Parallel Systems)GPars (Groovy Parallel Systems)
GPars (Groovy Parallel Systems)
 
Gpars concepts explained
Gpars concepts explainedGpars concepts explained
Gpars concepts explained
 
Declarative Internal DSLs in Lua: A Game Changing Experience
Declarative Internal DSLs in Lua: A Game Changing ExperienceDeclarative Internal DSLs in Lua: A Game Changing Experience
Declarative Internal DSLs in Lua: A Game Changing Experience
 
Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012Dynamic C++ Silicon Valley Code Camp 2012
Dynamic C++ Silicon Valley Code Camp 2012
 
Oleksii Holub "Expression trees in C#"
Oleksii Holub "Expression trees in C#" Oleksii Holub "Expression trees in C#"
Oleksii Holub "Expression trees in C#"
 
Expression trees in C#
Expression trees in C#Expression trees in C#
Expression trees in C#
 
Polyglot Grails
Polyglot GrailsPolyglot Grails
Polyglot Grails
 
Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! 
 
core.logic introduction
core.logic introductioncore.logic introduction
core.logic introduction
 
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
Industrial Strength Groovy - Tools for the Professional Groovy Developer: Pau...
 

Viewers also liked

Introduction to Groovy (Serbian Developer Conference 2013)
Introduction to Groovy (Serbian Developer Conference 2013)Introduction to Groovy (Serbian Developer Conference 2013)
Introduction to Groovy (Serbian Developer Conference 2013)
Joachim Baumann
 
Understanding GORM (Greach 2014)
Understanding GORM (Greach 2014)Understanding GORM (Greach 2014)
Understanding GORM (Greach 2014)
Alonso Torres
 
(Codemotion 2014) 20 lenguajes en 40 minutos
(Codemotion 2014) 20 lenguajes en 40 minutos(Codemotion 2014) 20 lenguajes en 40 minutos
(Codemotion 2014) 20 lenguajes en 40 minutos
Alonso Torres
 
[Greach 2016] Down The RabbitMQ Hole
[Greach 2016] Down The RabbitMQ Hole[Greach 2016] Down The RabbitMQ Hole
[Greach 2016] Down The RabbitMQ Hole
Alonso Torres
 
(Codemotion 2014) JVM GC: WTF?!
(Codemotion 2014) JVM GC: WTF?!(Codemotion 2014) JVM GC: WTF?!
(Codemotion 2014) JVM GC: WTF?!
Alonso Torres
 
(Greach 2015) Decathlon Sport Meeting
(Greach 2015) Decathlon Sport Meeting(Greach 2015) Decathlon Sport Meeting
(Greach 2015) Decathlon Sport Meeting
Alonso Torres
 
Idiomatic gradle plugin writing
Idiomatic gradle plugin writingIdiomatic gradle plugin writing
Idiomatic gradle plugin writing
Schalk Cronjé
 
[Jbcn 2016] Garbage Collectors WTF!?
[Jbcn 2016] Garbage Collectors WTF!?[Jbcn 2016] Garbage Collectors WTF!?
[Jbcn 2016] Garbage Collectors WTF!?
Alonso Torres
 
Continuous Deployment at Etsy: A Tale of Two Approaches
Continuous Deployment at Etsy: A Tale of Two ApproachesContinuous Deployment at Etsy: A Tale of Two Approaches
Continuous Deployment at Etsy: A Tale of Two ApproachesRoss Snyder
 
[Greach 17] make concurrency groovy again
[Greach 17] make concurrency groovy again[Greach 17] make concurrency groovy again
[Greach 17] make concurrency groovy again
Alonso Torres
 
Going to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific LanguagesGoing to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific Languages
Guillaume Laforge
 

Viewers also liked (12)

Practical Groovy DSL
Practical Groovy DSLPractical Groovy DSL
Practical Groovy DSL
 
Introduction to Groovy (Serbian Developer Conference 2013)
Introduction to Groovy (Serbian Developer Conference 2013)Introduction to Groovy (Serbian Developer Conference 2013)
Introduction to Groovy (Serbian Developer Conference 2013)
 
Understanding GORM (Greach 2014)
Understanding GORM (Greach 2014)Understanding GORM (Greach 2014)
Understanding GORM (Greach 2014)
 
(Codemotion 2014) 20 lenguajes en 40 minutos
(Codemotion 2014) 20 lenguajes en 40 minutos(Codemotion 2014) 20 lenguajes en 40 minutos
(Codemotion 2014) 20 lenguajes en 40 minutos
 
[Greach 2016] Down The RabbitMQ Hole
[Greach 2016] Down The RabbitMQ Hole[Greach 2016] Down The RabbitMQ Hole
[Greach 2016] Down The RabbitMQ Hole
 
(Codemotion 2014) JVM GC: WTF?!
(Codemotion 2014) JVM GC: WTF?!(Codemotion 2014) JVM GC: WTF?!
(Codemotion 2014) JVM GC: WTF?!
 
(Greach 2015) Decathlon Sport Meeting
(Greach 2015) Decathlon Sport Meeting(Greach 2015) Decathlon Sport Meeting
(Greach 2015) Decathlon Sport Meeting
 
Idiomatic gradle plugin writing
Idiomatic gradle plugin writingIdiomatic gradle plugin writing
Idiomatic gradle plugin writing
 
[Jbcn 2016] Garbage Collectors WTF!?
[Jbcn 2016] Garbage Collectors WTF!?[Jbcn 2016] Garbage Collectors WTF!?
[Jbcn 2016] Garbage Collectors WTF!?
 
Continuous Deployment at Etsy: A Tale of Two Approaches
Continuous Deployment at Etsy: A Tale of Two ApproachesContinuous Deployment at Etsy: A Tale of Two Approaches
Continuous Deployment at Etsy: A Tale of Two Approaches
 
[Greach 17] make concurrency groovy again
[Greach 17] make concurrency groovy again[Greach 17] make concurrency groovy again
[Greach 17] make concurrency groovy again
 
Going to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific LanguagesGoing to Mars with Groovy Domain-Specific Languages
Going to Mars with Groovy Domain-Specific Languages
 

Similar to (Greach 2015) Dsl'ing your Groovy

Store and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and CassandraStore and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and CassandraDeependra Ariyadewa
 
Groovy.pptx
Groovy.pptxGroovy.pptx
Groovy.pptx
Giancarlo Frison
 
Module Magic
Module MagicModule Magic
Module Magic
James Gray
 
NodeJS: the good parts? A skeptic’s view (jax jax2013)
NodeJS: the good parts? A skeptic’s view (jax jax2013)NodeJS: the good parts? A skeptic’s view (jax jax2013)
NodeJS: the good parts? A skeptic’s view (jax jax2013)
Chris Richardson
 
MongoDB
MongoDB MongoDB
Groovy closures
Groovy closuresGroovy closures
Groovy closures
Vijay Shukla
 
Dsl
DslDsl
Dsl
phoet
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Tsuyoshi Yamamoto
 
User Defined Aggregation in Apache Spark: A Love Story
User Defined Aggregation in Apache Spark: A Love StoryUser Defined Aggregation in Apache Spark: A Love Story
User Defined Aggregation in Apache Spark: A Love Story
Databricks
 
User Defined Aggregation in Apache Spark: A Love Story
User Defined Aggregation in Apache Spark: A Love StoryUser Defined Aggregation in Apache Spark: A Love Story
User Defined Aggregation in Apache Spark: A Love Story
Databricks
 
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...
Data Con LA
 
The Ring programming language version 1.5.2 book - Part 11 of 181
The Ring programming language version 1.5.2 book - Part 11 of 181The Ring programming language version 1.5.2 book - Part 11 of 181
The Ring programming language version 1.5.2 book - Part 11 of 181
Mahmoud Samir Fayed
 
Metaprogramovanie #1
Metaprogramovanie #1Metaprogramovanie #1
Metaprogramovanie #1Jano Suchal
 
CS101- Introduction to Computing- Lecture 29
CS101- Introduction to Computing- Lecture 29CS101- Introduction to Computing- Lecture 29
CS101- Introduction to Computing- Lecture 29
Bilal Ahmed
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014
Baruch Sadogursky
 
Groovy Fly Through
Groovy Fly ThroughGroovy Fly Through
Groovy Fly Throughniklal
 
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)MongoSF
 
Introduction to Scalding and Monoids
Introduction to Scalding and MonoidsIntroduction to Scalding and Monoids
Introduction to Scalding and Monoids
Hugo Gävert
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
MongoDB
 

Similar to (Greach 2015) Dsl'ing your Groovy (20)

Store and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and CassandraStore and Process Big Data with Hadoop and Cassandra
Store and Process Big Data with Hadoop and Cassandra
 
Groovy.pptx
Groovy.pptxGroovy.pptx
Groovy.pptx
 
Module Magic
Module MagicModule Magic
Module Magic
 
NodeJS: the good parts? A skeptic’s view (jax jax2013)
NodeJS: the good parts? A skeptic’s view (jax jax2013)NodeJS: the good parts? A skeptic’s view (jax jax2013)
NodeJS: the good parts? A skeptic’s view (jax jax2013)
 
MongoDB
MongoDB MongoDB
MongoDB
 
Groovy closures
Groovy closuresGroovy closures
Groovy closures
 
Dsl
DslDsl
Dsl
 
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
Grails 1.2 探検隊 -新たな聖杯をもとめて・・・-
 
User Defined Aggregation in Apache Spark: A Love Story
User Defined Aggregation in Apache Spark: A Love StoryUser Defined Aggregation in Apache Spark: A Love Story
User Defined Aggregation in Apache Spark: A Love Story
 
User Defined Aggregation in Apache Spark: A Love Story
User Defined Aggregation in Apache Spark: A Love StoryUser Defined Aggregation in Apache Spark: A Love Story
User Defined Aggregation in Apache Spark: A Love Story
 
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...
Big Data Day LA 2015 - Compiling DSLs for Diverse Execution Environments by Z...
 
The Ring programming language version 1.5.2 book - Part 11 of 181
The Ring programming language version 1.5.2 book - Part 11 of 181The Ring programming language version 1.5.2 book - Part 11 of 181
The Ring programming language version 1.5.2 book - Part 11 of 181
 
Latinoware
LatinowareLatinoware
Latinoware
 
Metaprogramovanie #1
Metaprogramovanie #1Metaprogramovanie #1
Metaprogramovanie #1
 
CS101- Introduction to Computing- Lecture 29
CS101- Introduction to Computing- Lecture 29CS101- Introduction to Computing- Lecture 29
CS101- Introduction to Computing- Lecture 29
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014
 
Groovy Fly Through
Groovy Fly ThroughGroovy Fly Through
Groovy Fly Through
 
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
Map/reduce, geospatial indexing, and other cool features (Kristina Chodorow)
 
Introduction to Scalding and Monoids
Introduction to Scalding and MonoidsIntroduction to Scalding and Monoids
Introduction to Scalding and Monoids
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New Tricks
 

Recently uploaded

FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
Aftab Hussain
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
Alpen-Adria-Universität
 
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
Neo4j
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
sonjaschweigert1
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
Neo4j
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
KatiaHIMEUR1
 
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
Neo4j
 
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionGenerative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Aggregage
 
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Nexer Digital
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Albert Hoitingh
 
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdfSAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
Peter Spielvogel
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 

Recently uploaded (20)

FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
 
Video Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the FutureVideo Streaming: Then, Now, and in the Future
Video Streaming: Then, Now, and in the Future
 
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...A tale of scale & speed: How the US Navy is enabling software delivery from l...
A tale of scale & speed: How the US Navy is enabling software delivery from l...
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
 
Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !Securing your Kubernetes cluster_ a step-by-step guide to success !
Securing your Kubernetes cluster_ a step-by-step guide to success !
 
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
 
Generative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to ProductionGenerative AI Deep Dive: Advancing from Proof of Concept to Production
Generative AI Deep Dive: Advancing from Proof of Concept to Production
 
Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?Elizabeth Buie - Older adults: Are we really designing for our future selves?
Elizabeth Buie - Older adults: Are we really designing for our future selves?
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
 
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdfSAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
SAP Sapphire 2024 - ASUG301 building better apps with SAP Fiori.pdf
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 

(Greach 2015) Dsl'ing your Groovy

  • 2.
  • 3.
  • 5.
  • 6.
  • 8. a Domain Specific Language is a programming language that offers, through appropriate notations and abstractions, expressive power focused on a particular problem domain.
  • 9. a Domain Specific Language is a programming language that offers, through appropriate notations and abstractions, expressive power focused on a particular problem domain.
  • 10. Expressive abstractions and notations for a particular problem
  • 11. A code snippet is worth a thousand images
  • 13. log4j.main = { error 'org.codehaus.groovy.grails.web.servlet', 'org.codehaus.groovy.grails.web.pages', 'org.codehaus.groovy.grails.web.sitemesh', 'org.codehaus.groovy.grails.web.mapping.filter', 'org.codehaus.groovy.grails.web.mapping', 'org.codehaus.groovy.grails.commons', 'org.codehaus.groovy.grails.plugins', 'org.codehaus.groovy.grails.orm.hibernate', 'org.springframework', 'org.hibernate', 'net.sf.ehcache.hibernate' debug 'myapp.core', }
  • 14. class User { ... static constraints = { login size: 5..15, blank: false, unique: true password size: 5..15, blank: false email email: true, blank: false age min: 18 } }
  • 16. def results = Account.createCriteria() { between "balance", 500, 1000 eq "branch", "London" or { like "holderFirstName", "Fred%" like "holderFirstName", "Barney%" } maxResults 10 order "holderLastName", "desc" }
  • 18. class MathSpec extends Specification { def "maximum of two numbers"() { expect: Math.max(a, b) == c where: a | b || c 3 | 5 || 5 7 | 0 || 7 0 | 0 || 0 } }
  • 20. apply plugin: 'groovy' sourceCompatibility = 1.8 targetCompatibility = 1.8 repositories { mavenLocal() jcenter() } dependencies { compile 'org.codehaus.groovy:groovy-all:2.4.1' testCompile 'org.spockframework:spock-core:0.7-groovy-2.0' testCompile 'junit:junit:4.11' }
  • 21. How cool is that?
  • 22. But only “them” can do those things
  • 23.
  • 24. 1. Closures 2. Builders 3. Open Classes 4. AST 5. Script TOC
  • 27. dependencies { compile 'org.codehaus.groovy:groovy-all:2.4.1' testCompile 'org.spockframework:spock-core:0.7-groovy-2.0' testCompile 'junit:junit:4.11' } dependencies({ compile('org.codehaus.groovy:groovy-all:2.4.1') testCompile('org.spockframework:spock-core:0.7-groovy-2.0') testCompile('junit:junit:4.11') })
  • 28. ▸ Optional parentheses ▸ Getter / setters GROOVY NICETIES
  • 29. sourceCompatibility = 1.8 targetCompatibility = 1.8 void setSourceCompatibility(version) { ... } void setTargetCompatibility(version) { ... }
  • 30. def sourceVersion = script.sourceCompatibility def targetVersion = script.targetCompatibility def getSourceCompatibility() { ... } def getTargetCompatibility() { ... }
  • 31. ▸ Optional parentheses ▸ Getter / setters ▸ Operator overloading GROOVY NICETIES
  • 32. Operator Method + a.plus(b) - a.minus(b) * a.multiply(b) / a.div(b) % a.mod(b) ** a.power(b) | a.or(b) & a.and(b) ^ a.xor(b) Operator Method a[b] a.getAt(b) a[b] = c a.putAt(b, c) << a.leftShift(b) >> a.rightShift(b) ++ a.next() -- a.previous() +a a.positive() -a a.negative() ~a a.bitwiseNegative()
  • 33. ▸ Optional parentheses ▸ Getter / setters ▸ Operator overloading ▸ Keyword arguments GROOVY NICETIES
  • 34. def myKeyArgs(Map keyargs=[:], String value1, String value2) { ... } myKeyArgs("value1", "value2") myKeyArgs("value1", "value2", cache: true) myKeyArgs("value1", "value2", drop: 20, take: 50)
  • 35. ▸ Optional parentheses ▸ Getter / setters ▸ Operator overloading ▸ Keyword arguments ▸ Closure arguments GROOVY NICETIES
  • 36. def myClosureArg(String value1, String value2, Closure cls=null) { ... } myClosureArg("value1", "value2") myClosureArg("value1", "value2") { println ">> Calling inside closure" }
  • 37. ▸ Optional parentheses ▸ Getter / setters ▸ Operator overloading ▸ Keyword arguments ▸ Closure arguments ▸ Command chaining GROOVY NICETIES
  • 38. take 2.pills of chloroquinine after 6.hours take(2.pills).of(chloroquinine).after(6.hours) paint(wall).with(red, green).and(yellow) paint wall with red, green and yellow given({}).when({}).then({}) given { } when { } then { }
  • 39. Now, let’s talk business
  • 41. ▸ DSL inside a closure CLOSURE DSL’s emailService.send { from 'grumpy@cat.com' to 'keyboard@cat.com' subject 'Check this video out!' body { p 'Really awesome!' } }
  • 42. ▸ DSL inside a closure CLOSURE DSL’s emailService.send { from 'grumpy@cat.com' to 'keyboard@cat.com' subject 'Check this video out!' body { p 'Really awesome!' } } Method invocation. Where are these methods?
  • 43. ▸ this ▸ owner ▸ delegate GROOVY CLOSURES CONTEXT Three objects handle the closure context
  • 44. ▸ this ▸ owner ▸ delegate GROOVY CLOSURES CONTEXT Normaly handles the context (default)
  • 45. ▸ this ▸ owner ▸ delegate GROOVY CLOSURES CONTEXT Only changes for nested closures
  • 46. ▸ this ▸ owner ▸ delegate GROOVY CLOSURES CONTEXT Can be changed!
  • 47. ▸ The handler will be called CLOSURE DSL’s class EmailHandler { void from(String value) { } void to(String value) { } void subject(String value) { } void body(Closure body) { } Map buildData() { } }
  • 48. ▸ Set the handler as delegate CLOSURE DSL’s def send(Closure dsl) { def handler = new EmailHandler() def code = cls.rehydrate(handler, null, null) code.resolveStrategy = Closure.DELEGATE_ONLY code.call() def emailData = handler.buildData() }
  • 49. ▸ Set the handler as delegate CLOSURE DSL’s def send(Closure dsl) { def handler = new EmailHandler() def code = cls.rehydrate(handler, null, null) code.resolveStrategy = Closure.DELEGATE_ONLY code.call() def emailData = handler.buildData() } delegate owner this
  • 50. ▸ Set the handler as delegate CLOSURE DSL’s def send(Closure dsl) { def handler = new EmailHandler() def code = cls.rehydrate(handler, null, null) code.resolveStrategy = Closure.DELEGATE_ONLY code.call() def emailData = handler.buildData() } Disable unexpected interactions
  • 51. ▸ Set the handler as delegate CLOSURE DSL’s def send(Closure dsl) { def handler = new EmailHandler() def code = cls.rehydrate(handler, null, null) code.resolveStrategy = Closure.DELEGATE_ONLY code.call() def emailData = handler.buildData() } Call the NEW closure
  • 52. ▸ Set the handler as delegate CLOSURE DSL’s def send(Closure dsl) { def handler = new EmailHandler() def code = cls.rehydrate(handler, null, null) code.resolveStrategy = Closure.DELEGATE_ONLY code.call() def emailData = handler.buildData() } The handler now contains the data
  • 53. ▸ All closure’s method/properties calls will call a delegate ▸ Build around the delegate and then retrieve the data CLOSURE DSL’s
  • 55. ▸ Problem: Complex nested structures BUILDER DSL’s def bookshelf = builder.bookshelf { author("George R. R. Martin") { books { "A Game Of Thrones" { pages 1000 characters 57 houses { stark { motto "Winter is comming" } } } } } }
  • 56. ▸ Problem: Complex nested structures BUILDER DSL’s def bookshelf = builder.bookshelf { author("George R. R. Martin") { books { "A Game Of Thrones" { pages 1000 characters 57 houses { stark { motto "Winter is comming" } } } } } } Delegate HELL
  • 57. ▸ Groovy provides support for this type of DSL ▸ groovy.util.BuilderSupport BUILDER DSL’s
  • 58. ▸ Defines a tree-like structure BUILDER DSL’s class BinaryTreeBuilderSupport extends BuilderSupport { def createNode(def name, Map attributes, def value) { new Container(name: name, attributes: attributes, value: value) } void setParent(def parent, def child) { parent.items.push(child) } ... }
  • 59. ▸ Defines a tree-like structure BUILDER DSL’s class BinaryTreeBuilderSupport extends BuilderSupport { def createNode(def name, Map attributes, def value) { new Container(name: name, attributes: attributes, value: value) } void setParent(def parent, def child) { parent.items.push(child) } ... } Create Nodes
  • 60. ▸ Defines a tree-like structure BUILDER DSL’s class BinaryTreeBuilderSupport extends BuilderSupport { def createNode(def name, Map attributes, def value) { new Container(name: name, attributes: attributes, value: value) } void setParent(def parent, def child) { parent.items.push(child) } ... } Define parent-children relationship
  • 61. ▸ Profit BUILDER DSL’s def bookshelf = builder.bookshelf { author("George R. R. Martin") { books { "A Game Of Thrones" { ... } ... } } } println bookshelf.items[0].items[0].items.name >>> [“A Game of Thrones”, ...]
  • 62. ▸ You can use the BuilderSupport when you have complex tree-like structures ▸ Only have to create nodes and relationships between them BUILDER DSL’s
  • 64. ▸ Groovy “standard” types can be extended OPEN CLASSES DSL’s Integer.metaClass.randomTimes = { Closure cls-> def randomValue = (new Random().nextInt(delegate)) +1 randomValue.times(cls) } Adding the method “randomTimes” to ALL the Integers
  • 65. ▸ Groovy “standard” types can be extended OPEN CLASSES DSL’s Integer.metaClass.randomTimes = { Closure cls-> def randomValue = (new Random().nextInt(delegate)) +1 randomValue.times(cls) } delegate has the Integer’s value
  • 66. ▸ Groovy “standard” types can be extended OPEN CLASSES DSL’s Integer.metaClass.randomTimes = { Closure cls-> def randomValue = (new Random().nextInt(delegate)) +1 randomValue.times(cls) } Repeat a random number of times the closure
  • 67. ▸ Groovy “standard” types can be extended OPEN CLASSES DSL’s Integer.metaClass.randomTimes = { Closure cls-> def randomValue = (new Random().nextInt(delegate)) +1 randomValue.times(cls) } 10.randomTimes { println "x" }
  • 68. ▸ Allows us to create nice DSL’s OPEN CLASSES DSL’s def order = buy 10.bottles of "milk"
  • 69. ▸ Allows us to create nice DSL’s OPEN CLASSES DSL’s def order = buy 10.bottles of "milk" Integer.metaClass.getBottles = { return new Quantity(quantity: delegate, ontainer: "bottle") }
  • 71. ▸ Problem: The language isn’t flexible enough for your taste AST DSL’s class MathSpec extends Specification { def "maximum of two numbers"() { expect: Math.max(a, b) == c where: a | b || c 3 | 5 || 5 7 | 0 || 7 0 | 0 || 0 } }
  • 72. ▸ Problem: The language isn’t flexible enough for your taste AST DSL’s class MathSpec extends Specification { def "maximum of two numbers"() { expect: Math.max(a, b) == c where: a | b || c 3 | 5 || 5 7 | 0 || 7 0 | 0 || 0 } } What???!!!!
  • 73. ▸ With AST’s you can modify the language on compile time ▸ BUT you have to respect the syntax AST DSL’s
  • 74. AST DSL’s where: a | b || c 3 | 5 || 5 7 | 0 || 7 0 | 0 || 0 Bit-level OR Logical OR
  • 75. ▸ We can do the same AST DSL’s class Main { @SpockTable def getTable() { value1 | value2 | value3 || max 1 | 2 | 3 || 3 2 | 1 | 0 || 2 2 | 2 | 1 || 2 } public static void main(def args) { def tableData = new Main().getTable() assert tableData['value1'] == [1, 2, 2] } }
  • 76. ▸ We can do the same OPEN CLASSES DSL’s class Main { @SpockTable def getTable() { value1 | value2 | value3 || max 1 | 2 | 3 || 3 2 | 1 | 0 || 2 2 | 2 | 1 || 2 } public static void main(def args) { def tableData = new Main().getTable() assert tableData['value1'] == [1, 2, 2] } } Local AST
  • 77. ▸ What kind of transformation we want? AST DSL’s def getTable() { value1 | value2 | value3 || max 1 | 2 | 3 || 3 2 | 1 | 0 || 2 2 | 2 | 1 || 2 } def getTablePostAST() { [ value1 : [1, 2, 2], value2 : [2, 1, 2], value3 : [3, 0, 1], max : [3, 2, 2] ] }
  • 79. ▸ Have to convert from one AST to the other AST DSL’s void visit(ASTNode[] nodes, SourceUnit sourceUnit) { MethodNode method = (MethodNode) nodes[1] def existingStatements = ((BlockStatement)method.code).statements def headers = processTableHeaders(existingStatements[0]) def mapToSet = processTableBody(headers, existingStatements[1..-1]) def mapExpression = createMapStatement(mapToSet) existingStatements.clear() existingStatements.add(mapExpression) }
  • 80. ▸ Have to convert from one AST to the other AST DSL’s void visit(ASTNode[] nodes, SourceUnit sourceUnit) { MethodNode method = (MethodNode) nodes[1] def existingStatements = ((BlockStatement)method.code).statements def headers = processTableHeaders(existingStatements[0]) def mapToSet = processTableBody(headers, existingStatements[1..-1]) def mapExpression = createMapStatement(mapToSet) existingStatements.clear() existingStatements.add(mapExpression) } Retrieves all the method statements
  • 81. ▸ Have to convert from one AST to the other AST DSL’s void visit(ASTNode[] nodes, SourceUnit sourceUnit) { MethodNode method = (MethodNode) nodes[1] def existingStatements = ((BlockStatement)method.code).statements def headers = processTableHeaders(existingStatements[0]) def mapToSet = processTableBody(headers, existingStatements[1..-1]) def mapExpression = createMapStatement(mapToSet) existingStatements.clear() existingStatements.add(mapExpression) } The first will be the header of our table
  • 82. ▸ Have to convert from one AST to the other AST DSL’s void visit(ASTNode[] nodes, SourceUnit sourceUnit) { MethodNode method = (MethodNode) nodes[1] def existingStatements = ((BlockStatement)method.code).statements def headers = processTableHeaders(existingStatements[0]) def mapToSet = processTableBody(headers, existingStatements[1..-1]) def mapExpression = createMapStatement(mapToSet) existingStatements.clear() existingStatements.add(mapExpression) } The rest will be the different values for the table body
  • 83. ▸ Have to convert from one AST to the other AST DSL’s void visit(ASTNode[] nodes, SourceUnit sourceUnit) { MethodNode method = (MethodNode) nodes[1] def existingStatements = ((BlockStatement)method.code).statements def headers = processTableHeaders(existingStatements[0]) def mapToSet = processTableBody(headers, existingStatements[1..-1]) def mapExpression = createMapStatement(mapToSet) existingStatements.clear() existingStatements.add(mapExpression) } With this values we create new code for this method body
  • 84. ▸ Have to convert from one AST to the other AST DSL’s void visit(ASTNode[] nodes, SourceUnit sourceUnit) { MethodNode method = (MethodNode) nodes[1] def existingStatements = ((BlockStatement)method.code).statements def headers = processTableHeaders(existingStatements[0]) def mapToSet = processTableBody(headers, existingStatements[1..-1]) def mapExpression = createMapStatement(mapToSet) existingStatements.clear() existingStatements.add(mapExpression) } Delete all the old one
  • 85. ▸ Have to convert from one AST to the other AST DSL’s void visit(ASTNode[] nodes, SourceUnit sourceUnit) { MethodNode method = (MethodNode) nodes[1] def existingStatements = ((BlockStatement)method.code).statements def headers = processTableHeaders(existingStatements[0]) def mapToSet = processTableBody(headers, existingStatements[1..-1]) def mapExpression = createMapStatement(mapToSet) existingStatements.clear() existingStatements.add(mapExpression) } Replace with the new code
  • 86. ▸ Try your DSL syntax on groovyConsole ▸ Check the “source” AST and the “target” AST ▸ Think about how to convert from one to another AST DSL’s
  • 89. ▸ All these techniques with external scripts SCRIPTING DSL’s apply plugin: 'groovy' sourceCompatibility = 1.8 targetCompatibility = 1.8 repositories { mavenLocal() jcenter() } dependencies { compile 'org.codehaus.groovy:groovy-all:2.4.1' testCompile 'junit:junit:4.11' }
  • 90. ▸ All these techniques with external scripts SCRIPTING DSL’s apply plugin: 'groovy' sourceCompatibility = 1.8 targetCompatibility = 1.8 repositories { mavenLocal() jcenter() } dependencies { compile 'org.codehaus.groovy:groovy-all:2.4.1' testCompile 'junit:junit:4.11' } Properties Method calls
  • 91. ▸ Script binding to a map SCRIPTING DSL’s def binding = new Binding( apply: { Map args -> println args}, repositories: { Closure dsl -> println "repositories"}, dependencies: { Closure dsl -> println "dependencies" } ) def shell = new GroovyShell(binding) shell.evaluate(new File("build.gradle"))
  • 92. ▸ We want a state for these methods SCRIPTING DSL’s class MyGradle { void apply(Map toApply) { ... } void repositories(Closure dslRepositories) { ... } void dependencies(Closure dslDependencies) { ... } }
  • 93. ▸ Script binding to an object SCRIPTING DSL’s def configuration = new CompilerConfiguration() configuration.setScriptBaseClass(DelegatingScript.class.getName()) def shell = new GroovyShell(new Binding(),configuration) def script = shell.parse(new File("build.gradle")) script.setDelegate(new MyGradle()) script.run()
  • 94. ▸ Script binding to an object SCRIPTING DSL’s def configuration = new CompilerConfiguration() configuration.setScriptBaseClass(DelegatingScript.class.getName()) def shell = new GroovyShell(new Binding(),configuration) def script = shell.parse(new File("build.gradle")) script.setDelegate(new MyGradle()) script.run() Type of Script
  • 95. ▸ Script binding to an object SCRIPTING DSL’s def configuration = new CompilerConfiguration() configuration.setScriptBaseClass(DelegatingScript.class.getName()) def shell = new GroovyShell(new Binding(),configuration) def script = shell.parse(new File("build.gradle")) script.setDelegate(new MyGradle()) script.run() Set our delegate
  • 96. ▸ Default imports SCRIPTING DSL’s def configuration = new CompilerConfiguration() def imports = new ImportCustomizer() imports.addStaticStar('java.util.Calendar') configuration.addCompilationCustomizers(imports)
  • 97. ▸ Default imports SCRIPTING DSL’s def configuration = new CompilerConfiguration() def imports = new ImportCustomizer() imports.addStaticStar('java.util.Calendar') configuration.addCompilationCustomizers(imports) import static from java.util.Calendar.*
  • 98. ▸ Apply AST Transformations SCRIPTING DSL’s def configuration = new CompilerConfiguration() def ast = new ASTTransformationCustomizer(Log) configuration.addCompilationCustomizers(ast)
  • 99. ▸ Apply AST Transformations SCRIPTING DSL’s def configuration = new CompilerConfiguration() def ast = new ASTTransformationCustomizer(Log) configuration.addCompilationCustomizers(ast) AST to apply inside the script
  • 100. ▸ Sanitize user input SCRIPTING DSL’s def configuration = new CompilerConfiguration() def secure = new SecureASTCustomizer() secure.methodDefinitionAllowed = false configuration.addCompilationCustomizers(secure)
  • 101. ▸ Sanitize user input SCRIPTING DSL’s def configuration = new CompilerConfiguration() def secure = new SecureASTCustomizer() secure.methodDefinitionAllowed = false configuration.addCompilationCustomizers(secure) We don’t allow method definitions in the script
  • 102. 1. Closures 2. Builders 3. Open Classes 4. AST 5. Script