5
votes

I have trouble understanding the groovy syntax in gradle.

If named parameters (in groovy) are using the : suffix, then I assume that the code apply plugin: 'java' means to call the function apply(plugin = 'java'). This is strange because the function apply is not even defined. The following gives me an error in my gradle script:

println apply.getClass()
> Could not get unknown property 'apply' for root project 'Simple' of type 
org.gradle.api.Project.

So what is apply and where is it defined? Why doesn't the code above just print the class of the apply element?

And one other thing that is strange to me is the following:

dependencies {
    compile 'org.slf4j:slf4j-api:1.7.12'
    testCompile 'junit:junit:4.12'
}

The syntax suggests that the code wrapped in {} is a closure, but what are the compile and testCompile elements? If it was a closure, then the code above would just return 'junit:junit:4.12' as a string and the rest should fail to compile. It looks like it's more a definition of a map. But again, if the code above is data, then I should be able to enter it at the groovysh shell.

groovy:000> dependencies {
        compile 'org.slf4j:slf4j-api:1.7.12'
        testCompile 'junit:junit:4.12'
    }
groovy:001> groovy:002> groovy:003> ERROR groovy.lang.MissingMethodException:
No signature of method: groovysh_evaluate.dependencies() is applicable for argument types: (groovysh_evaluate$_run_closure1) values: [groovysh_evaluate$_run_closure1@b7c4869]

This is confusing to me. I thought that gradle scripts are just groovy scripts, but it seems that the gradle DSL adds element to the groovy language. A groovy clojure becomes a map, a function call with named parameters becomes something different.

Can someone enlighten me on this groovy DSL ;)

2
Just wondering, should that say a "groovy closure"? Just asking because I searched for "Clojure" questions and this came up. - Carcigenicate

2 Answers

3
votes
plugin: 'java' 

is a groovy map. See the Project.apply() documentation and the explanation for this syntax in the groovy documentation.

Regarding dependencies, see DependencyHandler.

Groovy is a very dynamic language, where you can actually call non-declared methods and have a handler do something based on the called method name. AFAIK, that's the trick used here. See the source code.

I'm not a groovy developer, and although I find the DSL elegant, I also find it confusing at times, because I find it hard to link some parts of the DSL to concrete methods in the documentation. But you end up understanding it and getting used to it.

2
votes

compile 'org.slf4j:slf4j-api:1.7.12' is not a map, it's a method invocation. In Groovy you can omit brackets, so the call is equivalent to

compile( 'org.slf4j:slf4j-api:1.7.12' ) 

Also such methods in Gradle can take the second argument:

compile( 'org.slf4j:slf4j-api:1.7.12' ){ exclude module:'log4j' }

In this case, the module:'log4j' is a map with omitted square brackets, and the call can be rewritten as

compile( 'org.slf4j:slf4j-api:1.7.12' ){ exclude( [module:'log4j'] ) }