Binding Groovy TemplateEngine with any variable names - groovy

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'

Related

Groovy script to split a file line at ',' and create a new XML file

I am very new to Groovy and trying to figure my way out.
I am trying to write a groovy to split the lines of a file on encountering ',' and then write a if condition based on the first two characters of the line. After that I wanted to create a XML file using the different data in the file. This is how far I have reached.
def Message processData(Message message) {
//Body
def body = message.getBody(java.lang.String)as String;
def varStringWriter = new StringWriter();
def varXMLBuilder = new MarkupBuilder(varStringWriter);
String newItem ;
body.eachLine{
line -> newItem = line ;
String newItem1 = newItem.substring(0,2).trim();
String newItem2 = newItem.substring(3,11).trim();
varXMLBuilder.RECORD{
node1(newItem1);
node2(newItem2);
}
}
def xml = varStringWriter.toString();
xml="<RECORDS>"+xml+"</RECORDS>" ;
message.setBody(xml);
return message;
}
In the above code I tried to use offset but, since each of my file lines are of different length it wont work.
Please help me handle this issue.
Regards,
Nisha
Splitting on a character can be done like this:
data = 'axaratgxrgc,rxregxsergcs'
def lines = data.split(/,/)
assert lines[0] == 'axaratgxrgc'
assert lines[1] == 'rxregxsergcs'
Welcome, first of all, to groovy and Stack Overflow :)
You can use tokenize() to split a string, as shown bellow.
And yeah, don't worry about ; in groovy ;)
def Message processData(Message message) {
//Body
def body = message.getBody(java.lang.String) as String;
def varStringWriter = new StringWriter()
def varXMLBuilder = new MarkupBuilder(varStringWriter)
body.eachLine { line ->
def newItems = line.tokenize(',') // input is a list of chars that will split your string, usually better than .split()
String newItem1 = newItems.first() // looks like you want just two items
String newItem2 = newItems.last() // but you can use as an array as well newItems[0] and newItems[1]
varXMLBuilder.RECORD {
node1(newItem1)
node2(newItem2)
}
}
def xml = varStringWriter.toString()
xml="<RECORDS>${xml}</RECORDS>" // you can use ${} to add a variable inside a string
message.setBody(xml)
return message
}

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
}

How to make snakeyaml and GStrings work together

When I'm trying to use snakeyaml to dump out Yaml out of Groovy interpolated strings, it ends up printing a class name instead.
For example:
#Grab(group='org.yaml', module='snakeyaml', version='1.16')
import org.yaml.snakeyaml.Yaml
Yaml yaml = new Yaml();
def a = "a"
def list = ["$a"]
def s = yaml.dump(list)
Prints:
- !!org.codehaus.groovy.runtime.GStringImpl
metaClass: !!groovy.lang.MetaClassImpl {}
I'm guessing it has something to do with the fact that GStrings get transformed to Strings when they used and I suspect snakeyaml uses some sort of introspection to determine the class of the object.
Is there a better solution than calling toString() on all GStrings?
Try to create a new Representer :
public class GroovyRepresenter extends Representer {
public GroovyRepresenter() {
this.representers.put(GString.class, new StringRepresenter());
}
}
Yaml yaml = new Yaml(new GroovyRepresenter())
...
You could add type info to your variables
Yaml yaml = new Yaml();
def a = "a"
String aStr = "$a"
def list = [aStr]
def s = yaml.dump(list)

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)

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