3

Tips And Resources For Creating DSLs in Groovy

 2 years ago
source link: https://blog.jakubholy.net/2011/11/13/tips-and-resources-for-creating-dlss-in-groovy/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Tips And Resources For Creating DSLs in Groovy

November 13, 2011

Paul King had a very good presentation (last year's slides) at JavaZone about why to use Domain-Specific Languages and how to create internal DSLs in Groovy. I'd like to list here few tips that he has mentioned but before we get to that, why would you want to create a DSL? Martin Fowler answers that in his Domain-Specific Languages book (2010). Some of the reasons are to have a higher-level, more focused and conscise representation that also domain experts can read and perhaps even write. You  have certainly already used a DSL such as regular expressions, CSS, SQL, Spock's BDD tests, build instructions in Gradle - these are rather technical but sometimes DSLs are also created to be used by business users, f.ex. for anti-malaria drug resistance simulation. (Want more DSLs in Groovy?).

Paul mentions one important thing - you can always make your DSL better, i.e. more fail-proof (case insensitive, support plural endings, ...) and secure and more like a natural language but it all comes at a cost and you must evaluate when the cost overweights the benefit (beware the 80:20 rule).

Some of the Groovy DSL implementation tips:

  • Add methods to any object/class via metaprogramming: <class|instance>.metaclass.<method name or getProperty> = {MyType param -> ... } - you can use 'delegate' to refer to the instance
  • notice that getProperty is called for anything that isn't a method as in map['key'] == map.key - useful to implement e.g. 1.kg
  • Call ExpandoMetaClass.enableGlobally() to propagate methods added to Number also to Integer etc.

Use a GroovyShell and a custom Binding subclass overriding getVariable(String symbol) so as to return/create an object for unknown "variables" (ex.: "newOrder" -> new Order(), creation of vars for symbols like "h", "km" etc. => 24.km/h)Operator overloading: methods of specific names are invoked for operators (/ -> div, * -> multiply etc.)Use a closure setting its delegate and configuring it the cosure's resolve strategy to delegate unknown methods further to the delegateCreate a custom Closure subclass and use that for a closure instead of the default oneUse Groovy's Categories (st. like a temporary mixin, activated via the use(category) { .. } form) to add localy methods to classesUse Groovy Builders for tree-like DSLs (builder <-> method calls that take a Closure as argument)Use map attributes to get st. resembling named atributesUse GroovyShell with a custom classloader and compilation phase something to prevent calls of other static and instance methods than allowed

Resources

PS: The latest release of Groovy in Action should also contain a chapter on DSLs.

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK