Mustache
is a full Mustache templating implementation for Carp.
A template is rendered via Mustache.template against a context of type
(Map String Mustache). The Mustache sumtype carries the supported value
kinds: strings, lists, nested maps, and lambdas.
(Mustache.template
"Hello, {{#users}}{{name}} {{/users}}!"
&{@"users" (Mustache.Lst [(Box.init (Mustache.Mp {@"name" (Box.init (Mustache.Str @"Ada"))}))
(Box.init (Mustache.Mp {@"name" (Box.init (Mustache.Str @"Grace"))}))])})
; => "Hello, Ada Grace !"
Supports comments, section iteration, inverted sections, object contexts, dotted names, partials, inheritance (parent and block tags), and the set-delimiter tag. Templates are parsed into an intermediate node tree before rendering, so nested sections work correctly.
Templates are processed at byte level, which is correct for ASCII and UTF-8 input as long as the delimiters themselves are ASCII.
template
(Fn [(Ref String a), (Ref (Map String Mustache) b)] String)
(template s values)
templates a Mustache-formatted
string s using the map values.
The map must be from String to Mustache. Values can be:
Str— a plain string. Empty strings are falsy for section purposes.Lst— an array of boxedMustachevalues. Empty arrays are falsy; non-empty arrays cause sections to iterate once per item. Inside a list section, bare items are bound as{{.}}andMpitems provide nested object contexts.Mp— a nested map of boxedMustachevalues. Used as a section value, it pushes its entries onto the context for the section body.Lambda— a function applied to the raw (unrendered) section body, or to the empty string when it is used in an interpolation tag. Its return value is parsed as a Mustache template and rendered against the current context, so tags the lambda emits are interpolated. A section lambda's output is parsed with the delimiters active at the section tag, an interpolated one's with the default delimiters. An interpolated lambda is called once per occurrence, and what it renders to is escaped unless the tag is{{{…}}}.
Example:
(Mustache.template
"this is a super {{ adjective }} library"
&{@"adjective" (Mustache.Str @"cool")})
Dotted names like {{a.b.c}} walk nested Mp values: the first segment is
looked up on the context stack, then each further segment must be a key of the
previous segment's map. This works in interpolation, sections, and inverted
sections. If any segment is missing or is not a map, the name is treated as
absent (renders empty / skips the section). A bare {{.}} remains the implicit
iterator.
A {{> name}} partial that stands alone on its line has that line removed, and
every non-empty line of name.mustache is indented to the tag's column before
it is parsed. The indent applies to the partial's source, not to its rendered
output, so newlines inside an interpolated value are not indented.
A {{$name}}default{{/name}} block marks a spot that can be filled in from
elsewhere; on its own it renders default. A {{<name}}...{{/name}} parent
injects name.mustache like a partial, but the blocks written directly inside
it replace the same-named blocks of the injected template. Everything else
inside a parent tag is ignored. Overrides stay in scope for partials and
further parents encountered while rendering, and when the same name is
overridden at several levels the outermost one wins.
Trimming: names inside mustache tags are trimmed, so {{ thing }} looks up
"thing". Opening and closing section markers must use consistent names,
i.e. {{/thing}} is not a close for {{^ thing }}.
Rendering nests at most 128 levels deep, and one render emits at most 1048576 bytes; each expansion costs a further 16 bytes of that same budget, so at most 65536 subtrees are expanded even when they emit nothing. Past any of these the offending subtree renders as the empty string, the same as a partial naming a missing file. The depth limit stops a partial, parent or lambda that pulls itself back in once; the byte budget stops one that pulls itself back in twice and fans out exponentially, and because it counts bytes rather than expansions it does so whatever the size of the body being repeated. The budget is shared by the whole render, so a template that legitimately emits more than 1048576 bytes — iterating over a very large list, say — is truncated too.