In the documentation/section 14.4 I came accross with the following example of code:
task configure << {
def pos = configure(new java.text.FieldPosition(10)) {
beginIndex = 1
endIndex = 5
}
println pos.beginIndex
println pos.endIndex
}
It's not quite clear what the pos and the configure means. I thought configure is just a property, so we can write something like
println configure.beginIndex
but the line causes compile-time error. And
{
beginIndex = 1
endIndex = 5
}
is just a closure, is it?
configure() is a method of the gradle Project object. The documentation of this method explains what it does:
Object configure(Object object, Closure configureClosure)
Configures an object via a closure, with the closure's delegate set to the supplied object. This way you don't have to specify the context of a configuration statement multiple times.
Instead of:
MyType myType = new MyType()
myType.doThis()
myType.doThat()
you can do:
MyType myType = configure(new MyType()) {
doThis()
doThat()
}
So the manual snippet defines an object of type FieldPosition, assigns it to the variable pos, sets its beginIndex and endIndex properties using a closure, thanks to the configure() method of Project, and then prints these properties.
It's a pointless example showing how to use the gradle DSL to configure several properties of an object.
Related
This is my simple groovy script;
def fourtify(String str) {
def clsr = {
str*4
}
return clsr
}
def c = fourtify("aa")
println("binding variables: ${c.getBinding().getVariables()}")
...
All I'm trying to do here is being able to access the free variable "str" using the closure instance to understand how closure works behind the scenes a bit more better. Like, perhaps, Python's locals() method.
Is there a way to do this?
The closure you have defined does not store anything in binding object - it simply returns String passed as str variable, repeated 4 times.
This binding object stores all variables that were defined without specifying their types or using def keyword. It is done via Groovy metaprogramming feature (getProperty and setProperty methods to be more specific). So when you define a variable s like:
def clsr = {
s = str*4
return s
}
then this closure will create a binding with key s and value evaluated from expression str * 4. This binding object is nothing else than a map that is accessed via getProperty and setProperty method. So when Groovy executes s = str * 4 it calls setProperty('s', str * 4) because variable/property s is not defined. If we make a slightly simple change like:
def clsr = {
def s = str*4 // or String s = str * 4
return s
}
then binding s won't be created, because setProperty method does not get executed.
Another comment to your example. If you want to see anything in binding object, you need to call returned closure. In example you have shown above the closure gets returned, but it never gets called. If you do:
def c = fourtify("aa")
c.call()
println("binding variables: ${c.getBinding().getVariables()}")
then your closure gets called and binding object will contain bindings (if any set). Now, if you modify your example to something like this:
def fourtify(String str) {
def clsr = {
def n = 4 // it does not get stored as binding
s = str * n
return s
}
return clsr
}
def c = fourtify("aa")
c.call()
println("binding variables: ${c.getBinding().getVariables()}")
you will see following output in return:
binding variables: [args:[], s:aaaaaaaa]
Hope it helps.
in your example str is a parameter of the method/function fortify
however maybe following example will give you better Closure understanding:
def c={ String s,int x-> return s*x }
println( c.getClass().getSuperclass() ) // groovy.lang.Closure
println( c.getMaximumNumberOfParameters() ) // 2
println( c.getParameterTypes() ) // [class java.lang.String, int]
the locals() Python's function better matches groovy.lang.Script.getBinding()
and here is a simple example with script:
Script scr = new GroovyShell().parse('''
println this.getBinding().getVariables() // print "s" and "x"
z = s*(x+1) // declare a new script-level var "z"
println this.getBinding().getVariables() // print "s", "x", and "z"
return s*x
''')
scr.setBinding( new Binding([
"s":"ab",
"x":4
]) )
println scr.run() // abababab
println scr.getBinding().getVariables() // print "s", "x", and "z"
Please help with a metaprogramming configuration such that I can add collections methods called collectWithIndex and injectWithIndex that work in a similar manner to eachWithIndex but of course include the base functionality of collect and inject. The new methods would accept a two (three with maps) argument closure just like eachWithIndex. I would like to have the capability to utilize these methods across many different scripts.
Use case:
List one = [1, 2, 3]
List two = [10, 20, 30]
assert [10, 40, 90] == one.collectWithIndex { value, index ->
value * two [index]
}
Once the method is developed then how would it be made available to scripts? I suspect that a jar file would be created with special extension information and then added to the classpath.
Many thanks in advance
I'm still sure, it's not a proper SO question, but I'll give you an example, how you can enrich metaclass for your multiple scripts.
Idea is based on basescript, adding required method to List's metaClass in it's constructor. You have to implement collect logic yourself, through it's pretty easy. You can use wrapping
import org.codehaus.groovy.control.CompilerConfiguration
class WithIndexInjector extends Script {
WithIndexInjector() {
println("Adding collectWithIndex to List")
List.metaClass.collectWithIndex {
int i = 0
def result = []
for (o in delegate) // delegate is a ref holding initial list.
result << it(o, i++) // it is closure given to method
result
}
}
#Override Object run() {
return null
}
}
def configuration = new CompilerConfiguration()
configuration.scriptBaseClass = WithIndexInjector.name
new GroovyShell(configuration).evaluate('''
println(['a', 'b'].collectWithIndex { it, id -> "[$id]:$it" })
''')
// will print [[0]:a, [1]:b]
If you like to do it in more functional way, without repeating collect logic, you may use wrapping proxy closure. I expect it to be slower, but maybe it's not a deal. Just replace collectWithIndex with following implementation.
List.metaClass.collectWithIndex {
def wrappingProxyClosure = { Closure collectClosure, int startIndex = 0 ->
int i = startIndex
return {
collectClosure(it, i++) // here we keep hold on outer collectClosure and i, and use call former with one extra argument. "it" is list element, provided by default collect method.
}
}
delegate.collect(wrappingProxyClosure(it))
}
offtopic: In SO community your current question will only attract minuses, not answers.
I'am trying to understand how this code example works. Unfortunately isn't commented at all.
HSSFRow.metaClass.getAt = { int idx ->
def cell = delegate.getCell(idx)
if(!cell) {
return null
}
def value
switch(cell.cellType) {
case HSSFCell.CELL_TYPE_NUMERIC:
if(HSSFDateUtil.isCellDateFormatted(cell)) {
value = cell.dateCellValue
} else {
value = cell.numericCellValue
}
break
case HSSFCell.CELL_TYPE_BOOLEAN:
value = cell.booleanCellValue
break
default:
value = cell.stringCellValue
break
}
return value
}
}
Can some one please explain me
Why need to override the MetaClass.getAt() method? It's not used directly. How does it work?
What's the cellType, dateCellValue, numericCellValue etc (methods or variables)? Where are they defined?
You don't need to override getAt method but it's overridden to make coding easier. When getAt is overridden it enables using [] syntax when You refer to object as in this line of code return row[idx] (taken from the example). It's operator overloading, see here. Summing up it's not used directly via getAt but with [] syntax.
In groovy when getXXX() method is provided (no arguments) on object x You can just refer to it omitting get so: x.getXXX() is the same as x.XXX. cell is just invocation of getCell() on HSSFRow object, the other methods are invoked on HSSFCell object and exactly the same rule applies.
I'd like to call a closure with a delegate parameter to override or shadow the calling context. But the following example prints prints "outside" where I expect "inside".
What am I doing wrong?
def f(String a){
def v = { return a }
v.delegate = [a:"inside"]
// Makes no difference:
// v.resolveStrategy = Closure.DELEGATE_FIRST
println(v.call())
}
f("outside")
I believe the issue is that when the closure is declared inside the function, it 'closes' round the known values in the method (a), so that value becomes effectively hard-coded into the closure (it never hits the delegate to find the unknown value as it is known to the Closure).
If you move the closure v definition outside of the function f, then it works:
v = { return a }
def f(String a){
v.delegate = [a:"inside"]
println(v.call())
}
f("outside")
Other option is to use getProperty('a') instead of directly using a as this forces the use of the delegate to retrieve the value of a.
Can also be done by referring the delegate in the closure. For v as a closure, a does not make any sense (equivalent to use of ExpandoMetaClass)
def f(String a){
def v = { delegate.a }
v.delegate = [a:"inside"]
println v()
}
f("outside")
I stumbled onto something with Groovy closures and delegates that I'm not sure is an official part of the language or perhaps even a bug.
Basically I am defining a closure that I read in as a string from an external source,
and one of the variables in the class that defines the closure needs to be modified by the closure. I wrote
a simple example showing what I found works, and what does not work.
If you look at the test code below you will see a class that defines a variable
animal = "cat"
and two closures defined on the fly from strings that attempt to modify the animal variable.
This works >
String code = "{ -> delegate.animal = 'bear'; return name + 'xx' ; }"
But this does not
String code = "{ -> animal = 'bear'; return name + 'xx' ; }"
It seems like I need to explicitly qualify my to-be-modified variable with 'delegate.' for this to work.
(I guess i can also define a setter in the enclosing class for the closure to call to modify the value.)
So.... I've found out how to make this work, but I'd be interested if someone could point me to some groovy
doc that explains the rules behind this.
Specifically.... why will the simple assignment
animal = 'bear'
affect the original variable ? Are there shadow copies being made here or something ?
import org.junit.Test
/*
* Author: cbedford
* Date: 8/30/12
* Time: 1:16 PM
*/
class GroovyTest {
String animal = "cat"
String name = "fred"
#Test
public void testDelegateWithModificationOfDelegateVariable() {
String code = "{ -> delegate.animal = 'bear'; return name + 'xx' ; }"
def shell = new GroovyShell()
def closure = shell.evaluate(code)
closure.delegate = this
def result = closure()
println "result is $result"
println "animal is $animal"
assert animal == 'bear'
assert result == 'fredxx'
}
// This test will FAIL.
#Test
public void testDelegateWithFailedModificationOfDelegateVariable() {
String code = "{ -> animal = 'bear'; return name + 'xx' ; }"
def shell = new GroovyShell()
def closure = shell.evaluate(code)
closure.delegate = this
def result = closure()
println "result is $result"
println "animal is $animal"
assert animal == 'bear'
assert result == 'fredxx'
}
}
Groovy closures have five strategies for resolving symbols inside closures:
OWNER_FIRST: the owner (where the closure is defined) is checked first, then the delegate
OWNER_ONLY: the owner is checked, the delegate is only checked if referenced explicitly
DELEGATE_FIRST: the delegate is checked first, then the owner
DELEGATE_ONLY: the delegate is checked first, the owner is only checked if referenced explicitly
TO_SELF: neither delegate nor owner are checked
The default is OWNER_FIRST. Since the closure is defined dynamically, your owner is a Script object which has special rules itself. Writing animal = 'bear' in a Script will actually create a new binding called animal and assign 'bear' to it.
You can fix your tests to work without explicitly referencing delegate by simply changing the resolve strategy on the closure before calling it with:
closure.resolveStrategy = Closure.DELEGATE_FIRST
This will avoid the odd the Script binding and use the delegate as expected.