In my last post I showed a simple use of Enlive to create a web application with a common layout for all pages. I resisted the temptation to introduce any abstractions because I wanted to make it absolutely clear how to use the building blocks that Enlive provides.
But my fingers were itching the whole time to abstract away some of the wrinkles and I couldn’t let it rest until I’d had a play to see what it looks like. So here is a very thin layer over Enlive that manifests some of the structure that I saw.
Here’s the code we ended up with last time. There is a
template that is used to wrap the two pages (
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
I’d like to find a way to clarify the page and layout concepts in the code. I’ll use macros to define them, so that I get the define-and-assign style effect which I think is appropriate for important entities like this.
Layouts first. There is some slightly tricky stuff here, stripping off
<body> tags, which we can hide. Let’s assume
that every layout will have one main piece of content, which we can
define by convention will go into
div.content; but we’ll allow each
template to define other slots and substitutions for them.
So we want the layout definition for our example above to look like this.
This defines a function (
layout) which takes a single argument
title) and returns an Enlive template—another function that
takes the page’s content and returns the rendered HTML. We’re
effectively currying the
layout function defined in the raw example
because we want to specify
content at different points.
Here is how we would use it, without changing anything else.
1 2 3
And here’s what
deflayout looks like.
1 2 3 4 5
And now pages. There are two different kinds of page: dynamic ones,
show, which take one or more parameters and transform their
HTML and static ones, like
index, with neither parameters nor
transformations. We’d like to make defining and calling both types
simple. We’d also like to specify the layout when defining the page
and hide its application. Here’s what we’re aiming for.
1 2 3 4
And here’s the definition of
1 2 3 4 5 6 7 8
This creates functions for parameterized pages and simple values for static ones to simplify calling them.
1 2 3 4
You can see the complete code, in a working project, here.
This refactoring is obviously overkill for a tiny example like this, but something like it could be useful on a real project. It meets the two objectives, anyway: clarifying the important concepts and hiding some of the fiddly details.