/stencl

A lightweight templating library for Common Lisp

Primary LanguageCommon LispOtherNOASSERTION

Stencl

Stencl is a simple templating library loosely based on BRL (the Beautiful Report Language). It leverages the power of the lisp reader to create a dynamic templating system that is easy to understand and powerful enough for most applications.

Downloading and Installation

The official repository is currently at https://github.com/dlowe-net/stencl . Download the code, and place the directory with the asd file in ~/quicklisp/local-projects/ or somewhere in your asdf tree.

Writing templates

Here is an example of a stencl template:

<html><head><title>[#{title}]</title><body>
<ul>[(dolist (item #{list})
       (out ]
<li>[item]</li>[))]
</ul>
  <p>[#{footer}]</p>
</body></html>

and here's how you can get the template output:

(stencl:to-string (stencl:from-string template)
  :title "My title"
  :list '("alpha" "beta" "gamma" "delta")
  :footer "generated by stencl")

and here's the output:

"<html><head><title>My title</title><body>
<ul>
<li>alpha</li>
<li>beta</li>
<li>gamma</li>
<li>delta</li>
</ul>
<p>generated by stencl</p>
</body></html>
"

In this example, there's some html, with some Common Lisp code thrown in. The code is separated from the data with square brackets ([]), there's a stencl function in the middle, and there's a weird #{} notation. What is going on here?

The OUT function is what generates the output of the template. It converts all of its arguments to strings automatically, then appends them to the output stream of the template. The entire template starts with an implicit stencl wrapper, so that everything inside is, by default, a string that is output.

The square brackets are tricky, though. They delimit a string, but the open bracket ([) closes a string and the close bracket (]) starts a new string. So when you see [(out ]<p>[item]</p>[)], this will produce a form (internally) like (out "<p>" item "</p>"). This preserves the clarity of the template with a simple transformation, and was the central beautiful insight of the BRL language.

The notation of #{foo} is a stencl innovation, and tells the stencl library that FOO should be a keyword parameter to the generated function.

Using Stencl

  • FROM-STREAM stream

Generates a stencl function from the template text found on stream. The resulting function may be called with keywords defined inside the template.

  • FROM-FILE path

Generates a stencl function from the file at the given pathname.

  • FROM-STRING string

Generates a stencl function from a string.

  • TO-STREAM stream template &rest keyword args

Outputs the result of template to the stream, with the given keyword args. Returns the collected results of the template.

  • TO-FILE output pathname template &rest keyword args

Like TO-STREAM, but outputs to a file, which is created if necessary. Returns the collected results of the template.

  • TO-STRING template &rest keyword args

Like TO-STREAM, but outputs to a string. The collected results of the template are returned as the second value.

  • FORMAT-TEMPLATE stream template &rest keyword args

Generates a stencl function from template, calls it with keyword args, and outputs it to stream if not NIL. Outputs to standard-output if stream is T. Returns the string generated and the collected results of the template.

  • OUT arguments*

Usually called within a template, the stencl function converts all its arguments to strings and appends each string to the output of the template.

  • INCLUDE template [additional or default args]

When found in a template definition, this form includes the template, forwarding all its keyword arguments to the interior template. This may be useful for providing nested templates for layout or other shared structures. The template argument is just another variable which is evaluated at runtime.

  • COLLECT values

In a template definition, this form collects values into a list, which are returned as the result of the template function. This is useful for passing information calculated in the template back to the caller. Returned results from included templates are also appended to the result. COLLECT is most useful when collecting property lists (e.g. (:foo "bar" :baz 23)), but any value can be returned.