Template inheritance
Recall that a StringTemplateGroup is a collection of related templates such as all templates associated with the look of a web site. If you want to design a similar look for that site (such as for premium users), you don't really want to cut-n-paste the original template files for use in the new look. Changes to the original will not be propogated to the new look.
Just like you would do with a class definition, a template group may inherit templates from another group, the supergroup. If template t is not found in a group, it is looked up in the supergroup, if present. This works regardless of whether you use a group file format or load templates from the disk via a StringTemplateGroup object. Currently you cannot use the group file syntax to specify a supergroup. I am investigating how this should work. In the meantime, you must explicitly set the supergroup in code.
From the unit tests, here is a simple inheritance of a template, bold:
| Java |
StringTemplateGroup supergroup = new StringTemplateGroup("super");
StringTemplateGroup subgroup = new StringTemplateGroup("sub");
supergroup.defineTemplate("bold", "<b>$it$</b>");
subgroup.setSuperGroup(supergroup);
StringTemplate st = new StringTemplate(subgroup, "$name:bold()$");
st.setAttribute("name", "Terence");
String expecting = "<b>Terence</b>";
|
| C# |
StringTemplateGroup supergroup = new StringTemplateGroup("super");
StringTemplateGroup subgroup = new StringTemplateGroup("sub");
supergroup.DefineTemplate("bold", "<b>$it$</b>");
subgroup.SuperGroup = supergroup;
StringTemplate st = new StringTemplate(subgroup, "$name:bold()$");
st.SetAttribute("name", "Terence");
string expecting = "<b>Terence</b>";
|
| Python |
supergroup = stringtemplate3.StringTemplateGroup("super")
subgroup = stringtemplate3.StringTemplateGroup("sub", superGroup=group)
supergroup.defineTemplate("bold", "<b>$it$</b>")
st = stringtemplate3.StringTemplate("$name:bold()$", group=subgroup)
st["name"] = "Terence"
expecting = "<b>Terence</b>"
|
The supergroup has a bold definition but the subgroup does not. Referencing $name:bold()$ works because subgroup looks into its supergroup if it is not found.
You may override templates:
| Java |
supergroup.defineTemplate("bold", "<b>$it$</b>");
subgroup.defineTemplate("bold", "<strong>$it$</strong>");
|
| C# |
supergroup.DefineTemplate("bold", "<b>$it$</b>");
subgroup.DefineTemplate("bold", "<strong>$it$</strong>");
|
| Python |
supergroup.defineTemplate("bold", "<b>$it$</b>");
subgroup.defineTemplate("bold", "<strong>$it$</strong>");
|
And you may refer to a template in a supergroup via super.template():
| Java |
StringTemplateGroup group = new StringTemplateGroup(...);
StringTemplateGroup subGroup = new StringTemplateGroup(...);
subGroup.setSuperGroup(group);
group.defineTemplate("page", "$font()$:text");
group.defineTemplate("font", "Helvetica");
subGroup.defineTemplate("font", "$super.font()$ and Times");
StringTemplate st = subGroup.getInstanceOf("page");
|
| C# |
StringTemplateGroup group = new StringTemplateGroup(...);
StringTemplateGroup subGroup = new StringTemplateGroup(...);
subGroup.SuperGroup = group;
group.DefineTemplate("page", "$font()$:text");
group.DefineTemplate("font", "Helvetica");
subGroup.DefineTemplate("font", "$super.font()$ and Times");
StringTemplate st = subGroup.GetInstanceOf("page");
|
| Python |
group = stringtemplate3.StringTemplateGroup(...)
subGroup = stringtemplate3.StringTemplateGroup(...)
subGroup.setSuperGroup(group)
group.defineTemplate("page", "$font()$:text")
group.defineTemplate("font", "Helvetica")
subGroup.defineTemplate("font", "$super.font()$ and Times")
st = subGroup.getInstanceOf("page")
|
The string st.ToString() results in "Helvetica and Times:text".
Just like object-oriented programming languages, StringTemplate has polymorphism. That is, template names are looked up dynamically relative to the invoking templates group.
The classic demonstration of dynamic message sends, for example, would be the following example (this catches my students all the time): 
| Java |
class A {
public void page() {bold();}
public void bold() {System.out.println("A.bold");}
}
class B extends A {
public void bold() {System.out.println("B.bold");}
}
...
A a = new B();
a.page();
|
| C# |
class A {
public void page() {bold();}
override public void bold() {Console.Out.WriteLine("A.bold");}
}
class B : A {
virtual public void bold() {Console.Out.WriteLine("B.bold");}
}
...
...
A a = new B();
a.page();
|
This prints "B.bold" not "A.bold" because the receiver determines how to answer a message not the type of the variable. So, I have created a B object meaning that any message, such as bold(), invoked will first look in class B for bold().
Similarly, a template's group determines where it starts looking for a template. In this case, both super and sub groups define a bold template mirroring the code above. Because I create template st as a member of the subGroup and reference to bold starts looking in subGroup even though page is the template referring to bold.
| Java |
StringTemplateGroup group = new StringTemplateGroup("super");
StringTemplateGroup subGroup = new StringTemplateGroup("sub");
subGroup.setSuperGroup(group);
group.defineTemplate("bold", "<b>$it$</b>");
group.defineTemplate("page", "$name:bold()$");
subGroup.defineTemplate("bold", "<strong>$it$</strong>");
StringTemplate st = subGroup.getInstanceOf("page");
st.setAttribute("name", "Ter");
String expecting = "<strong>Ter</strong>";
|
| C# |
StringTemplateGroup group = new StringTemplateGroup("super");
StringTemplateGroup subGroup = new StringTemplateGroup("sub");
subGroup.SuperGroup = group;
group.DefineTemplate("bold", "<b>$it$</b>");
group.DefineTemplate("page", "$name:bold()$");
subGroup.DefineTemplate("bold", "<strong>$it$</strong>");
StringTemplate st = subGroup.GetInstanceOf("page");
st.SetAttribute("name", "Ter");
string expecting = "<strong>Ter</strong>";
|
| Python |
group = stringtemplate3.StringTemplateGroup("super")
subGroup = stringtemplate3.StringTemplateGroup("sub", superGroup=group)
group.defineTemplate("bold", "<b>$it$</b>")
group.defineTemplate("page", "$name:bold()$")
subGroup.defineTemplate("bold", "<strong>$it$</strong>")
st = subGroup.getInstanceOf("page")
st["name"] = "Ter"
expecting = "<strong>Ter</strong>"
|
StringTemplate group maps also inherit. If an attribute reference is not found, StringTemplate looks for a map in its group with that name. If not found, the super group is checked.