Passing variable to be evaluated in groovy gstring - groovy

I am wondering if I can pass variable to be evaluated as String inside gstring evaluation.
simplest example will be some thing like
def var ='person.lName'
def value = "${var}"
println(value)
I am looking to get output the value of lastName in the person instance. As a last resort I can use reflection, but wondering there should be some thing simpler in groovy, that I am not aware of.

Can you try:
def var = Eval.me( 'new Date()' )
In place of the first line in your example.
The Eval class is documented here
edit
I am guessing (from your updated question) that you have a person variable, and then people are passing in a String like person.lName , and you want to return the lName property of that class?
Can you try something like this using GroovyShell?
// Assuming we have a Person class
class Person {
String fName
String lName
}
// And a variable 'person' stored in the binding of the script
person = new Person( fName:'tim', lName:'yates' )
// And given a command string to execute
def commandString = 'person.lName'
GroovyShell shell = new GroovyShell( binding )
def result = shell.evaluate( commandString )
Or this, using direct string parsing and property access
// Assuming we have a Person class
class Person {
String fName
String lName
}
// And a variable 'person' stored in the binding of the script
person = new Person( fName:'tim', lName:'yates' )
// And given a command string to execute
def commandString = 'person.lName'
// Split the command string into a list based on '.', and inject starting with null
def result = commandString.split( /\./ ).inject( null ) { curr, prop ->
// if curr is null, then return the property from the binding
// Otherwise try to get the given property from the curr object
curr?."$prop" ?: binding[ prop ]
}

Related

Groovy string interpolation when string is defined before the interpolated variables are defined

I have a similar question to this:
Groovy string interpolation with value only known at runtime
What can be done to make the following work:
def message = 'Today is ${date}, your id is: ${id}';
def date1 = '03/29/2019'
def id1 = '12345'
def result = {date, id -> "${message}"}
println(result(date1, id1))
So I want to take a string that has already been defined elsewhere (for simplicity I define it here as 'message'), having the interpolated ${date} and ${id} already embedded in it, and process it here using the closure, with definitions for the input fields.
I've tried this with various changes, defining message in the closure without the "${}", using single or double quotes, embedding double quotes around the interpolated vars in the string 'message', etc., I always get this result:
Today is ${date}, your id is: ${id}
But I want it to say:
Today is 03/29/2019, your id is: 12345
The following worked but I am not sure if it is the best way:
def message = '"Today is ${date}, your id is: ${id}"'
def sharedData = new Binding()
def shell = new GroovyShell(sharedData)
sharedData.setProperty('date', '03/29/2019')
sharedData.setProperty('id', '12345')
println(shell.evaluate(message))
http://docs.groovy-lang.org/latest/html/documentation/guide-integrating.html
ernest_k is right, you can use the templating engine for exactly this:
import groovy.text.SimpleTemplateEngine
def templatedMessage = new SimpleTemplateEngine().createTemplate('Today is ${date}, your id is: ${id}')
def date1 = '03/29/2019'
def id1 = '12345'
def result = { date, id -> templatedMessage.make(date: date, id: id)}
println(result(date1, id1))

How to extract a numeric id from a string using groovy in SOAP UI

One of the service is returning a field with a value like this one below , I want to extract the number '2734427' from the below string using Groovy in SOAP UI
[[https%3a%2f%2fthis.is.a.sample.link%2fproduct-data-v1%2f/jobs/2734427]]
I have used the below lines of codes - which works , but it looks a bit hacky .Was wondering if anyone could suggest a better option.
//Get the value of the Job Id Link
def gtm2joblink = "[[https%3a%2f%2fthis.is.a.sample.link%2fproduct-data-v1%2f/jobs/2734427]]"
// split jobid full link for extracting the actual id
def sub1 = { it.split("jobs/")[1] }
def jobidwithbrackets = sub1(gtm2joblink)
// split jobid full link for extracting the actual id
def sub2 = { it.split("]]")[0] }
def jobid = sub2(jobidwithbracket)
log.info gtm2joblink
Sounds like a job for a regular expression. If the job ID always follows /jobs, and is always numeric, and there are always double brackets ]] at the end, then the following will extract the ID:
import java.util.regex.Matcher
//Get the value of the Job Id Link
def gtm2joblink = "[[https%3a%2f%2fthis.is.a.sample.link%2fproduct-data-v1%2f/jobs/2734427]]"
Matcher regexMatcher = gtm2joblink =~ /(?ix).*\\/jobs\\/([0-9]*)]]/
if (regexMatcher.find()) {
String jobId = regexMatcher.group(1);
log.info(jobId)
} else {
log.info('No job ID found')
}

Classes in Genie

