Group inheritance

Skip to end of metadata
Go to start of metadata

It's a common problem to need to generate a website with multiple skins or a code generator that must generate multiple variations of the same language such as Java 1.4 and 1.5 (1.5 added enums, for example). In either case, we want to design a variation as it differs from an existing code generation target. The easiest way to do this is to create a group of templates that override templates from a "supergroup" using the import statement. Templates in the current group override templates inherited from the imported group.

Let's look at the problem of generating enumerated types. In Java 1.4, we simulate enums with something like this:

Java 1.4

whereas Java 1.5 lets us do this:

Java 1.5

The goal is to keep the model and controller the same and to use a different group of templates according to the output we need. Here is what a piece of a Java 1.4 code generation template group file:

Java1_4.stg

Instead of copying and altering the entire group for Java 1.5, we can import the 1.4 group and alter just the part that changes, template constants:

Java1_5.stg

Group Java1_5 the inherited template classs will write template constants. The following sample code creates group objects referring to both template group files, creates and filled in instances of template class, and finally prints out the rendered text.

Java
C#
Python

 

Here is the output we get:

StringTemplate output

Simply by switching template group pointers in the test function, we have generated different code--only the templates changed.

Template polymorphism

In object-oriented programming languages, the type of the receiving object dictates which overridden method to call and response to method call o.f(). Similarly, StringTemplate looks up templates according to the group of the template doing the invocation. Template polymorphism is at work.

Imagine we're generating an HTML page using templates from group file site.stg (using $...$ delimiters) that invokes a searchbox template defined within the same group file:

site.stg

To create an instance of page, inject some test content, and print it out, we can use the following controller code.

 

Java
C#
Python

 

We get the following output.

StringTemplate output

Now, let's define a subgroup that overrides searchbox so that it generates nothing.

bland.stg

We can use identical code except for changing the source of the templates:

That yields the following output

StringTemplate output

Template page uses the overwritten version of the search box because we created that the page template via the subgroup. A template instantiated via the bland group should always start looking for templates in bland rather than the site supergroup even though searchbox is physically defined within site.stg.

Dynamic inheritance

When dealing with lots of output language variations, a proper separation of concerns can make generating multiple targets very complicated. For example, adding a debugging variation to our Java templates from above means adding another group of templates derived from both the 1.4 and 1.5 templates. The goal is to isolate all debugging code fragments in one group instead of cramming it all into the main templates. The problem is that we need a new debugging variation for each of the 1.4 and 1.5 templates--the import statement takes a literal string. We would need a new debugging group file to refer to different Java group file variations. In other words, DbgJava1_4.stg would have import "Java1_4.stg" and DbgJava1_5.stg would have import "Java1_5.stg".

Obviously the number of variations can explode. To deal with this problem, StringTemplate allows you to dynamically import/inherit templates using the controller instead of an import statement in the group file (and is the only way to do it when using directories of templates instead of group files). Here's some code that assumes there are no imports in the group files. To create group dbg_java1_5, it imports java1_5 group, which itself imports java1_4.

 

Java
C#
Python

 

Inheritance and subdirectories

There are 2 kinds of people using StringTemplate: web type folks and code generation type folks. The web folks usually have directory trees full of templates and code generation people tend to have group files. Everything is fine with respect to inheritance as long as the two don't mix. It's just too complicated thinking about inheritance hierarchies as well as directory hierarchies as well as polymorphism all at the same time. So, I've made this illegal by throwing an unsupported operation exception if you try to do an import in a group filed its nested within an outer STGroupDir.

Remember, for each group there should only be one STGroup object. So, imagine we have group file foo.stg and template a.st in a directory called /tmp and we create a group object to handle that stuff:

 

Java

So far so good. Now, what you cannot do is have foo.stg import something because it is nested within dir:

If I did,

then there is no problem. Difference is that you don't want to mix inheritance with subdirectories and a group file within a STGroupDir acts like a subdirectory.

Labels: