user626528
user626528

Reputation: 14418

Using `evaluate` function. Why it doesn't work?

This code:

evaluate ("def test() { println \"Test is successful!\" }")
test()

results in exception:

FATAL: No signature of method: script1409644336796288198097.test() is applicable for argument types: () values: [] Possible solutions: use([Ljava.lang.Object;), getAt(java.lang.String), use(java.util.List, groovy.lang.Closure), use(java.lang.Class, groovy.lang.Closure), wait(), wait(long) groovy.lang.MissingMethodException: No signature of method: script1409644336796288198097.test() is applicable for argument types: () values: [] Possible solutions: use([Ljava.lang.Object;), getAt(java.lang.String), use(java.util.List, groovy.lang.Closure), use(java.lang.Class, groovy.lang.Closure), wait(), wait(long) at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55) ...

What I'm doing wrong?

Upvotes: 12

Views: 20224

Answers (4)

Boris Brodski
Boris Brodski

Reputation: 8695

In addition to all other answers, if you don't want to change the structure of your code you can simply use return this at the end of your groovy-string:

lib = evaluate ("def test() { println \"Test is successful!\" }; return this")
lib.test()

Upvotes: 1

Sam Gleske
Sam Gleske

Reputation: 1060

If a variable has an undeclared type, then it goes into the script binding. The binding is visible to all methods which means data is shared.

evaluate() is a helper method to allow the dynamic evaluation of groovy expressions using this scripts binding as the variable scope.

In a variable binding, you can declare a closure which accepts no argument and must be restricted to calls without arguments.

With all of that in mind, here is your script working as intended.

evaluate ("test = { -> println \"Test is successful!\" }")
test()

Upvotes: 3

Will
Will

Reputation: 14529

That script evaluation results in null. You should either return something or execute the script and return the result.

An example returning a closure instead of defining a method:

test = evaluate ('return { "Test is successful!" }')
assert test() == "Test is successful!"

And an example where the script executes the method itself:

result = evaluate 'def test() { "eval test" }; return test()'
assert result == "eval test"

If you cannot change the script code, you may parse a class from the script, create a new object, and then execute the test() method:

def parent = getClass().getClassLoader()
def loader = new GroovyClassLoader(parent)
def clazz = loader.parseClass('def test() { "new class definition" }');

obj = clazz.newInstance()
assert obj.test() == "new class definition"

Upvotes: 15

jk47
jk47

Reputation: 765

You can do this using the ExpandoMetaClass to add dynamic closures to your own class. You would need to parse the string beforehand to split it into function name, arguments and code.

methodName = "test"
methodArgs = []
methodCode = """println "Hello World!" """

this.metaClass."$methodName"{ code, args ->
  evaluate(code)
}

Then you can call it by doing:

"$methodName"(code, arguments)

or

test(code, arguments)

To get the output Hello World!

You can read more about ExpandoMetaClass here http://groovy.codehaus.org/ExpandoMetaClass

Upvotes: 1

Related Questions