I am trying to replicate the Verbal Expression library for python in Genie as an exercise to learn how to use classes. I've got simple classes like the ones listed at the tutorial down, however when it comes to instatiate methods in a object oriented fashion I am running into problems. Here is what I am trying:
For training purposes I want a method called add that behaves identically as string.concat().
[indent=4]
class VerEx : Object
def add(strg:string) : string
return this.concat(strg)
But I get the error:
verbalexpressions.gs:33.16-33.26: error: The name `concat' does not exist in the context of `VerEx'
When I use a different approach, like:
class VerEx : Object
def add(strg:string) : string
a:string=""
a.concat(strg)
return a
init
test:string = "test"
sec:string = " + a bit more"
print test.VerEx.add(sec)
I get the error in the last line of the above text, with the warning:
verbalexpressions.gs:84.11-84.21: error: The name `VerEx' does not exist in the context of `string?'
I want to be able to make test.add(sec) behave identically to test.concat(sec), what can I do to achieve this?
a small example for this,
Note:
unhandle RegexError in
new Regex
r.replace
[indent=4]
class VerX
s: GenericArray of string
construct ()
s = new GenericArray of string
def add (v: string): VerX
s.add (v)
return self
def find (v: string): VerX
return self.add ("(%s)".printf (v))
def replace(old: string, repl: string): string
// new Regex: unhandle RegexError HERE!!
var r = new Regex (#"$(self)")
// r.replace: unhandle RegexError HERE!!
return r.replace(old, old.length, 0, repl)
def to_string (): string
return string.joinv ("", s.data)
init
var replace_me = "Replace bird with a duck"
var v = new VerX
print v.find("bird").replace(replace_me, "duck")
var result = (new VerX).find("red").replace("We have a red house", "blue")
print result

Binding Groovy TemplateEngine with any variable names

I am trying to write a method that:
Loads a template file (*.tpl) from the local file system
Parameterizes that template file with a list of supplied variables
Best attempt thus far:
String loadParameterizedTemplateByName(String templateName,
String... variables) {
InputStream inputStream =
this.class.classLoader.getResourceAsStream(templateName)
StringWriter writer = new StringWriter()
IOUtils.copy(inputStream, writer, 'UTF-8')
String templateBody = writer.toString()
def binding = variablesAsBinding(variables) // ?!?!
engine.createTemplate(templateBody).make(binding).toString()
}
So for instance say I have the following HelloEmail.tpl template file:
HelloEmail.tpl
==============
Hello ${firstName},
You are awesome! ${someGuy} even says so!
Sincerely,
${me}
Then my desired invocation of this would be:
String firstName = 'John'
String someGuy = 'Mark'
String me = '#smeeb'
String parameterizedTemplate =
loadParameterizedTemplateByName('HelloEmail.tpl', firstName, someGuy, me)
So that the final result is that parameterizedTemplate string has a value of:
println parameterizedTemplate
// Prints:
Hello John,
You are awesome! Mark even says so!
Sincerely,
#smeeb
The trick here is that the method needs to be able to use any list of supplied variables against any supplied template file!
Is this possible to accomplish via reflection? Meaning the TemplateEngine just looks as the supplied list of String variables, and substitutes them for variables of the same name (as found in the template)?
You can pass a Map like so:
import groovy.text.markup.MarkupTemplateEngine
import groovy.text.markup.TemplateConfiguration
String loadParameterizedTemplateByName(Map variables, String templateName) {
def engine = new groovy.text.SimpleTemplateEngine()
this.class.getResource(templateName).withReader { reader ->
engine.createTemplate(reader).make(variables)
}
}
def result = loadParameterizedTemplateByName('/mail.tpl', firstName:'Tim', someGuy:'StackOverflow', me:'smeeb')
assert result == 'Hello Tim,\n\nYou are awesome! StackOverflow even says so!\n\nSincerely,\nsmeeb'

Groovy/Grails: Fill up String Placeholder with current instance

Im really new to groovy/grails and I want to implement following:
In Groovy.config declare a string with a placeholder:
urls.sampleUrl = "http://foo/bar/${person.name}.jpg"
Later in another file, I want to fill up the placeholder with the current instance of the 'person'-object:
private void updateUrls(Person person)
{
def sampleString = urls.sampleUrl;
}
sampleString should then be, for example: _http://foo/bar/anthony.jpg
But the output is: _http://foo/bar/[:].jpg
How could I solve this?
...of course the code is probably wrong, I know, but its just for make you understanding my problem ;-)
Thanks for help.
Greetings.
try to use
urls.sampleUrl = "http://foo/bar/${->person.name}.jpg"
this will turn it into a GString. The closure will be executed when the .toString() is applied.
example:
def person = [name: 'jim']
def sampleUrl = "http://foo/bar/${->person.name}.jpg"
println person.name
println sampleUrl
person.name = 'jeff'
println sampleUrl
it could be that you run into a problem with
the scope of person.name . It must be defined before you define the GString
the config itself. If it is a properties file, I guess it does not know about GStrings
So you can also just use a replace like the following one:
def person = [name: 'jim']
def sampleUrl = "http://foo/bar/{0}.jpg"
println person.name
println sampleUrl.replace('{0}',person.name)
person.name = 'jeff'
println sampleUrl.replace('{0}',person.name)

Resources