How to dynamically resolve templated string?

76 views Asked by At

The need is very simple: resolve a string with the current execution context.

Example:

def templateToResolve = "${hello}"  // This comes from a function, the variable is not resolved here
def hello = "world"

// How to "resolve" templateToResolve without knowing the existence of hello

println templateToResolve // world

Maybe we could extract the Binding of the execution context and use it with StreamingTemplateEngine but I didn't find a way to get the current binding. I also gave a look to Eval.me but Eval does not use external context. I even checked dynamic compilation without success.

The solution must not use hello var in any way, it must be dynamic.

1

There are 1 answers

3
chubbsondubs On

So bottom line is using GString (ie "${hello}") you can't. There is no concept of a binding that can be defined later with GString. The variables you reference in your GString must be visible in the context where they are defined. GString internally doesn't know the expression that was used to evaluate the value it holds so the binding is lost. Now you can do fancy things with this like translating the GString into other representations like this:

def hello = "world"
def x = "Guy ${hello} Hi"

println( x.getStrings() )
println( x.getValues() )

StringBuilder builder = new StringBuilder()
String[] gstr = x.getStrings()
String[] gVals = x.getValues()
for( int i = 0; i < gstr.length; i++ ) {
    String curr = gstr[i]
    int valueIndex = i - 1
    if( valueIndex >= 0 ) {
        builder.append("`")
        builder.append( gVals[i-1] )
        builder.append("`")
    }
    builder.append( curr )
}
println( builder.toString() )

But I don't know if that's what you're after. I think you might want to look at SimpleTemplateEngine which would let you define the template you want without the context embedded within it. Like so:

def text = 'Dear "$firstname $lastname",\nSo nice to meet you in <% print city %>.\nSee you in ${month},\n${signed}'

def binding = [firstname:"Sam", 
               lastname:"Pullara", 
               city:"San Francisco", 
               month:"December", 
               signed:"Groovy-Dev"]

def engine = new groovy.text.SimpleTemplateEngine()
def template = engine.createTemplate(text).make(binding)

def result = 'Dear "Sam Pullara",\nSo nice to meet you in San Francisco.\nSee you in December,\nGroovy-Dev'

assert result == template.toString()

For a full discussion see the Groovy docs on Template Engines