0

I would like to use Eval.me to expand a string which contains a variable name.

def var = '1234'

// This works
eval_str = "println $var"
Eval.me(eval_str)

// This does not: No such property: $var
eval_str = 'println $' + "var" // I hoped later replace "var" with a parameter
Eval.me(eval_str)

So as I see Eval.me cannot do this. Then what is the sense in this Eval.me at all if it does not do anything more than the expression itself? Only for math expressions?

Is there any workaround, with Reflections or what ever to enforce it to expand the local def-variable (not Binding and not global one) from a string?

UPDATE: Added a minimal program fragment to explain, why I need variable expansion and what does not work in my case:

def func(def value_for_local_var, def closure_as_param) {
    def local_var = value_for_local_var
    closure_as_param()
}


// main
func('1234',
    {
        // println(local_var) // <- fails: "local_var" is visible only for func()
        // Eval.x(local_var, 'println "${x}') // <- again I need the value of "local_var" before
        // If I could something like this ...:
        Eval.me('println "${local_var}"') // but Eval.me is not so advanced as I thought
    }
)
1
  • Eval.me is not so advanced as I thought - you are just cooking it incorrectly :) Commented Oct 6 at 14:26

3 Answers 3

1

as for me according to the declared issue in update - you don't need evalme at all

def func(Map args, Closure closure_as_param) {
    closure_as_param(args)
}

//here how you can call it
//and you can declare the name of variable to use later in closure
func(local_var:'1234', local_var2:'abcd', map_var: [a:1,b:2]) { args ->
    println( "direct print: " + args.local_var) // <- success
    println( "direct print: " + args.local_var2) // <- success
    println( "direct print: " + args.map_var) // <- success
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, @daggett. So I see we came nearly same conclusion about how to solve the case. Your solution also uses a function argument in which you store your map.
1

The first one only works as it has already captured the field outside the call to Eval

def var = '1234'

eval_str = "println $var"

println eval_str

prints println 1234

---

You could do something like this instead, and store all your variables in a map:

def variableMap = [
    var1: '1234'
]

def eval_str = 'println "${x.var1}"'

Eval.x(variableMap, eval_str)

Which just prints 1234

---

You could also use delegate if there's only one value:

def func(value, Closure c) {
    c.delegate = [local_var: value]
    c()
}

func('1234') {
    println local_var
}

3 Comments

Well, I must have explained it better. I updated my question and put there my code (the logic is removed except of the fragment which contains the problem). I need somehow to access the local variable of the function inside the closure which I also pass into this function as argument. At the moment the closure is executing the local variable exists, but I cannot access it from the closure. Hardcoding of the variable or making it global - this is exactly I want to avoid, because I want to make my function most as possible general, so that the names of the local variables are parameterized.
So, in another words, the problem is not how to pass the values into the func(), regardless of how they are represented: a list or a map or whatever. Let's say, it will be a map. The problem is, how to reference this map by its name inside the closure if the name is def-ined only inside the func().
Updated with another alternative 🤔
0

I answer my own question. I found a workaround which requires an additional function argument. The closures-arguments should be turned into functions and take the map as an extra argument. Then this map can survive between closures:

def func(def vars, def f_try, def f_catch, def f_finally) {
    def local_vars = vars
    try {
        f_try(local_vars)
    } catch (e) {
        f_catch(local_vars, e)
    } finally {
        f_finally(local_vars)
    }
}

def try_func(def vars) {
    vars.put('try', 'true')
}
def catch_func(def vars, def e) {
    vars.put('catch', 'true')
    e.printStackTrace()
}
def finally_func(def vars) {
    vars.put('finally', 'true')
    println(vars)
}

// main
func([:], this.&try_func, this.&catch_func, this.&finally_func)

Output: [try:true, finally:true]

1 Comment

you don't need def in the function definitions, ie: def func(vars, f_try, f_catch, f_finally) { is enough

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.