Home | News | Wiki | About StringTemplate | Feedback | Support | Bugs


Latest version is 3.2.
Download now! »

Download
» Home
» Download
» News
»Using StringTemplate
» Documentation
» Wiki
» Articles
» File Sharing
» Code API
» Tech Support
»About StringTemplate
» What is it?
» Showcase
» Testimonials
» Software License
» Changes
»Feedback
»Credits
»Contact


Support StringTemplate, ANTLR Project by making a donation! Terence often pays for things like the antlr.org server, conference travel, and this site design (that alone cost US$1000). Buy him a beer and pizza remotely ;)

Search



StringTemplate 2.2 Release Notes

Brought to you by that maniac that brings you the ANTLR parser generator!

Terence Parr
University of San Francisco
parrt@cs.usfca.edu
Copyright 2003-2005
http://www.stringtemplate.org
(StringTemplate released under BSD License)

Version 2.2, August 5, 2005

2.2 fixes a few bugs, but mainly 2.2 adds lots of great new features. The features were added in response to my needs building ANTLR v3's code generator and from feedback by StringTemplate users.

2.2 should be a drop-in replacement for those using StringTemplate for websites and code generation with a few minor potential incompatibilities.

Enhancements

  • You can define arguments for anonymous templates now, which is much nicer that using it all the time:
    $names:{n| <b>$n$</b><br>}; separator=","$
    
  • added parallel attribute iteration where you can apply a template to multiple lists of values; works for anonymous templates only:
    $names,phones:{n,p | $n$: $p$}$
    
    An error is generated if you have too many args for the number of parallel lists. Iteration proceeds while at least one of the attributes (names or phones, in this case) has values.
  • added "[a,b,c,...]" list operator to create multi-valued attributes, yielding single, longer multi-valued attribute. $[mine,yours]$ is a new list with both elements; all of mine first then all of yours.
  • any template invocation assumes sole formal argument name if just one formal argument defined in target template. For example, if you do $bold(name)$ and bold has one formal argument, then it gets the value of name. This works also for template application:
    test(names) ::= "<names:bold(),italics()>"
    bold(x) ::= "*<x>*"
    italics(y) ::= "_<y>_"
    
    Note: The binding of a value to the name of a sole formal argument is done dynamically so that indirect template invocation and lazy evaluation stuff works properly. For example (templateName)(value) should work for different templates with differently-named (but sole) formal arguments. See unit test testInvokeIndirectTemplateWithSingleFormalArgs().
  • Added operators to get first, rest, last attribute elements; e.g., first(users) yields the first value of users. rest(users) returns all elements of users except the first; it returns nothing if users is single-valued. This introduces a function-like syntax, which necessitated the "assign to sole formal arg" functionality above that supports things like bold(name). You can combine operations to say things like first(rest(names)) to get second element. Can say first([mine,yours]) to get the first of a combined list. These operators work on any iterable object. [backward incompatible if you used first,last,tail as an attribute or template name]
  • Added maps to StringTemplate groups. For example,
    typeInitMap ::= ["int"="0", "float"="0.0", default="null"]
    
    then within a template you can refer to them <typeInitMap.int>, which returns "0". Those strings are actually templates, but I can't really think of a use for that just yet. ;) If your type name is an attribute not a constant like int, then use <typeInitMap.(typeName)>. The maps are defined in the group's scope and are visible if no attribute hides them. For example, if you define a formal argument called typeInitMap in template foo then foo cannot see the map defined in the group (though you could pass it in, which would be the point). If a name is not an attribute and it's not in the group's maps table, then the super group is consulted etc... You may not redefine a map and it may not have the same name as a template in that group. The default value is used if you use a key as a property that doesn't exist. For example <typeInitMap.foo> returns "null".
  • Added renderers per template and group. Templates are inherited from super group. New Interface AttributeRenderer defines how an object is rendered to String. Here is a renderer that renders Calendar date objects tersely.
    public class DateRenderer implements AttributeRenderer {
    	public String toString(Object o) {
    		SimpleDateFormat f = new SimpleDateFormat("yyyy.MM.dd");
    		return f.format(((Calendar)o).getTime());
    	}
    }
    ...
    StringTemplate st =new StringTemplate(
    		"date: <created>",
    		AngleBracketTemplateLexer.class);
    st.setAttribute("created", new GregorianCalendar(2005, 07-1, 05));
    st.registerRenderer(GregorianCalendar.class, new DateRenderer());
    String expecting = "date: 2005.07.05";
    
    You can set the renderer for a class either at the group level or the individual template level. Thanks to Anton Keks for his suggestion and sample implementation.
  • template arguments can be anonymous templates now or simple strings. From the bug list:
    Template inclusion expressions won't accept a nested template
    as an argument.  I'd like to be able to write <foo(bar={...})>, which
    would mean the same thing as <foo(bar="":{...})>.
    
    Now you can do <foo(bar={<firstName> <lastName>)>}.
  • added default values (strings or anonymous templates like explicit template arguments) for formal arguments like
    bold(x="empty") ::= ...
    
    Note: because of lazy evaluation semantics, default value templates may refer to argument values. Everything is evaluated after arg values are set. This works for invoked templates and templates you create with code.
  • when calling another template, y, with formal arguments from within a template, x, none of the x parameters are visible to y because the formal parameters force you to define values. This prevents surprises and makes it easy to ensure a a value is empty unless you specifically set it for that template. The problem is that you need to factor templates sometimes and want to refine behavior with a subclass or just invoke another shared template but <y()> erases all of x's parameters. Now, use <y(...)> as a syntax to indicate y should inherit all values. <y(name="foo", ...)> would set one arg, but the others are inherited whereas <y(name="foo")> only has name set; others are empty. You can set manually with StringTemplate.setPassThroughAttributes().
  • When a property or argument is not found, you get a better error. I show the template context (nested tree of templates); e.g.,
    no such attribute: decisionNumber in template context
     [outputFile lexer cyclicDFA cyclicDFAState cyclicDFAEdge lookaheadTest]
    
  • added ability to use indirect property names. $user.(propName)$ evaluates (propName) to find the name of the property and then looks it up in user object whereas $user.foo$ looks for literally property foo in user object.

Bug Fixes

  • Thanks to Joe Soroka, you can now access public members of anonymous inner classes; Java doesn't normally allow even with public keyword. Bizarre. The following unit test works now:
     
    StringTemplate st =
    		new StringTemplate("$x.foo$:$x.bar$");
    Object o = new Object() {
    	public int foo = 9;
    	public int getBar() { return 34; }
    };
    st.setAttribute("x", o);
    String expecting = "9:34";
    assertEqual(st.toString(), expecting);
    
  • fields that were arrays didn't get treated as iterable objects
  • When you invoke foo(x=y), x must be an attribute of foo (well if you have formal args defined that is) and y is evaluated within the context of the surrounding template; more precisely, it's evaluated in the context of the actual template invocation (which can have predefined attributes like attr, it, and i). It's weird, but foo(x=x) also makes sense. See new unit test testArgEvaluationContext(). This was not working before, though I thought it was!
  • Collections, Maps, and Iterators that are non-null but have no elements return false in conditionals; e.g., $if(users)$ is false if users is an empty list.
  • To define an empty template, you had to write <<>>; "" didn't work.
  • Previous release (2.1) notes forgot to mention that I added field access to public object fields now instead of via just accessors.