2

I understand that the gradle DSL

task doTask { logger.info "some text" }

will actually call the method task(String,Closure) on the Project delegate object. It's more or less a short hand for

task("doTaks", {logger.info("some text")})

That's all fine. But things get complicated when I try to understand some gradle DSL syntax I've seen in third party build scripts:

task doTask (dependsOn: 'otherTask'){logger.info "some text"}

I figure that groovy will create a map from (dependsOn: 'otherTask'), and that somehow the Project method

task(Map args, String name, Closure config)

will be called. But how do these additional parentheses come into play, why are they necessary, how does groovy figure out what we want here? The syntax looks totally counter-intuitive to me with my minimal groovy skill. I would never guess that I have to do it this way to make it work.

So, that's the question: how does groovy figure out what to do with this command:

task doTask (dependsOn: 'otherTask'){ // some code }
doelleri
  • 19,232
  • 5
  • 61
  • 65
rexford
  • 5,192
  • 5
  • 27
  • 40
  • Gradle build scripts in groovy are a DSL, not plain groovy – tim_yates May 18 '19 at 21:34
  • https://stackoverflow.com/questions/38627258/gradle-task-method-syntax-in-build-gradle – tim_yates May 18 '19 at 21:36
  • @tim_yates: thanks for linking to the other question. The answers there do not add anything new to my question, so I would not consider it a duplicate though the difference is really in the nuances. Marco R.'s response below actually solves my problem. – rexford May 18 '19 at 23:03

1 Answers1

1

You can invoke groovy methods using one the following syntaxes:

  1. Args must be all comma separated within parenthesis:

     method(arg1, arg2, ..., argN, argClosure)
    
  2. Args must be all comma separated without parenthesis:

     method arg1, arg2, ..., argN, argClosure
    
  3. If the last argument is a closure, all previous args must be all comma separated within parenthesis, and the code block (within braces {...}) following the closing parenthesis will be interpreted as the last Closure argument argClosure:

     method(arg1, arg2, ..., argN) { ... }
    

    If you DO NOT want the code block within the curly braces to be interpreted as a Closure argument for the preceding method invocation; then end the method invocation with a semicolon:

     // Because of `;` following { ... } is not a Closure argument for `method`
     method(arg1, arg2, ..., argN); { ... }
    
  4. A method that accepts as an argument a single Map or a Map and a closure, may be invoked using the named parameters syntax; which will transform each named argument into an entry in the map and the last argument will be a closure. This will create the following intuitive syntactic variants:

     method(name1: arg1, name2: arg2, ..., nameN: argN, argClosure)
     method name1: arg1, name2: arg2, ..., nameN: argN, argClosure
     method(name1: arg1, name2: arg2, ..., nameN: argN) { ... }
    

Groovy provides tons of syntactic sugar, so other intuitive variants can be found around this; but this gives you the feeling for groovy's way of handling Closure arguments.

The following is a working demo of these different ways of doing a method invocation:

import java.time.LocalDateTime

def handleWithClosure(data1, data2, closure) {
    closure("$data1. $data2")
}

def logger = { println "${LocalDateTime.now()} - $it" }
handleWithClosure(1, 'All within parenthesis', logger)
handleWithClosure 2, 'All without parenthesis', logger
handleWithClosure(3, 'List of arguments within parenthesis and closure outside') { logger(it) }

def handleMapWithClosure(map, closure) {
    handleWithClosure(map['num'], "[Named Arguments/Map based] ${map['msg']}", closure)
}

handleMapWithClosure(msg: 'All within parenthesis', num: 1, logger)
handleMapWithClosure msg: 'All without parenthesis', num: 2, logger
handleMapWithClosure(msg: 'List of arguments within parenthesis and closure outside', num: 3) { logger(it) }

Running it you can see how it is treating all these syntactic options.

Complete code on GitHub

Hope this helps.

Marco R.
  • 2,667
  • 15
  • 33