Skip to content
Simplistic template library featuring Clojure language processing with Ruby 2.0 ERB-esque syntax.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.

Ash Ra Template

Simplistic template library featuring Clojure language processing with Ruby 2.0 ERB-esque syntax.

Motivation: Of the Clojure templating libraries we found, none seemed to directly assist in porting a non-trivial amount of ERB-templated content from Middleman to a custom Clojure-based static site generation tool. We find that the ERB syntax contrasts well with Clojure, and being able to in-line arbitrary Clojure code is intoxicatingly pragmatic (also expressed as: Enough rope to hang oneself). Seeking to wield such expressive power, we wrote Ash Ra Template, or ART.

Works with Clojure 1.9 and newer.


Clojars Project

Include this library from Clojars by adding [vivid/ash-ra-template "0.2.0"] to :dependencies in your project.clj.

Rendering a template string is easy:

(require [ :as art])

(art/render "There were <%= (+ 1 2) %> swallows, dancing in the sky.")

Or, to render from a file:

(art/render (slurp ""))

All Clojure code is evaluated within a sandboxed Clojure runtime courtesy of ShimDandy.


Plain content with no ART-specific syntax

(art/render "We are but stow-aways aboard a drifting ship, forsaken to the caprices of the wind and currents.")

Passed as a string, the rendered output is expected to be a byte-perfect mirror of its input:

We are but stow-aways aboard a drifting ship, forsaken to the caprices of the wind and currents.

Clojure code blocks

You can embed Clojure code within the template by surrounding forms with <% and %> tags, on one line:

<% (def button-classes [:primary :secondary :disabled]) %>

or over many lines:

(defn updated-statement
  [date version]
  (format "This document was updated on %s for version %s"
          date version))

Intermixing text and code

An example of intermixing text and Clojure code blocks that realizes the full expressive power of ART templates:

(require '[clojure.string])
(def publication-dates [1987 1989 1992])
(defn cite-dates [xs] (clojure.string/join ", " xs))
Chondrichthyes research published in <%= (cite-dates publication-dates) %>.

Renders to:

Chondrichthyes research published in 1987, 1989, 1992.

External dependencies

Given a template that requires namespaces from external dependencies in Clojure, such as:

(require '[hiccup.core])

(def ^:const toc-headings [{:id 739 :text "Moving wing assembly in place"}
                           {:id 740 :text "Connecting fuel lines and hydraulics"}
                           {:id 741 :text "Attaching wing assembly to fuselage"}])

(defn toc-entry [heading]
  (hiccup.core/html [:li
      {:href (str "#" (heading :id))}
      (heading :text)]]))
<%= (apply str (map toc-entry toc-headings)) %>

The template's external dependencies can be specified as a Clojure deps lib map with the :dependencies keyword argument:

(art/render template
            :dependencies {'hiccup {:mvn/version "1.0.5"}})

The specific version of Clojure can be overridden:

{'org.clojure/clojure {:mvn/version "1.10.0"}}


Note that until ART achieves version 1.0 status, details may be subject to change.

Design Goals

  • Minimal restrictions:
    • Java 1.8 class files, because Java 1.8 strikes a good balance between wide adoption and long-term stability.
    • Clojure 1.9.0, which is compatible with a version that has reasonable dependency resolving abilility, and doesn't cause an additional macOS App to run and disrupt keyboard focus during runtime.
  • Effortlessly composable: Use render wherever you like.
  • No inferrence of parens in Clojure code portions: Clojure forms are kept whole for natural recognition by the eye, copy & paste, machine processing, etc.


(render s :dependencies deps) Renders an input string containing Ash-Ra Template -formatted content to an output string. An optional map of dependencies (as a Clojure deps lib map) can be provided using the :dependencies keyword argument. These dependencies will be resolved prior to template rendering using Clojure's org.clojure/tools.deps.alpha.


It's unnecessary to surround ERB tags with whitespace. Whitespace in the text portions of the template is preserved.

<% Clojure forms -- will be evaluated but not included in rendered output %>

<%= Clojure forms -- replaced with result of evaluation %>

(emit x) As in ERB, the <%= syntax causes the value of the expression to be emitted to the rendered template output. The same effect can be accomplished with the emit function which is available within templates. To demonstrate, the statements in the following template snippet are functionally equivalent in that they both emit the string "Splash!" to the rendered output:

<% (emit "Splash!") %>

<%= "Splash!" %>

Goals: The Path to Version 1.0

  • Sufficient error reporting, with well-detailed error messages.
  • Permit ERB tag syntax literals to occur in templates. Follow ERB's escaping rules: <%% and %%>
  • Clarify the mechanics of the template evaluation runtime: dependencies + default deps, initial namespace, requires.
  • Accept alternative tag nomenclature, defaulting to ERB. Provide examples for Mustache, PHP, and others.
  • Accept an optional map of bindings/definitions that are made available for symbol resolution during render.
  • Provide examples: Nesting templates.
  • Round out the tests. Test against each supported version of Clojure.
  • Fast runtime performance, fast test feedback.
  • Lein and Boot tasks, to assist with adoption. Look at and
  • Investigate signing Clojars releases.
  • Declare version 1.0.0 once the community deems the ART feature-complete, reliable, and properly documented.


ART is structured as a Leiningen project.

Run the tests with

lein test

or keep a test watch with

lein test-refresh

Pull requests in accord with the simplistic goals are welcome. And include tests, or your contributions almost will certainly become broken later. Commits must include Signed-off-by indicating acceptance of the Developer's Certificate of Origin. Unproductive behavior such as unkindness towards others is not tolerated.



© Copyright Vivid Inc. EPL licensed.

You can’t perform that action at this time.