[stringtemplate-interest] Managing template parameters
Nathan Ward
nward at resqsoft.com
Fri Nov 14 10:10:50 PST 2008
Terence,
I got this working. My code is included below in case it would be of use to
someone else. I would think this would be a common problem because I would
think it is pretty common for template parameters to become "tramp data" as
Meiler Page-Jones defined in the book Structured Systems Design many years
ago (i.e. passing parameters around for use in code that is called later
down the line.
I also think there is an interesting StringTemplate design issue here... The
solution described in the Meiler Page-Jones book was to use "Information
Hiding" is similar to using object-oriented design but was before OOD. I had
done this kind of thing when programming in C where I would group data and
processing (i.e. C functions) in the same file. The variables defined at the
top of the file where like object attributes. Not exactly OO, but not bad
when programming in C.
Given that StringTemplate is designed with a syntax that encourages good
template design, I would think that implicit access to variables like I am
now doing should not be allowed, but an alternative should be provided by
allowing template groups to accept parameters. This would be similar to an
object having instance member variables. This makes the intension to share
data across templates more explicit and help the template designer think
about if the data really should be shared this way or should be treated as
formal parameters. This would also eliminate the need for me to create this
temporary template and template group for testing purposes.
Shared.stg:
// Implicit variable references: screen
screenElementResourceBundleKey(screenElement, screenElementType) ::= <<
<formClassName(screen)>.<screenElementType>.<screenElement.text>.Text
>>
SharedTemplateTestCase.java:
public void testScreenElementResourceBundleKey() {
Screen screen = new Screen();
screen.setName("MY_SCREEN");
Button button = new Button();
button.setText("MyButtonText");
super.setTemplateAttribute("screen", screen);
super.setTemplateAttribute("screenElement", button);
super.setTemplateAttribute("screenElementType", "Button");
String templateString = super.executeTemplateWithImplicitVariables(
templateGroup, templateGroup,
"screenElementResourceBundleKey");
super.logTemplateOutput(templateString);
TestCase.assertEquals("MyScreenForm.Button.MyButtonText.Text",
templateString);
}
BaseTemplateTestCase.java:
/**
* Use this method to test templates that use one or more <i>implicit
variables</i>
* rather than using only formal parameters. Implicit variables should
be used only
* in cases where the immediate template doesn't need the parameter
other than to
* pass it to other templates d several levels down in the template
calling chain.
*
* This method execute the template given by the templateName parameter
from a temporary
* template that this method creates in the template group so that the
parameters
* previously added by calling setTemplateAttribute() method will be
accessible to
* the template under test.
*
* If the template under test does not use implicit variables,
* (i.e. only uses formal parameters), then the StringTemplate API can
be used directly
* rather than using this method.
*
* @param rootTemplateGroup The rootTemplateGroup in the template group
inheritance hierarchy
* for the template group that the template under test is in. If the
target template group
* does not inherit from another template group, then just pass the
target template group
* as this parameter and also pass the same template group as the
targetTemplateGroup parameter.
* @param targetTemplateGroup The template group in which the template
under test is defined.
* @param templateName The name of the template under test.
* @return
*/
public String executeTemplateWithImplicitVariables(StringTemplateGroup
rootTemplateGroup,
StringTemplateGroup targetTemplateGroup, String templateName) {
StringBuilder temporaryTemplateGroup = new StringBuilder();
temporaryTemplateGroup.append("group temp;");
temporaryTemplateGroup.append(newline);
temporaryTemplateGroup.append("aTemplate(");
boolean notFirst = false;
for (final String parmName : parms.keySet()) {
if (notFirst) {
temporaryTemplateGroup.append(", ");
}
else {
notFirst = true;
}
temporaryTemplateGroup.append(parmName);
}
temporaryTemplateGroup.append(") ::= <<");
temporaryTemplateGroup.append(newline);
temporaryTemplateGroup.append("<");
temporaryTemplateGroup.append(templateName);
temporaryTemplateGroup.append("(...) >");
temporaryTemplateGroup.append(newline);
temporaryTemplateGroup.append(">>");
String temporaryTemplateGroupString =
temporaryTemplateGroup.toString();
StringTemplateGroup newParentGroup = new StringTemplateGroup(new
StringReader(
temporaryTemplateGroupString));
// Make the rootTemplateGroup inherit from the newParentGroup that
we created
// from temporaryTemplateGroupString
rootTemplateGroup.setSuperGroup(newParentGroup);
// Get an instance of the temporary template that we have created
named aTemplate
// from the targetTemplateGroup. Important that we get the instance
from the targetTemplateGroup
// rather than directly from the newParentGroup template so that the
template has access to
// all other templates in the template group inheritance hierarchy.
StringTemplate template =
targetTemplateGroup.getInstanceOf("aTemplate");
for (final Map.Entry<String, Object> entry : parms.entrySet()) {
template.setAttribute(entry.getKey(), entry.getValue());
}
String templateString = template.toString();
return templateString;
}
public void setTemplateAttribute(String parmName, Object value) {
this.parms.put(parmName, value);
}
-----Original Message-----
From: Terence Parr [mailto:parrt at cs.usfca.edu]
Sent: Thursday, November 13, 2008 5:58 PM
To: Nathan Ward
Cc: stringtemplate-interest at antlr.org
Subject: Re: [stringtemplate-interest] Managing template parameters
On Nov 13, 2008, at 11:50 AM, Nathan Ward wrote:
> I'm aware of that, but how can I make a JUnit test for the subtemplate
> if it uses an attribute that is not passed as a formal parameter?
> Hmmm, I guess I can create a template inline in my test code that uses
> the template that I'm testing, which is a string group template file.
> I'll try that. Thanks!
That'll work. :)
Ter
More information about the stringtemplate-interest
mailing list