apply plugin: 'groovy'
repositories {
jcenter()
mavenCentral()
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.4'
runtime 'org.postgresql:postgresql:9.4-1201-jdbc41'
}
Craig Burke
Groovy/Grails Developer at Carnegie Mellon
Creator of the Groovy Document Builder
www.craigburke.com
@craigburke1
Background and Definitions
A Domain Specific Language (DSL) is a computer programming language of limited expressiveness focused on a particular domain.
Makes use of the language and metaphors used by domain experts
apply plugin: 'groovy'
repositories {
jcenter()
mavenCentral()
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.4'
runtime 'org.postgresql:postgresql:9.4-1201-jdbc41'
}
INSERT INTO EMPLOYEE (ID, NAME) VALUES (1, 'Craig Burkee');
UPDATE EMPLOYEE SET NAME = 'Craig Burke' WHERE ID = 1;
SELECT ID, NAME FROM EMPLOYEE;
DELETE FROM EMPLOYEE WHERE ID = 1;
p {
font-size: 12px;
color: #B41F1F;
}
div.content {
width: 100%;
padding: 5px;
border: 1px solid #000000;
}
Simple Syntax (Less Noise)
Scripting Support
Operator Overloading
Meta-Programming
def map = [language: 'Groovy']
def list = ['foo', 'bar']
// equivilent to: say(hello).to('Craig')
say hello to 'Craig'
class Note {
static from(Map args, String name) {
println "${name} said ${args.message}"
}
}
Note.from 'Craig Burke', message: 'Hey, how are you?'
public class ScriptClass {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
println 'Hello World'
groovy script.groovy
a + b | a.plus(b) |
a - b | a.minus(b) |
a * b | a.multiply(b) |
a ** b | a.power(b) |
a / b | a.div(b) |
a % b | a.mod(b) |
a | b | a.or(b) |
a & b | a.and(b) |
a ^ b | a.xor(b) |
a or a | a.next() |
a-- or --a | a.previous() |
a << b | a.leftShift(b) |
a >> b | a.rightShift(b) |
a <⇒ b | a.compareTo(b) |
class Person {
String name
String nickName
}
Person person = new Person()
person.name = 'Craig'
println person.name
person.nickName = person.name
Number.metaClass.getDollars = { delegate as BigDecimal }
Number.metaClass.getProperty = { String name ->
def rates = [euros: 1.1f, pesos: 0.063f]
delegate * (rates[name] as BigDecimal)
}
def total = 20.dollars + 40.euros + 200.pesos
assert total == 76.60
class Person {
def methodMissing(String name, args) {
if (name.startsWith('say')) {
String message = (name - 'say').trim()
println message
}
}
}
Person you = new Person()
you.sayHello()
you."say Craig is Awesome"()
Closure myClosure = {
name = 'Craig'
printName()
}
class NamePrinter {
String name
void printName() {
println "My Name is ${name}!!!"
}
}
myClosure.delegate = new NamePrinter()
myClosure.resolveStrategy = Closure.DELEGATE_FIRST
myClosure()
(Not Really)
Comedy Albums Have Sold Millions
Voice of Dusty Crophopper from Planes
Estimated Net Worth of $30 million
Rides Around in a Sweet Lamborghini
'Dane Cook sucks'.watch { tweetedStatus ->
tweet 'Hey @DaneCook, somebody said this:' << tweetedStatus
tweet "LEAVE DANE ALONE, @${tweetedStatus.user.screenName}!!!"
}
Simple and Readable DSL for Document Creation
Use Same Code for Word or Pdf Documents
Shouldn’t Require Knowledge of a Complex Library
builder.generate {
paragraph 'OMFG! Look at the cat!'
picture kitty, [name: 'kitty.png', width: 354, height: 290]
paragraph 'That cat is amazing!!!'
}
class DocumentBuilder {
File file
Document(File file) {
this.file = file
}
void generate(Closure builder) {
builder.delegate = this
builder()
}
abstract void paragraph(String text)
abstract void picture(Map params = [:], byte[] data)
}
builder.generate {
paragraph 'Check out this table'
table {
row {
cell 'First Name'
cell 'Last Name'
}
row {
cell 'Craig'
cell 'Burke'
}
}
}
Closure Delegation
BuilderSupport
FactoryBuilderSupport
class MyBuilder extends BuilderSupport {
def createNode(name) { /* TODO */ }
def createNode(name, value) { /* TODO */ }
def createNode(name, Map attributes) { /* TODO */ }
def createNode(name, Map attributes, value) { /* TODO */ }
void setParent(parent, child) { /* TODO */ }
void nodeCompleted(parent, node) { /* TODO */ }
}
Now We’re Talking
class User {
String firstName
String lastName
Date birthDate
static constraints = {
firstName blank:false
lastName blank:false
birthDate nullable:false
}
}
class User {
String firstName
String lastName
Date birthDate
static constraints = {
firstName blank:false
lastName blank:false
birthDate nullable:false
}
}
class User {
String firstName
String lastName
Date birthDate
static Closure constraints = {
firstName([blank:false])
lastName([blank:false])
birthDate([nullable:false])
}
}
class User {
String firstName
String lastName
Date birthDate
static Closure constraints = {
Map nameConstrants = [blank:false]
['firstName', 'lastName'].each {
"${it}"(nameContraints)
}
delegate.birthDate([nullable:false])
}
}
Books
Domain-Specific Languages (Martin Fowler)
Groovy for Domain-Specific Languages (Fergal Dearle)
Presentations
Groovy Domain Specific Languages
DSL’ing your Groovy
Links
Domain-Specific Languages (Groovy Docs)