Software Design by Example 9: Page Templates
Some day I’ll blog about the tools I built to create Software Design by Example, but if you’re interested in that kind of thing, check out Bob Nystrom’s articles (, ) about how he built Crafting Interpreters, which is the most beautiful book about programming I’ve seen in years. (It’s worth buying a copy of the book just to admire the production values.)
This book uses a static site generator called Ivy, which in turn relies on a page templating tool called Ibis. Thousands of these have been written in the last thirty years; most use one of three designs:
Create a mini-language with its own commands. Mini-languages are appealing because they are smaller and safer than general-purpose languages, but experience shows that they eventually grow most of the features of a general-purpose language. Again, some kind of marker must be used to show which parts of the page are code and which are ordinary text.
Put directives in specially-named attributes in the HTML. This approach has been the least popular, but since pages are valid HTML, it eliminates the need for a special parser.
This chapter used the third strategy, partly for novelty’s sake and partly because it saved us writing a parser. What the chapter shows is that even an apparently simple task of filling in strings requires the implementation of variables and scope—in short, a programming language. There are lots of ways to get this wrong; hopefully, this chapter will help readers get it right if it’s ever their turn.
Terms defined: bare object, dynamic scoping, environment, lexical scoping, stack frame, static site generator, Visitor pattern.
A Note on Open Source Etiquette
While using Ivy and Ibis on another project,
I ran into a problem that I’d never encountered before.
Ibis is hosted on PyPI at https://pypi.org/project/ibis/,
pip install ibis,
and imported with
There is another project called the Ibis Framework
that is hosted on PyPI at https://pypi.org/project/ibis-framework/,
pip install ibis-framework,
but which is also imported with
That naming conflict makes it impossible to use the two together
without manually renaming one or the other.
Ibis-the-templating-engine was created first, which I presume is why Ibis-the-framework uses a two-part name. I recognize that Ibis-the-framework is a bigger project than Ibis-the-templating-engine, and that the space of package names is getting pretty crowded, but I still think the authors of the latter should have chosen a different name to avoid the import conflict.