Software Design by Example 9: Page Templates

Posted

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 ([1], [2]) 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:

  1. Mix commands in a language such as JavaScript with the HTML or Markdown using some kind of marker to indicate which parts are commands and which parts are to be taken as-is.

  2. 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.

  3. 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.

Three options for page templates
Figure 9.1: Three different ways to implement page templating.

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/, installed with pip install ibis, and imported with import ibis. There is another project called the Ibis Framework that is hosted on PyPI at https://pypi.org/project/ibis-framework/, installed with pip install ibis-framework, but which is also imported with import ibis. 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.