3

I'm trying to generate a closure from a string. The code inside the closure references a DSL function build(). The errors I'm getting imply that Groovy is trying to execute the closure instead of just declaring it. What is the correct syntax for this? Here are some of the constructs I have already tried.

sh = new GroovyShell() 
cl = sh.evaluate( '{ build("my job") }' } 
=> Ambiguous expression could be either a parameterless closure expression or an isolated open code block;

sh = new GroovyShell() 
cl = sh.evaluate( 'L: { build("my job") }' } 
=> No signature of method: Script1.build() is applicable ...

cl = Eval.me( 'L: { build("my job") }' } 
=> No signature of method: Script1.build() is applicable ...

cl = Eval.me( 'L: { com.flow.FlowDelegate.build("my job") }' } 
=> No such property: com for class: Script1

The example I'm trying to follow comes from: Load closure code from string in Groovy

Community
  • 1
  • 1
Jeremy Woodland
  • 3,444
  • 5
  • 17
  • 25

4 Answers4

1

What about returning the closure from the script?

Eval.me("return { build('my job') } ")

What do you intend using that L:? Returning a map? If is that so, you can use square brackets:

groovy:000> a = Eval.me("[L: { build('test for') }]")
===> {L=Script1$_run_closure1@958d49}
groovy:000> a.L
===> Script1$_run_closure1@958d49
Will
  • 14,348
  • 1
  • 42
  • 44
  • I think the L: is added as per the suggestion by Groovy console "Ambiguous expression could be either a parameterless closure expression or an isolated open code block", "solution: Add an explicit closure parameter list, e.g. {it -> ...}, or force it to be treated as an open block by giving it a label, e.g. L:{...}" – Alexander Suraphel Feb 11 '14 at 12:21
1

Consider the example below. The key is to specify, explicitly, a closure without parameters.

def build = { def jobName ->
    println "executing ${jobName}"
}

// we initialize the shell to complete the example
def sh = new GroovyShell()
sh.setVariable("build", build)

// note "->" to specify the closure
def cl = sh.evaluate(' { -> build("my job") }')

println cl.class
cl.call()
Michael Easter
  • 23,733
  • 7
  • 76
  • 107
0

In addition to Michael Easter's answer, you could also pass the script's binding through to the GroovyShell

def build = { ->
  "BUILD $it"
}

def shell = new GroovyShell( this.binding )
def c = shell.evaluate( "{ -> build( 'tim_yates' ) }" )

c()
Community
  • 1
  • 1
tim_yates
  • 167,322
  • 27
  • 342
  • 338
0

If you are evaluating the String from your DSL configuration script, you do not need to create a GroovyShell object.

Your script will be run as a subclass of Script which provides a convenience method for evaluating a string with the current binding.

public Object evaluate(String expression)
            throws CompilationFailedException

A helper method to allow the dynamic evaluation of groovy expressions using this scripts binding as the variable scope

So in this case, you'd just need to call evaluate('{ -> build("my job") }').

Jan Gassen
  • 3,406
  • 2
  • 26
  • 44