SlideShare a Scribd company logo
1 of 104
Download to read offline
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 Pythonkwatch
 
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 LaforgeGR8Conf
 
Logic programming a ruby perspective
Logic programming a ruby perspectiveLogic programming a ruby perspective
Logic programming a ruby perspectiveNorman Richards
 
Grooscript gr8conf
Grooscript gr8confGrooscript gr8conf
Grooscript gr8confGR8Conf
 
Designing with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf IndiaDesigning with Groovy Traits - Gr8Conf India
Designing with Groovy Traits - Gr8Conf IndiaNaresha K
 
concurrency with GPars
concurrency with GParsconcurrency with GPars
concurrency with GParsPaul King
 
Turtle Graphics in Groovy
Turtle Graphics in GroovyTurtle Graphics in Groovy
Turtle Graphics in GroovyJim 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 explainedVaclav 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 2012aleks-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
 
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
 
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 minutosAlonso Torres
 
[Greach 2016] Down The RabbitMQ Hole
[Greach 2016] Down The RabbitMQ Hole[Greach 2016] Down The RabbitMQ Hole
[Greach 2016] Down The RabbitMQ HoleAlonso 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 MeetingAlonso Torres
 
Idiomatic gradle plugin writing
Idiomatic gradle plugin writingIdiomatic gradle plugin writing
Idiomatic gradle plugin writingSchalk 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 againAlonso 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 LanguagesGuillaume 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 DSL'ing YOUR CODE

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
 
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
 
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 StoryDatabricks
 
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 StoryDatabricks
 
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 181Mahmoud 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 29Bilal Ahmed
 
Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Groovy puzzlers по русски с Joker 2014
Groovy puzzlers по русски с Joker 2014Baruch 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 MonoidsHugo Gävert
 
Fun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksFun Teaching MongoDB New Tricks
Fun Teaching MongoDB New TricksMongoDB
 

Similar to DSL'ing YOUR CODE (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

Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessPixlogix Infotech
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Enterprise Knowledge
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 

Recently uploaded (20)

Advantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your BusinessAdvantages of Hiring UIUX Design Service Providers for Your Business
Advantages of Hiring UIUX Design Service Providers for Your Business
 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...Driving Behavioral Change for Information Management through Data-Driven Gree...
Driving Behavioral Change for Information Management through Data-Driven Gree...
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 

DSL'ing YOUR CODE

  • 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