Search code examples
grailsgroovy

Groovy syntax, named block?


I'm starting to learn grails and there is some groovy syntax that I don't get at all, and is undocumented as far as I can tell because I don't know what it's called.

What are 'grails', 'views', and 'gsp' in the code below?

    grails {
      views {
        gsp { 
          encoding = 'UTF-8'
          // ...
        }
      }
    }

Thanks! p.s. I feel like an idiot for not being able to figure this out...


Solution

  • This is an example of DSL (domain specific language) code. In Groovy, many DSLs are implemented as Groovy code, although sometimes it can look pretty funky. This code block is run as Groovy code, and it's more clear that it's code if you add in the omitted optional parentheses:

    grails({
       views({
          gsp({ 
             encoding = 'UTF-8'
             // ...
          })
       })
    })
    

    and more so if we replace the property set call to the equivalent method call

    grails({
       views({
          gsp({ 
             setEncoding('UTF-8')
             // ...
          })
       })
    })
    

    If you ran this in a console or as part of other Groovy code or in a Grails app it would fail, because there's no 'grails' method taking a closure as an argument, or a similar 'views' or 'gsp' method, and there's no setEncoding(String) method either. But when run as DSL code, often the code is run inside a closure whose delegate is set to a DSL helper class that handles the resulting methodMissing and propertyMissing calls.

    This helper looks at the method name and the number and/or types of the method arguments (or property name and value type) and if they are valid for the DSL, it does the corresponding work, otherwise it throws a MissingMethodException/MissingPropertyException, or a DSL-specific exception, or handles the problem some other way.

    In this case, there's a configuration DSL handler that translates these method calls into config property calls.

    There are several other DSLs in use in a Grails app that work the same way. The mapping and constraints blocks in domain classes, the grails.project.dependency.resolution block in BuildConfig.groovy, etc. All are evaluated as Groovy code, and the missing method/property calls configure GORM mappings, constraint definitions, plugin dependencies, etc.

    Programming Groovy 2 is a particularly good Groovy book for learning DSLs.