What does this syntax mean in Groovy?
class CreateMessagePage extends Page {
static at = { assert title == 'Messages : Create'; true }
static url = 'messages/form'
static content = {
submit { $('input[type=submit]') }
MyVeryStrangeForm { $('form') }
errors(required:false) { $('label.error, .alert-error')?.text() }
}
}
(taken from Spring MVC Test HtmlUnit manual)
The question is about Groovy and I would like know the answer in Groovy terms.
What is content? Is it a static variable? Is its name is random or predefined by base class of Page?
What is = (equal sign) after it? Is it an assignment operator?
What is at the right hand side of =? Is this a closure? Or if this an anonymous class? Or if these are the same?
What is submit inside curly braces?
Is this a variable? Why there is no assignment operator after it then?
Is this a function definition? Can I define functions in arbitrary places in Groovy? If this is a function definition, then what is errors then?
Is submit is a function call, receiving { $('input[type=submit]') } as a parameter? If yes, then where is this function can be defined? For example, where is MyVeryStrangeForm defined (is nowhere)?
If this was function call, then it won't work since it's undefined...
Quick answer to all questions: it's a block of code, like anonymous function, called closure in Groovy.
See http://www.groovy-lang.org/closures.html
In Groovy you can reference/pass/set such closure, as in any Functional Language.
So this:
static at = { assert title == 'Messages : Create'; true }
means that class field at will be set to this closure (notice, not result of closure execution, but closure itself, as block of code). Type of at is omitted there, but it could be static def at or static Object at, or static Closure at
This code could be executed anytime later, in different context, with title defined, etc.
This:
submit { $('input[type=submit]') }
means calling a function submit with closure as argument.
If you want to write own function like this, it should be something like:
def submit(Closure code) {
code.call()
}
Brackets could be omitted, so it could be written as submit({$('input[type=submit]')}). Same for other function as well, it could be println 'hello world!' instead of println('hello world').
There's also a common practice to define closure as last argument, like:
def errors(Map opts, Closure code) {
....
}
at this case you could pass first arguments as usual, wrapped in brackets, and closure outside:
errors(required:false) { ...... }
same to:
errors([required: false], { ..... })
Related
In Groovy, if I have:
def say(msg = 'Hello', name = 'world') {
"$msg $name!"
}
And then call:
say() // Hello world!
say("hi") // Hi world!
say(null) // null world!
Why is the last one getting interpreted literally as null and not applying the default value? Doesn't this defeat the purpose of default method argument values? I do get that passing null is different from not passing anything w/r/t argument length.
My problem here is that if I now have a method that takes a collection as an argument:
def items(Set<String> items = []) {
new HashSet<>(items)
}
This will throw a NullPointerException if I call items(null) but work fine if I just say items(). In order for this to work right, I have to change the line to be new HashSet<>(items ?: []) which, again, seems to defeat the entire purpose of having default method argument values.
What am I missing here?
In Groovy, default parameters generates overloaded methods. Thus, this:
def items(Set<String> items = []) {
new HashSet<>(items)
}
Will generate these two methods (I used javap to get these values):
public java.lang.Object items(java.util.Set<java.lang.String>);
public java.lang.Object items();
So when you call items(null) you are, in fact, passing some value, and items(Set) method will be used.
You can also refer to this question about default parameters.
I'm new to Gradle/Groovy and am running into issues with variable name resolution in nested closures. I have a custom task class that defines some properties and I am instantiating potentially multiple tasks of that type using a closure. This closure defines a variable named the same as one of the properties in the custom task class and I am running into some odd behavior which seems to go against what is defined in the Groovy language guide. Could someone please answer the questions in the code below?
class Something extends DefaultTask {
def thing = "a"
}
/*
def thing = "b" // produces the error message:
// > Could not find method b() for arguments [build_63hfhkn4xq8gcqdsf98mf9qak$_run_closure1#70805a56] on root project 'gradle-test'.
// ...why?
*/
(1..1).each {
def thing = "c"
task ("someTask${it}", type: Something) {
println resolveStrategy == Closure.DELEGATE_FIRST // prints "true"
println delegate.class // prints "class Something_Decorated"
println thing // prints "c" shouldn't this be "a" since it's using DELEGATE_FIRST?
/*
println owner.thing // produces the error message:
// > Could not find property 'thing' on root project 'gradle-test'
// shouldn't the "owner" of this closure be the enclosing closure?
// in that case shouldn't this resolve to "c"
*/
}
}
EDIT:
For some reason after changing all of the def into String and then back into def I can no longer replicate the def thing = "b" line producing that weird error
The code prints c because the variable named thing is declared within the lexical scope of the closure. It means that closure can just use the value of this variable. What will work:
Renaming the thing variable defined in the closure.
Explicitly referring to thing via delegate:
println delegate.thing
I have a DSL where, if present, a closure called before will be called before every command.
In my setup I have 3 files: The script itself - Script, a ScriptBase, that is 'attached' to the script via a CompilerConfiguration, and a Handler.
In the script I may or may not have a closure called before.
before = {
//Do stuff.
}
Notice the lack of a type declaration, or def. If I understand Groovy correctly, this means that before is a in the binding, and accessible from outside code when evaluated with GroovyShell.evaluate().
In the ScriptBase I do the following:
class ProductSpecificationBase extends Script {
def before = null
}
This script base may or may not be overridden later on.
Then, in the Handler, I'm doing a check for whether a before closure is defined in the script:
def config = new CompilerConfiguration()
config.setScriptBaseClass(ScriptBase.class.name)
def shell = GroovyShell()
evaluatedScript = shell.evaluate(new File(thePathToScript))
if (evaluatedScript.before) {
theEvaluationOfMyScript.before()
}
The code works as expected if the script does contain a before closure, but if it doesn't it returns a MissingPropertyException. I've had a look at what this means, and it seems that my before in the ScriptBase isn't considered a property, and all the examples of using these ScriptBases I've found on the internet give examples of using methods. This is not feasible for my use case I'm afraid. How can I ensure that the closure in the ScriptBase is considered a property instead of a field(as I am assuming it is now).
To be paraphrase: I would like my code to not execute the if block if the script does not contain a before closure as well as not having been overridden in an extension of the ScriptBase. However, I would like the evaluation of evaluatedScript.before to be false as it is an empty/null Closure (i.e. it went all the way up to ScriptBase, and found the null closure)
I like to avoid a try/catch approach if possible.
in your example you would basically call the getter for the before property. To check, if there is a method with the name (and params) check with respondsTo. To see, if there is a property at all with that name use hasProperty (Thanks #dmahapatro for pointing this out)
class X {
void before() { println 'x' }
}
class Y { }
class Z {
def before = { println 'z' }
}
def x = new X()
def y = new Y()
def z = new Z()
assert x.respondsTo('before', null)
assert !y.respondsTo('before', null)
assert !z.respondsTo('before', null)
assert !x.hasProperty('before')
assert !y.hasProperty('before')
assert z.hasProperty('before')
x.before()
z.before()
I need to mock a static method. I'm using the EMC approach described at Mocking static methods using groovy. Like this
TestDaemon.metaClass.'static'.newDownloadManager = {downloadManager}
The method newDownloadManager has no parameters and for some reason it is not replaced. The original code is called. In debug mode I can see that the closure that I define has a parameter. May be that's the reason? How can I define a closure without parameters? Or how can I mock a static method with no parameters?
Meta class changes aren't visible to Java code. Groovy can't help you to mock a static method that gets called from Java code. You will have to use something like JMockit instead (or refactor the code under test).
A closure written like that has an implicit parameter. Write the closure with { -> } syntax. Example:
x = { println "foo" }
y = { -> println "foo" }
assert x.parameterTypes as List == [Object]
assert y.parameterTypes as List == []
Code inside closures can refer to it variable.
8.times { println it }
or
def mywith(Closure closure) {
closure()
}
mywith { println it }
With this behavior in mind you can't expect following code to print 0011
2.times {
println it
mywith {
println it
}
}
And instead I have to write
2.times { i ->
println i
mywith {
println i
}
}
My question is: why closures without parameters override it variable even if they don't need it.
If you define a closure like this
def closure = {println "i am a closure"}
It appears to have no parameters, but actually it has one implicit parameter named it. This is confirmed by:
def closure = {println "i am a closure with arg $it"}
closure("foo")
which prints
"i am a closure with arg foo"
If you really want to define a closure that takes 0 parameters, use this:
def closure = {-> println "i am a closure"}
Your example could therefore be rewritten as:
2.times {
println it
mywith {->
println it
}
}
I think it has something to do with the formal Closure definition of Groovy:
Closures may have 1...N arguments,
which may be statically typed or
untyped. The first parameter is
available via an implicit untyped
argument named it if no explicit
arguments are named. If the caller
does not specify any arguments, the
first parameter (and, by extension,
it) will be null.
That means that a Groovy Closure will always have at least one argument, called it (if not specified otherwise) and it will be null if not given as a parameter.
The second example uses the scope of the enclosing closure instead.