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 groovy
Paul King
 
Polyglot Programming in the JVM
Polyglot Programming in the JVMPolyglot Programming in the JVM
Polyglot Programming in the JVM
Andres 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 Experience
Alexander 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

Practical Groovy DSL
Practical Groovy DSLPractical Groovy DSL
Practical Groovy DSL
Guillaume Laforge
 
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 Approaches
Ross 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 Cassandra
Deependra 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
 
Latinoware
LatinowareLatinoware
Latinoware
kchodorow
 
Metaprogramovanie #1
Metaprogramovanie #1Metaprogramovanie #1
Metaprogramovanie #1
Jano 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 Through
niklal
 
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

"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
Fwdays
 
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge GraphGraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
Neo4j
 
How to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdf
How to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdfHow to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdf
How to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdf
Chart Kalyan
 
Essentials of Automations: Exploring Attributes & Automation Parameters
Essentials of Automations: Exploring Attributes & Automation ParametersEssentials of Automations: Exploring Attributes & Automation Parameters
Essentials of Automations: Exploring Attributes & Automation Parameters
Safe Software
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
Zilliz
 
Mutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented ChatbotsMutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented Chatbots
Pablo Gómez Abajo
 
The Microsoft 365 Migration Tutorial For Beginner.pptx
The Microsoft 365 Migration Tutorial For Beginner.pptxThe Microsoft 365 Migration Tutorial For Beginner.pptx
The Microsoft 365 Migration Tutorial For Beginner.pptx
operationspcvita
 
Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |
AstuteBusiness
 
Digital Banking in the Cloud: How Citizens Bank Unlocked Their Mainframe
Digital Banking in the Cloud: How Citizens Bank Unlocked Their MainframeDigital Banking in the Cloud: How Citizens Bank Unlocked Their Mainframe
Digital Banking in the Cloud: How Citizens Bank Unlocked Their Mainframe
Precisely
 
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing InstancesEnergy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Alpen-Adria-Universität
 
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
Alex Pruden
 
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectorsConnector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
DianaGray10
 
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
saastr
 
5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides
DanBrown980551
 
Leveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and StandardsLeveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and Standards
Neo4j
 
June Patch Tuesday
June Patch TuesdayJune Patch Tuesday
June Patch Tuesday
Ivanti
 
Freshworks Rethinks NoSQL for Rapid Scaling & Cost-Efficiency
Freshworks Rethinks NoSQL for Rapid Scaling & Cost-EfficiencyFreshworks Rethinks NoSQL for Rapid Scaling & Cost-Efficiency
Freshworks Rethinks NoSQL for Rapid Scaling & Cost-Efficiency
ScyllaDB
 
Y-Combinator seed pitch deck template PP
Y-Combinator seed pitch deck template PPY-Combinator seed pitch deck template PP
Y-Combinator seed pitch deck template PP
c5vrf27qcz
 
Choosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptxChoosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptx
Brandon Minnick, MBA
 

Recently uploaded (20)

"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk"Frontline Battles with DDoS: Best practices and Lessons Learned",  Igor Ivaniuk
"Frontline Battles with DDoS: Best practices and Lessons Learned", Igor Ivaniuk
 
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge GraphGraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
GraphRAG for LifeSciences Hands-On with the Clinical Knowledge Graph
 
How to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdf
How to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdfHow to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdf
How to Interpret Trends in the Kalyan Rajdhani Mix Chart.pdf
 
Essentials of Automations: Exploring Attributes & Automation Parameters
Essentials of Automations: Exploring Attributes & Automation ParametersEssentials of Automations: Exploring Attributes & Automation Parameters
Essentials of Automations: Exploring Attributes & Automation Parameters
 
Generating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and MilvusGenerating privacy-protected synthetic data using Secludy and Milvus
Generating privacy-protected synthetic data using Secludy and Milvus
 
Mutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented ChatbotsMutation Testing for Task-Oriented Chatbots
Mutation Testing for Task-Oriented Chatbots
 
The Microsoft 365 Migration Tutorial For Beginner.pptx
The Microsoft 365 Migration Tutorial For Beginner.pptxThe Microsoft 365 Migration Tutorial For Beginner.pptx
The Microsoft 365 Migration Tutorial For Beginner.pptx
 
Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |Astute Business Solutions | Oracle Cloud Partner |
Astute Business Solutions | Oracle Cloud Partner |
 
Digital Banking in the Cloud: How Citizens Bank Unlocked Their Mainframe
Digital Banking in the Cloud: How Citizens Bank Unlocked Their MainframeDigital Banking in the Cloud: How Citizens Bank Unlocked Their Mainframe
Digital Banking in the Cloud: How Citizens Bank Unlocked Their Mainframe
 
Artificial Intelligence and Electronic Warfare
Artificial Intelligence and Electronic WarfareArtificial Intelligence and Electronic Warfare
Artificial Intelligence and Electronic Warfare
 
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing InstancesEnergy Efficient Video Encoding for Cloud and Edge Computing Instances
Energy Efficient Video Encoding for Cloud and Edge Computing Instances
 
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
zkStudyClub - LatticeFold: A Lattice-based Folding Scheme and its Application...
 
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectorsConnector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
Connector Corner: Seamlessly power UiPath Apps, GenAI with prebuilt connectors
 
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
9 CEO's who hit $100m ARR Share Their Top Growth Tactics Nathan Latka, Founde...
 
5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides5th LF Energy Power Grid Model Meet-up Slides
5th LF Energy Power Grid Model Meet-up Slides
 
Leveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and StandardsLeveraging the Graph for Clinical Trials and Standards
Leveraging the Graph for Clinical Trials and Standards
 
June Patch Tuesday
June Patch TuesdayJune Patch Tuesday
June Patch Tuesday
 
Freshworks Rethinks NoSQL for Rapid Scaling & Cost-Efficiency
Freshworks Rethinks NoSQL for Rapid Scaling & Cost-EfficiencyFreshworks Rethinks NoSQL for Rapid Scaling & Cost-Efficiency
Freshworks Rethinks NoSQL for Rapid Scaling & Cost-Efficiency
 
Y-Combinator seed pitch deck template PP
Y-Combinator seed pitch deck template PPY-Combinator seed pitch deck template PP
Y-Combinator seed pitch deck template PP
 
Choosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptxChoosing The Best AWS Service For Your Website + API.pptx
Choosing The Best AWS Service For Your Website + API.pptx
 

(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