Groovy: How to invoke methods when closure is one of the parameter - groovy

This is my closure method and i am looking for different ways to invoke this groovy method
myMethod(Closure c, def val) {
if(c)
c.call()
println val
}
Things i tried:
myMethod({/*code*/},"print something")
Is there a way i can skip braces or a better way to do the same?

Put the Closure last in the definition:
def myMethod(val, Closure c) {
if(c) c.call()
println val
}
Then you can do:
myMethod("print something") { -> println "closure!" }
Edit
Think you're going to need 2 methods:
def myMethod(Closure c) {
myMethod('default', c)
}
def myMethod(val, Closure c) {
if(c) c.call()
println val
}
Then you can do:
myMethod('tim') { println 'woo' }
or
myMethod { println 'woo' }

Related

Groovy resolveStrategy in nested closure

I am puzzling over Groovy delegation strategy in nested closures. Here is a simplified example:
class Clazz {
String name
String whoAmI() {
return name
}
void doit(Clazz clazz) {
def cl = {
println "Outer closure: resolveStrategy=${resolveStrategy}, " +
"implicit=${whoAmI()}, delegated=${delegate.whoAmI()}"
{->
println "Inner closure: resolveStrategy=${resolveStrategy}, " +
"implicit=${whoAmI()}, delegated=${delegate.whoAmI()}"
}.call()
}
cl.resolveStrategy = Closure.DELEGATE_FIRST
cl.delegate = clazz
cl()
}
}
def a = new Clazz(name: 'A')
def b = new Clazz(name: 'B')
a.doit(b)
Output:
Outer closure: resolveStrategy=1, implicit=B, delegated=B
Inner closure: resolveStrategy=0, implicit=A, delegated=B
Why doesn't resolveStrategy propagate to the inner closure? The point of setting resolution strategy is to change the way implicit this is resolved. But if it doesn't propagate inside closures, then the mechanism seems to be as good as useless. Closures are so ubiquitous in Groovy that you can hardly write a couple of lines without them.
Found a similar question from almost five years ago: Nested closure resolution different between methods and properties? Apparently it's a bug, and it has been open without any movement since then: https://issues.apache.org/jira/browse/GROOVY-7232
The linked post notes something I also noticed: properties are correctly resolved to the delegate, but not method calls. Here is a reworked example to demonstrate this:
class Clazz {
String name
void doit(Clazz clazz) {
def cl = {
println "Outer closure: property=${name}, method=${getName()}"
{->
println "Inner closure: property=${name}, method=${getName()}"
}.call()
}
cl.resolveStrategy = Closure.DELEGATE_FIRST
cl.delegate = clazz
cl()
}
}
def a = new Clazz(name: 'A')
def b = new Clazz(name: 'B')
a.doit(b)
Result:
Outer closure: property=B, method=B
Inner closure: property=B, method=A
Someone in the linked post posted a workaround using rehydrate. In my case though it works (sort of) only if all references are replaced, including this!
class Clazz {
String name
void doit(Clazz clazz) {
def cl = {
println "Outer closure: property=${name}, method=${getName()}"
{->
println "Inner closure: property=${name}, method=${getName()}"
}.call()
}
cl.rehydrate(clazz, clazz, clazz)()
}
}
def a = new Clazz(name: 'A')
def b = new Clazz(name: 'B')
a.doit(b)
Result:
Outer closure: property=B, method=B
Inner closure: property=B, method=B

Groovy DSL: How can I let two delegating classes handle different parts of a DSLScript?

