Download / Getting Started
First of all it would be a good idea to download the current release. In the source jar you can find some working tests and examples. Also reading the web-site, then some Javadoc and perhaps some of the code will get you up and running. Especially the benchmark code may be helpful. Also take notice of my current plans for Toxic.
Table of Contents
Prerequisites
- Java 7 Runtime / JDK
- Toxic is written for the Java 7 platform.
- SLF4J
- Toxic uses simple logging facade for java as its logging backend.
License
This software is licensed under the MIT License (MIT).
Downloads
Toxic was originally hosted on berliOS developer site. As berliOS Developer site announced to close in 04/0214 the project moved to SourceForge. Or better: The SourceForge project, that was replicated from berliOS, was claimed by me. But currently there are no file releases. To follow recent development and download Toxic, just clone it from Gitorious.
As long as it is still running, you can also visit the old berliOS project site and download old versions of Toxic.
Fundamental Concepts
Toxic was not planned to be only a Java template engine but started based on my conviction that a template system consists of only the following:
- The template, which is nothing more than a text with some named placeholders.
- Some content to be filled in for the placeholders of the template.
- A program that determines the content that is to be filled in for the placeholders.
For flexibility we allow anything that can be written out as text to be content. Now we consider that a template which has all its placeholder filled in with some content can be written out as text, i.e. such a filled in template itself makes pretty good content.
So the essential idea is that template processing is a back and for between templates and a program that determines content to be filled in.
Templates with text content and filled templates as content.
The Template 3
in the figure above has its two placeholders filled
in – aka bound – and therefore can be used as content for Template 1
. Note that also Template 2
, that has no placeholders, can be used
as content because all of its placeholders, actually none, are bound.
Dynamic Content
Though the illustration above is a rather static example it is
important to mention, that content can be much more than static,
predefined pieces. If the program that we write has some sort of
conditional content or some sort of repetitive content, we have the
flexibility we need to create complex output. Fortunately modern
programming paradigms give us the tools to easily express such dynamic
content. In any object oriented language it should be quite easy to
have abstract
content that overrides a write
method. In Java it
could be similar to this:
public interface Content { void write( PrintWriter wr ); } ... public void processTemplate( Template t, PrintWriter wr ) { final String[] strls = new String { "foo", "bar", "baz" }; t.bind( "place", new Content() { private List<Template> tls = new ArrayList<>(); { int count = 1; for ( String str : strls ) { Template lineTmpl = loadATemplate( "line-template" ); lineTmpl.bind( "num", count++ ); lineTmpl.bind( "str", str ); tls.add( lineTmpl ); } } @Override void write( PrintWriter wr ) { for ( Template t : tls ) t.write( wr ); } } ); t.write( wr ); } ...
However with functional programming style this would be much more
elegant, e.g. with C++ 11 we could allow any std::function<void (std::ostream&)>
as content and write:
void process_template( Template& t, std::ostream& os ) { using namespace std; vector<string> strls{ "foo", "bar", "baz" }; vector<Template> tls; int count = 1; for ( const string& str : strls ) { Template lineTmpl = load_a_template( "line-template" ); lineTmpl.bind( "num", count++ ); lineTmpl.bind( "str", str ); tls.push_back( lineTmpl ); } t.bind( "place", [&tls]( ostream& os ) { for ( const Template& t : tls ) os << t; } ); os << t; }
Templates and Binding
Though the examples in the previous section showed how to nest bound
templates as content into templates, the examples also give a hint
where the design should be "tuned". We reuse the so called
line-template over and over to create output for each element in the
strls
list of strings. It is very likely, that loading of templates
needs quite some processing. At least there has to be some parsing of
a template "text" to find the placeholders but locating and loading
from disk or somewhere else is very likely too.
This is why we split templates into two parts:
-
The
Template
that is immutably kept around to be used to generate some output. -
The bound template,
Bount
in the following, that references theTemplate
it binds content to and the content that is bound to the placeholders.
A bound template is also content.
With this simple design at the core of Toxic the general ideas should
be easy to grasp. Note that there is no special, proprietary
template language to learn! You can don anything with templates what
your programming language allows you to do when overriding
Content::write()
and you can do it with your programming language in
your IDE.
However that seems to put the burden of overriding Content::write()
on you – which indeed is the case. But as one might see in the current Java implementation this could easily be solved by writing useful
libraries of special Content
.
Date: May 25, 2014
HTML generated with emacs org-mode & Toxic by [qb]