Express yourself!

By Serdar Yegulalp | 2016/06/03 08:00


May was a busy month, but I'm back, and working on MeTal once again. Here's what's going on.

Template mappings are now expressions, not templates themselves

One of the key dilemmas I had was how to deal with page templates that needed to output multiple files per page per mapping. For instance, tag archives. If you have a page with tags like movies, music, and progressive rock, you need to update three different archives, one for each tag.

My original way to handle template mappings was to have the mapping described by what amounted to an HTML template, using the same templating language employed in MTL itself. To wit:

/page/{{page.basename}}.html

when used on a page named this_is_a_page_title would generate /page/this_is_a_page_title.html.

The problem with this approach was that if I had something that generated more than one result, parsing it properly was a pain -- and I could see many instances where I would in fact want to return an actual Python object and not simply a string.

Now, the mapping for a template is a Python expression, which can yield up any kind of object, but it's meant to mainly work with a string (one page) or an iterable (multiple pages) per page. This last is most useful for generating tag archives. So we use:

'/page/'+page.basename+'.html'

instead of our previous template.

Now I have to think about a new problem: how do you express the context for such an expression?

That is, how do we provide information to the underlying template about what specific fields are being referenced? The output is nothing but a string, after all; there's no way to also generate details about which specific things in the expression are yielding what results, and we need that metadata to constrain the scope of the archives.

One possibility is to have a restricted subset of expressions, perhaps by way of a macro-expansions system -- e.g., $Y for year, $m for month, $T for page tag in context (for when iterating through multiple tags to generate archives), and so on. I'm not crazy about this, because it limits the expressiveness of the system, but it might be the best interim choice.

The other stipulation with such an approach is that they must show up in the resulting expression in the order of the constraints. E.g., if I said

'/tags/{}/%Y'.format($T)

it would interpret this as the year constraint coming before the page tag(s) constraint.

Yet another possibility is to have the format entirely deterministic by way of the format command:

'tags/{0}/{1}'.format($T,$Y)

Or maybe use names:

'tags/{tag}/{year}'.format(tag=$T,year=$Y)

and have the order of the constraint determined by the order of appearance this way.

Another possibility is to use Python's ast module to parse the string and determine the order of the elements, but that might well be overkill. Yet another possibility is to have the format string as one field, the context for it as another expression (maybe as a dict?).

I think at some point I'm just going to have to give up and say this:

  1. The context is determined by looking for specific tokens in the string.
  2. The order of their appearance, left to right, in the expression, dictates the direction of the constraint for the context.

I had no idea this could get so complicated. But I guess that's how you know you're learning: when you know you're trying to play over your head.


Tags: Python design templates


comments powered by Disqus