Let's say I have a DSL like this
setup {name = "aDSLScript"}
println "this is common groovy code"
doStuff {println "I'm doing dsl stuff"}
One would have a delegating class implementing the methods 'setup' and 'doStuff' usually. Beside, one could write common Groovy code to be executed (println...).
What I am searching for, is a way to execute this in two steps. In the first step only the setup method should be processed (neither println). The second step handles the other parts.
At the moment, I have two delegating classes. One implements 'setup' the other one implements 'doStuff'. But both execute the println statement, of course.
You can create a single class to intercept the method calls from the script and let it coordinate the following method invoke. I did it through reflection, but you can go declarative if you want. These are the model and script classes:
class FirstDelegate {
def setup(closure) { "firstDelegate.setup" }
}
class SecondDelegate {
def doStuff(closure) { "secondDelegate.doStuff" }
}
class MethodInterceptor {
def invokedMethods = []
def methodMissing(String method, args) {
invokedMethods << [method: method, args: args]
}
def delegate() {
def lookupCalls = { instance ->
def invokes = instance.metaClass.methods.findResults { method ->
invokedMethods.findResult { invocation ->
invocation.method == method.name ?
[method: method, invocation: invocation] : null
}
}
invokes.collect { invoked ->
invoked.method.invoke(instance, invoked.invocation.args)
}
}
return lookupCalls(new FirstDelegate()) + lookupCalls(new SecondDelegate())
}
}
Here be scripts and assertions:
import org.codehaus.groovy.control.CompilerConfiguration
def dsl = '''
setup {name = "aDSLScript"}
println "this is common groovy code"
doStuff {println "Ima doing dsl stuff"}
'''
def compiler = new CompilerConfiguration()
compiler.scriptBaseClass = DelegatingScript.class.name
def shell = new GroovyShell(this.class.classLoader, new Binding(), compiler)
script = shell.parse dsl
interceptor = new MethodInterceptor()
script.setDelegate interceptor
script.run()
assert interceptor.invokedMethods*.method == [ 'setup', 'doStuff' ]
assert interceptor.delegate() ==
['firstDelegate.setup', 'secondDelegate.doStuff']
Notice I didn't bothered intercepting println call, which is a DefaultGroovyMethods thus, a little more cumbersome to handle.
Also having the class MethodInterceptor implementing the method delegate() is not a good idea, since this allows the user-defined script to call it.
I found a way to split up execution of the DSL script. I used a CompilationCustomizer to remove every statement from AST except the doFirst{}. So the first run will only execute doFirst. The second run does everything else. Here's some code:
class DoFirstProcessor {
def doFirst(Closure c) {
c()
}
}
class TheRestProcessor {
def doStuff(Closure c) {
c()
}
def methodMissing(String name, args) {
//nothing to do
}
}
def dsl = "
println 'this is text that will not be printed out in first line!'
doFirst { println 'First things first: e.g. setting up environment' }
doStuff { println 'doing some stuff now' }
println 'That is it!'
"
class HighlanderCustomizer extends CompilationCustomizer {
def methodName
HighlanderCustomizer(def methodName) {
super(CompilePhase.SEMANTIC_ANALYSIS)
this.methodName = methodName
}
#Override
void call(SourceUnit sourceUnit, GeneratorContext generatorContext, ClassNode classNode) throws CompilationFailedException {
def methods = classNode.getMethods()
methods.each { MethodNode m ->
m.code.each { Statement st ->
if (!(st instanceof BlockStatement)) {
return
}
def removeStmts = []
st.statements.each { Statement bst ->
if (bst instanceof ExpressionStatement) {
def ex = bst.expression
if (ex instanceof MethodCallExpression) {
if (!ex.methodAsString.equals(methodName)) {
removeStmts << bst
}
} else {
removeStmts << bst
}
} else {
removeStmts << bst
}
}
st.statements.removeAll(removeStmts)
}
}
}
}
def cc = new CompilerConfiguration()
cc.addCompilationCustomizers new HighlanderCustomizer("doFirst")
cc.scriptBaseClass = DelegatingScript.class.name
def doFirstShell = new GroovyShell(new Binding(), cc)
def doFirstScript = doFirstShell.parse dsl
doFirstScript.setDelegate new DoFirstProcessor()
doFirstScript.run()
cc.compilationCustomizers.clear()
def shell = new GroovyShell(new Binding(), cc)
def script = shell.parse dsl
script.setDelegate new TheRestProcessor()
script.run()
I did another variation of this where I execute the DSL in one step. See my blog post about it: http://hackserei.metacode.de/?p=247

How can a Groovy closure curry itself for repetition?

