Jennie 🩸
Logic-less templates inspired by Moustache.
Anthrodontics is the mobile operating system for dentists. Templates are the
best and most predictable form of automation. We need something that it is
simple for users to understand, from beginners to experts. Curly brackets sit
nicely in that spectrum - so there's currently Handlebars on the extreme end
and Moustache on the other side. Jennie is a compromise that tries to achieve
the best of both worlds
Installation
Add jennie to your list of dependencies in mix.exs:
def deps do
[
{:jennie, "~> 0.9"}
]
end
Usage
Jennie.render("Hello {{name}}!", %{"name" => "World"})
# Hello World!
Syntax
Jennie speaks the familiar Moustache tags:
| Tag | Meaning |
|---|---|
{{name}} | Variable, HTML-escaped |
{{{name}}} / {{& name}} | Variable, raw (not escaped) |
{{a.b.c}} | Dotted name lookup |
{{.}} | Implicit iterator (the current context) |
{{#name}}…{{/name}} | Section — rendered when truthy, iterated over lists |
{{^name}}…{{/name}} | Inverted section — rendered when falsey/empty |
{{! comment }} | Comment (ignored) |
{{> partial}} | Partial |
On top of these, Jennie adds two conveniences.
List formatters
A variable tag may name a formatter after a pipe. When the value is a list, the items are rendered (each escaped individually) and joined:
Jennie.render("{{list | and}}", %{"list" => ["mesial", "occlusal", "distal"]})
# "mesial, occlusal, and distal"
Jennie.render("{{steps | ol}}", %{"steps" => ["Etch", "Bond"]})
# "1. Etch\n2. Bond"
Available formatters:
| Formatter | Result |
|---|---|
ol | Numbered lines (1. …, 2. …) |
and | Oxford-comma list joined with "and" |
or | Oxford-comma list joined with "or" |
join | Plain join with ", " |
join "sep" | Plain join with a custom double-quoted separator |
Only the list items are escaped — the separators and conjunctions are emitted
raw. Use {{{list | and}}} or {{& list | and}} to skip escaping the items
too. A non-list value renders as if no formatter were present, and formatters
are only allowed on variable tags (not on {{#…}} / {{^…}} sections).
Collapsible lines
A line whose non-whitespace content is entirely enclosed in sections that open and close on that same line is dropped — trailing newline and leading indentation included — when those sections render blank, instead of leaving an empty line behind:
Jennie.render("{{#opt}}Step A.{{/opt}}\nStep B.", %{"opt" => false})
# "Step B."
Any literal (non-whitespace) text outside the sections keeps the line. This is
enabled by default; pass collapse_empty_lines: false to turn it off.
Options
Jennie.render/3 and Jennie.compile/2 accept:
| Option | Default | Meaning |
|---|---|---|
:escape | HTML escaper | A (binary -> iodata) escaper |
:partials | %{} | Map of partial name to template source |
:raise_on_missing_partial | false | Raise instead of rendering "" |
:engine | Jennie.Engine | Output engine module |
:ignore_nil | false | Leave tags whose keys are absent in place |
:collapse_empty_lines | true | Drop lines whose same-line sections all render blank |
You can run mix test to see the full code coverage.