Groovy/Grails: Fill up String Placeholder with current instance - string

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)

Related

Access variable value by its name as String (groovy)

I've done some research but I haven't found a working code for my case. I have two variables named test and test2 and I want to put them in a map in the format [test:valueof(test), test2:valueof(test2)]
My piece of code is the following:
def test="HELLO"
def test2="WORLD"
def queryText = "\$\$test\$\$ \$\$test2\$\$ this is my test"
def list = queryText.findAll(/\$\$(.*?)\$\$/)
def map = [:]
list.each{
it = it.replace("\$\$", "")
map.putAt(it, it)
}
queryText = queryText.replaceAll(/\$\$(.*?)\$\$/) { k -> map[k[1]] ?: k[0] }
System.out.println(map)
System.out.println(queryText)
Output:
Desired output:
"HELLO WORLD this is my test"
I think I need something like map.putAt(it, eval(it))
EDIT
This is the way I get my inputs. the code goes into the 'test' script
The ones on the right are the variable names inside the script, the left column are the values (that will later be dynamic)
You are almost there.
The solution is instead of putting the values into separate variables put them into the script binding.
Add this at the beginning ( remove the variables test and test2):
def test="HELLO"
def test2="WORLD"
binding.setProperty('test', test)
binding.setProperty('test2', test2)
and change this:
{ k -> map[k[1]] ?: k[0] }
to this:
{ k -> evaluate(k[1]) }
It should be very simple if you could use TemplateEngine.
def text = '$test $test2 this is my test'
def binding = [test:'HELLO', test2:'WORLD']
def engine = new groovy.text.SimpleTemplateEngine()
def template = engine.createTemplate(text).make(binding)
def result = 'HELLO WORLD this is my test'
assert result == template.toString()
You can test quickly online Demo
Final working code, thanks to all, in particular to dsharew who helped me a lot!
#input String queryText,test,test2,test3
def list = queryText.findAll(/\$\$(.*?)\$\$/)
def map = [:]
list.each{
it = it.replace("\$\$", "")
map.putAt(it, it)
}
queryText = queryText.replaceAll(/\$\$(.*?)\$\$/) { k -> evaluate(k[1]) }
return queryText

Groovy - 'no signature of method' error when calling method in main

I'm new to Groovy and I'm trying to fill a hash map with strain names and corresponding N50 values of bacteria obtained from a JSON-file. First, I want to fill the hash with the strain names as keys.
My method for doing so looks like this:
def getStrains() {
//create Slurper to get content from JSON file
def slurper = new JsonSlurper()
def inputFile = new File("-path to JSON file-")
def inputJSON = slurper.parseText(inputFile.text)
InputJSON.strains.each{
//get strain names from JSON file
def genus = it.genus
def species = it.species
def strain = it.strain
def folderName = "${genus}_${species}_${strain}"
//save folder name in hash
n50Values[folderName]
}
}
Now when I want to call my method in my main method (just to see if the strain names are correct) like this
public static void main (String[] args){
getStrains()
}
I get the following Error:
Exception in thread "main" groovy.lang.MissingMethodException: No signature of method: static scaffolds.ReadJSON.getStrains() is applicable for argument types: () values: []
I defined the hash in the beginning of my class.
I feel like I'm missing something obvious here, but I don't know what the error message wants to tell me. I've looked through other people having the same error but they are all very subjective. Any help is appreciated, thanks in advance.
declare the getStrains() as static since it is calling from a static context
You misspelled your var name:
def inputJSON = slurper.parseText(inputFile.text)
**i**nputJSON.strains.each{
btw, this
n50Values[folderName]
doesn't make any sense. perhaps you want to have it like
n50Values << folderName
or
n50Values[folderName] = folderName
UPDATE:
looks like you want to use a collect instead of each here:
def n50Values = inputJSON.strains.collect{
/*your code*/
folderName
}

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 Expando : why it consider the local variable and not the expando properties?

looking at this test code:
def a = "test"
def expando = new Expando()
expando.a = a
expando.foobar = {a}
expando.a = "test1"
assert expando.foobar() != a
why the last assertion fail? it considers "a" as the local variable and not as the expando.a properties.
Thanks for help
Perhaps I am mistaken, but when you invoke expando.foobar(), it returns the result of the closure that was assigned to foobar. In this case, it is a, so it returns the value of a: test.
expando.foobar() does not call the property 'a' because closures do not look for their delegate unless a variable is not defined in scope (and in this case it is).
Edit:
If you were to do expando.foobar = {delegate.a}, that would return the results you are expecting.

Passing variable to be evaluated in groovy gstring

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 ]
}

Resources