[stringtemplate-interest] Managing template parameters
Terence Parr
parrt at cs.usfca.edu
Mon Dec 8 10:54:37 PST 2008
On Nov 23, 2008, at 4:38 PM, Nathan Ward wrote:
> That's more than I was suggesting.
Added feature request anyway. Sounds like a good idea:
http://www.antlr.org:8888/browse/ST-46
> I just wanted to be able do something like:
>
> myTemplateGroup.setAttribute("project", myProject);
>
> Many of my templates don't need this object, but some low-level
> templates,
> such as the msgKeyTag template shown below do need the project
> object. In
Interesting...sort of a global attribute?
> order to test msgKeyTag template with a JUnit based test, I had to
> make a
> base template group and a temporary template that takes the project
> object
> as a formal parameter so that the object would be available when the
> msgKeyTag template was invoked.
Can't you use setUp or whatever with junit to set default parameters?
Why not just have a method/factory create templates and set the
default parameters?
Ter
>
>
> I would think that this situation is not uncommon. So, either other
> people
> don't test small templates like this or other people also have to
> come up
> with similar solutions to unit test these kinds of templates. So, I
> thought
> this concept and API might make sense.
>
> // Implicit variable references: project
> // Calls different template based on project.properties.msgFormatName
> property,
> // e.g. jstlMsgFormat() template if msgFormatName is "jstl"
> msgKeyTag(msgKey) ::= <<
> $(msgFormatTemplateNameMap.(project.projectOptions.msgTagType))(...)$
>>>
>
> jstlMsgFormat(msgKey) ::= <<
> <fmt:message key="$msgKey$">
>>>
>
> strutsMsgFormat(msgKey) ::= <<
> <bean:message key="$msgKey$">
>>>
>
> springMsgFormat(msgKey) ::= <<
> <spring:message code="$msgKey$">
>>>
>
> // Maps msg format name to msg format template
> // e.g. "jstl" maps to jstlMsgFormat template to produce
> <fmt:message ...
> tag
> // Used by msgKeyTag template
> msgFormatTemplateNameMap ::= [
> "jstl":"jstlMsgFormat",
> "struts":"strutsMsgFormat",
> "spring":"springMsgFormat"
> ]
>
>
> -----Original Message-----
> From: Terence Parr [mailto:parrt at cs.usfca.edu]
> Sent: Friday, November 21, 2008 1:53 PM
> To: Nathan Ward
> Cc: stringtemplate-interest at antlr.org
> Subject: Re: [stringtemplate-interest] Managing template parameters
>
> Hi Nathan,
>
> Yes, in general I am very much opposed to dynamic scoping. In the
> template world, it makes a huge amount of sense. Templates are very
> dynamic
> creatures and our combined willy-nilly into large, nested trees of sub
> templates. I agree, however, that like we do with parameters, it
> could be
> useful to say "heh,I'm going to reference this dynamically scoped
> variable... if it does not exist when I'm evaluated, throw an
> exception".
> sort of like
>
> foo(a,b) uses title ::= "<a> <b> are parameters, <title> is from
> above"
>
> Is that what you're talking about?
>
> Ter
>
> On Nov 14, 2008, at 10:10 AM, Nathan Ward wrote:
>
>> 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
>>
>>
>
>
>
> _______________________________________________
> stringtemplate-interest mailing list
> stringtemplate-interest at antlr.org
> http://www.antlr.org:8080/mailman/listinfo/stringtemplate-interest
More information about the stringtemplate-interest
mailing list