Minimal scheme implementation of string templates inspired by mustache.
Put {{stuff}} inside of strings and it will be replaced by some
other stuff:
(import (scheme base)
(scheme write)
(postiche mustache))
;; "Compile" the string template (it's just a list but whatever)
(define tpl (process-template "This a {{adj}} example\n"))
;; Provide a context (as an association list) to the template
(display (apply-template tpl
'((adj . "silly"))))
will display "This is a silly example". Yay!
Syntax is inspired by mustache, but everything is not (and won't be) implemented.
{{var}} will be replaced by the value of var as provided in the
context.
Unlike (real) Mustache, there is no HTML escaping.
Template:
* {{animal}}
* {{color}}
Context:
'(( animal . "cat")
( color . "orange"))Output:
* cat
* orange
Like Mustache, it is possible to access nested elements using the .
syntax in a tag:
Template:
* {{cat.name}}
* {{cat.color}}
Context:
'((cat . ((name . "Pipoune")
(color . "Orange"))))Output:
* Pipoune
* Orange
Sections allow for conditionals and/or list. A section starts with
{{#tag}} and ends with {{/tag}}. The inner part will be rendered
zero, one, or more times, depending of the value of tag in context.
If tag is not present, or its value is #f or (), the section
simply won't be rendered:
Template:
A little {{#pred}} silly{{/pred}} example
Context:
'(( pred . #f )) ;; an empty ( '() ) context gives same resultsOutput:
A little example
If the tag evaluates to a string or an atom, the section content will be rendered:
A little {{#pred}} silly{{/pred}} example
Context:
'(( pred . "whatever" )) Output:
A little silly example
Inside of the section, the value correponding to the tag can also be
accessed with the {{.}} syntax:
A little {{#pred}}{{.}}silly{{/pred}} example
Context:
'(( pred . "contrived and" )) Output:
A little contrived and silly example
This syntax is, however, more useful if the value is a list.
Indeed, when tag corresponds to a list, the section will be repeated
for every element of the list.
Template:
Look!{{#foo}} {{.}} example!{{/foo}}
Context:
'(( foo . ("An" "Another" "A final")))Output:
Look! An example! Another example! A final example!
For those who are not afraid of nested parenthesis, it is also possible to set each individual element of the list to an association list. In this case, it is possible to access named elements of the current item:
Template:
ANIMAL NOISES
=============
{{#animals}} * {{name}}: "{{noise}}"
{{/animals}}
Context :
'((animals . (((name . "cat")
(noise . "meow"))
((name . "dog")
(noise . "woof"))
((name . "duck")
(noise . "quack")))))Output:
ANIMAL NOISES
=============
* cat: "meow"
* dog: "woof"
* duck: "quack"
Sometimes, you want something to be displayed when a value is not
set. In order to do this, you can mark an "inverted section" with the
{{^tag}}...{{/tag}} syntax.
Such "inverted section" will only be displayed if var is false or
empty, similar to the unless operator.
Template:
A little {{^pred}} silly{{/pred}} example
Context:
'()Output:
A little silly example
Depending of the language you are writing in, {{ and }} delimiters
might be annoying. It is possible to modify them by giving additional
argument to process-template:
(define my-tpl (process-template "Some «adj» delimiters" "«" "»"))
(display (apply-template my-tpl
'((adj . unusual))))
; displays "Some unusual delimiters"No HTML escaping or any escaping.
Code is written trying to conform to R7RS, but only tested with Guile at the moment.
GNU Lesser General Public License.