I'm implementing Groovy step definitions for Cucumber-JVM and I want a step to be able store itself so that the next step can repeat it n times.
Given(~'the (\\S+) is in the blender') { String thing ->
// do stuff...
context.repeatable = self.curry(thing)
}
What should "self" be in the above code?
I can't use "this" as that refers to the enclosing object (whatever that is in this case, maybe the script).
Since curry is a method of the Closure class, directly invoking curry applies to the closure, both if it is named:
def context
test = { String thing ->
context = curry(thing)
thing.toUpperCase()
}
test('hello')
println context.call()
test('world')
println context.call()
=>
HELLO
WORLD
or anonymous:
def context
['test'].each { String thing ->
context = curry(thing)
thing.toUpperCase()
}
println context.call()
=>
TEST
You can try using unreferenced curry method passing the received parameters:
clos = { String text ->
if (text) {
println "text=$text"
a = curry null
a()
} else {
println "done"
}
}
clos "closure text"
Will print:
text=closure text
done
Update
You can also use clone():
closure = {
def clone = clone()
}

Pass method as parameter in Groovy

Is there a way to pass a method as a parameter in Groovy without wrapping it in a closure? It seems to work with functions, but not methods. For instance, given the following:
def foo(Closure c) {
c(arg1: "baz", arg2:"qux")
}
def bar(Map args) {
println('arg1: ' + args['arg1'])
println('arg2: ' + args['arg2'])
}
This works:
foo(bar)
But if bar is a method in a class:
class Quux {
def foo(Closure c) {
c(arg1: "baz", arg2:"qux")
}
def bar(Map args) {
println('arg1: ' + args['arg1'])
println('arg2: ' + args['arg2'])
}
def quuux() {
foo(bar)
}
}
new Quux().quuux()
It fails with No such property: bar for class: Quux.
If I change the method to wrap bar in a closure, it works, but seems unnecessarily verbose:
def quuux() {
foo({ args -> bar(args) })
}
Is there a cleaner way?
.& operator to the rescue!
class Quux {
def foo(Closure c) {
c(arg1: "baz", arg2:"qux")
}
def bar(Map args) {
println('arg1: ' + args['arg1'])
println('arg2: ' + args['arg2'])
}
def quuux() {
foo(this.&bar)
}
}
new Quux().quuux()
// arg1: baz
// arg2: qux
In general, obj.&method will return a bound method, i.e. a closure that calls method on obj.
In addition to the method pointer operator (.&), for Groovy version 3.0.0 and above there's the equivalent, compatible, well known Java 8+ method reference operator (::).
def foo(Closure c) {
c(func: "foo")
}
def bar(Map args = [:]) {
println "$args.func bar"
}
println foo(this::bar)
Output:
foo bar
The method reference operator, as stated in Groovy's documentation:
[…] overlaps somewhat with the functionality provided by Groovy’s
method pointer operator. Indeed, for dynamic Groovy, the method
reference operator is just an alias for the method pointer operator.
For static Groovy, the operator results in bytecode similar to the
bytecode that Java would produce for the same context.

How to select specific field using Groovy Closure

Given:
class FruitBasket {
int apples = 0
int oranges = 0
}
I need to pick out apples from each FruitBasket. The work need to be done in processFruit:
def processFruit(list, picker) {
list.each {
println "processing " + picker(it)
}
}
def processAll() {
List fruitList = [
new FruitBasket("apples": 2, "oranges": 4),
new FruitBasket("apples": 3, "oranges": 5)
]
processFruit(fruitList, applePicker)
}
def applePicker(FruitBasket f) {
return f.getApples()
}
but it is complaining # runtime that
No such property: applePicker for class: FooTest
possibly a problem with the closures FruitBasket arg...
In that code, applePicker is a method, not a closure.
You can either use a method handle to pass the method as a parameter like so:
processFruit(fruitList, this.&applePicker)
Or change it to an actual closure:
def applePicker = { FruitBasket f -> return f.getApples()    }
You are passing applePicker to processFruit, but it is a method. You can only pass closures this way. Redefine applePicker as a closure like so:
applePicker = { FruitBasket f ->
return f.getApples()
}
Or convert the method to a closure when processFruit is called:
processFruit(fruitList, this.&applePicker)

Resources