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.
Related
I am trying to evaluate string as code in groovy and it is failing with groovy.lang.MissingMethodException exception even though method exists in the same script. As I understood groovy runs new instance every time it tries to evaluate the code, but is there any way to inject current script into Eval.me or GroovyShell().evaluate() so that it can find the method and runs it ?
Below is sample code snippet,
def justSayHello(){
return "hello"
}
def my_str = "justSayHello()"
//Eval.me(my_func_str)
new GroovyShell().evaluate(my_func_str)
Both Eval and GroovyShell().evaluate() are throwing below exception
Caught: groovy.lang.MissingMethodException: No signature of method: Script1.justSayHello() is applicable for argument types: () values: []
groovy.lang.MissingMethodException: No signature of method: Script1.justSayHello() is applicable for argument types: () values: []
at Script1.run(Script1.groovy:1)
at string_split.run(string_split.groovy:35)
The following code:
justSayHello = {
println "hello"
}
def my_str = "justSayHello()"
new GroovyShell(binding).evaluate(my_str)
prints out hello when run. Here we have changed justSayHello from a method (on an implicit class that you can not see but which the groovy compiler generates around your script) to a closure. Further we are not doing def justSayHello as that would be defining it as a field on the implicit surrounding class (again which you can't see, but it's there), but rather just defining the variable without any modifiers which puts it in the global binding of the script.
We then send in the binding to the GroovyShell so that it can find the variable.
Result:
─➤ groovy solution.groovy
hello
A more generic variant is to do something like this:
def justSayHello() {
println "hello"
}
def someOtherMethod() {
println "hello again"
}
def methods = this.class.declaredMethods.findResults { m ->
if (m.name.startsWith('$') || m.name in ['main', 'run']) return null
[m.name, this.&"${m.name}"]
}.collectEntries { it }
// just for debugging, print the methods
methods.each { k, v ->
println "method: $k"
}
def my_str = "justSayHello()"
new GroovyShell(new Binding(methods)).evaluate(my_str)
which prints:
─➤ groovy solution.groovy
method: justSayHello
method: someOtherMethod
hello
here we find all the declared methods in the implicit class generated by groovy, remove some stuff added by the groovy compiler (namely main, run and methods starting with a $) and then send the resulting map as the binding for the GroovyShell constructor.
I suspect there might be a more elegant way of accomplishing this, so any groovy gurus - feel free to correct me here.
For an explanation of the implicit enclosing class for a groovy script, see for example this stackoverflow answer.
Actually I'm experimenting writing a DSL with groovy. So far ...
There are some things unclear to be regarding delegation and intercepting unwanted (Closure) structures:
first of all: How can I throw a (type of?) Exception to point to the correct line of code in the DSL that fails?
assuming
abstract MyScript extends Script {
def type(#DelegateTo(MyType) Closure cl) {
cl.delegate = new MyType()
cl()
this
}
}
under
new GroovyShell(this.class.classLoader, new CompilerConfiguration(scriptBaseClass: MyScript.name)).evaluate(…)
the passed DSL / closure
type {
foo: "bar"
}
passes silently.
I'm aware of, that foo: is just a POJ label but I'm not that sure what that defined Closure is interpreted as?
Neither did I found anything regarding the AST metaprogramming to get in touch of any defined labels to use them?
giving in
type {
foo = "bar"
}
it's clear that he will try to set the property foo, but do I really have to intercept unwanted fields/props by
class MyType {
def propertyMissing(String name) {
… // where I'm unable to println name since this leads to field access 'name' ...
}
}
while user is still allowed to pass
type {
foo "bar"
}
which leads to method not defined .. so I have to write additionally some metaClass.methodMissing or metaClass.invokeMethod stuff ..
meanwhile I tend to dismiss any closures in my dsl only working with simple
def type(Map vars) {
store << new MyType(vars)
// where in the constructor I was forced to write metaClass stuff to validate that only fields are given in the map that are defined in the class
}
that works, but both drafts are not what I expected to do when reading "groovy is so great for making DSLs" ...
I would experiment with the different options and then settle for one.
To guide your users you should give feedback similar to that of the regular compiler (i.e. line-number and column, maybe the expression).
Enforcing the correctness of the input can be non-trivial -- depending on your DSL.
For example:
type {
foo: "bar"
}
Is just a closure that returns the String bar. Is that something your user is supposed to do? The label will be part of the AST, AFAIK in org.codehaus.groovy.ast.stmt.Statement.statementLabels. If you want this syntax to assign something to foo then you'll need to rewrite the AST. The Expression could become a Declaration for the local Variable foo or could become an assignment for the Field foo. That's really up to you, however, Groovy gives you some capabilities that make creating a DSL easier:
You already used #DelegateTo(MyType) so you could just add a Field foo to MyType:
class MyType {
String foo
}
And then either use #CompileStatic or #TypeChecked to verify your script. Note that #CompileStatic will deactivate Run-time Metaprogramming (i.e. propertyMissing etc. won't be called anymore.) while #TypeChecked does not. This, however, will only verify Type-Correctness. That is: assigning to anything but a declared Field will fail and assigning an incompatible Type will fail. It does not verify that something has been assigned to foo at all. If this is required you can verify the contents of the delegate after calling the Closure.
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], { ..... })
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()