Groovy for Domain-specific Languages - Second Edition

(nextflipdebug2) #1

Example DSL – GeeTwitter


[ 126 ]

Even the one useful line in the Java version is burdened with boilerplate. We have
to explicitly write System.out.println to say that we are using the System class
to print to the standard output. In Groovy, this is all just assumed. When we write
Groovy, we embed mini DSLs within our code all the time, and surround it with
these types of regular Groovy and Java-like structures. The fact that we are using the
mini dialect of Groovy is hidden because the cool stuff gets hidden among other
not-so-cool boilerplate code.


What if we would like a non-Groovy or non-Java programmer to use our DSL?
Ideally, we just want to document how to use the DSL features, and not the
boilerplate that goes with it. Otherwise, we would find ourselves saying to our users,
"Trust me, just write this line of code and it will work... don't worry about what it
does." Unfortunately, that's not what happens in practice. Boilerplate will always be
a source of confusion and mistakes; so the less of it we have the better.


When we write something like the following in isolation of the boilerplate, we
are actually getting towards a dialect that could be written by a non-Groovy
programmer:


eachFriend {
println it
}

The goal now should be to remove as much of the boilerplate code as possible from
our scripts.


Refactoring


The next steps we take with our DSL are refactorings to remove boilerplate. Our
previous examples have all implemented methods locally within the script. This
clearly needs to change, so our first step will be to refactor these methods into a
standalone class. This class will become the main class for our DSL. We'll call the
class GeeTwitter.


We need to consider how we would like our users to access the methods in our class.
By default, the methods that we add to a class are instance methods and are only
accessible through an instance of the class. If we define login and search methods
in our class, as shown in the following code, the user of the DSL must first create a
new instance of the GeeTwitter class before they can use them:


import twitter4j.*

class GeeTwitter {
void search(terms) {
def query = new Query(terms)

http://www.ebook3000.com
Free download pdf