- Notifications
You must be signed in to change notification settings - Fork3
Racket implementation of Mustache templates
License
rcherrueau/rastache
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Racket implementation ofMustache templates.
Rastache is compliant with theMustache spec v1.1+λ
Rastache can be installed as a collection within Racket with package manager:
$ raco pkg install"git://github.com/rcherrueau/rastache.git?path=rastache"Or manually:
$ git clone git://github.com/rcherrueau/rastache.git$cd rastache/rastache$ raco link.$ raco setup
Once installed, here is the simplest way to use Rastache:
#lang racket/base(require rastache); rast-compile/render: input-port hash -> output-port(rast-compile/render (open-input-string"{{foo}}") #hash{ (foo ."bar") } (current-output-port))
The functionrast-compile/render takes three parameters, the template as an input port, the context as a hash table and an output port in which Rastache displays the rendered template.
The functionrast-compile/render is the composition of two auxiliary functions,rast-compile andrast-render. Using those two separately enables the compilation of a template and its memoization for later uses.
#lang racket/base(require rastache)(let* ([template (open-input-file"huge-template.mustache")] [compiled-template (rast-compile template)]) (define ctx1 #hash{#|context 1|#}) (define ctx2 #hash{#|context 2|#}) (define ctx3 #hash{#|context 3|#}) (for ([ctx (list ctx1 ctx2 ctx3)]) (rast-render compiled-template ctx (current-output-port)) (newline)))
Rastache also offers facilities for reading strings and files.
; rast-compile/open-string: string -> (listof token)(rast-compile/open-string"{{foo}}"); rast-compile/open-file: path -> (listof token)(rast-compile/open-file"path/to/file.mustache")
Seeexamples directory for more usage examples.
At the moment the project is under development but passes allMustache spec tests. If you want to run the tests yourself, do the following:
$ git clone git://github.com/rcherrueau/rastache.git$cd rastache/rastache/tests/$ racotest tests.rkt
The most basic tag type is the variable. A{{name}} tag in a basic template will try to find thename key in the current context.
All variables are HTML escaped by default. If you want to return unescaped HTML, use the triple mustache{{{name}}} or&.
Template:
*{{name}}*{{age}}*{{company}}*{{{company}}}*{{& company}}
Context:
#hash{ (name ."Chris") (company ."<b>GitHub</b>") }Output:
* Chris** <b>GitHub</b>*<b>GitHub</b>*<b>GitHub</b>
Dot notation may be used to access nested keys.
Template:
*{{type}}*{{delorean.name}}:{{delorean.speed}}
Context:
#hash{ (type ."Time Machine") (delorean . #hash{ (name ."DeLorean") (speed ."88 mph") }) }Output:
* Time Machine* DeLorean: 88 mph
If the value of a key is a lambda, it is called with the current context as its first argument. The second argument is a rendering function that uses the current context as its context argument.
Template:
Hello,{{lambda}}!Context:
`#hash{ (planet ."world") (lambda . ,(λ (_ render) (render"{{planet}}"))) }Output:
Hello, world!
Sections render blocks of text one or more times, depending on the value of the key in the current context.
A section begins with a pound and ends with a slash. That is,{{#person}} begins a “person” section while{{/person}} ends it.
The behavior of the section is determined by the value of the key.
Template:
Shown.{{#person}} Never shown!{{/person}}
Context:
#hash{ (person .#f) }Output:
Shown.
If theperson key exists and has a non-false value, the HTML between the pound and slash will be rendered and displayed one or more times.
When the value is a non-empty list, the text in the block will be displayed once for each item in the list. The context of the block will be set to the current item for each iteration. In this way we can loop over collections.
Template:
Death List Five:{{#death}}<b>{{name}}</b>{{/death}}
Context:
#hash{ (death . [#hash{ (name ."O-Ren Ishii") } #hash{ (name ."Vernita Green") } #hash{ (name ."Budd") } #hash{ (name ."Elle Driver") } #hash{ (name ."Bill") }]) }Output:
Death List Five:<b>O-Ren Ishii</b><b>Vernita Green</b><b>Budd</b><b>Elle Driver</b><b>Bill</b>
When looping over an array of strings, a. can be used to refer to the current item in the list.
Template:
{{#tmnt}}*{{.}}{{/tmnt}}
Context:
#hash{ (tmnt . ["Leonardo""Michelangelo""Donatello""Raphael"]) }Output:
* Leonardo* Michelangelo* Donatello* Raphael
If the value of a section key is a lambda, it is called with the section’s literal block of text, un-rendered, as its first argument. The second argument is a special rendering function that uses the current context as its context argument.
Template:
<{{#lambda}}-{{/lambda}}>
Context:
`#hash{ (planet ."Earth") (lambda . ,(λ (text render) (render (string-append text"{{planet}}" text)))) }Output:
<-Earth->
An inverted section begins with a caret (hat) and ends with a slash. That is{{^person}} begins a “person” inverted section while{{/person}} ends it.
Template:
{{#repo}}<b>{{name}}</b>{{/repo}}{{^repo}}No repos :{{{/repo}}
Context:
#hash{ (repo . []) }Output:
No repos :{Comments begin with a bang and are ignored. The following template:
<h1>Today{{! ignore me}}.</h1>
Will render as follows:
<h1>Today.</h1>
Comments may contain newlines.
Partials allow you to include other templates. It begins with a greater than sign, like{{> partialkey}}.
Thepartialkey can be a simple string, thus Rastache interpretspartialkey as a file path.
Template:
Hello{{>partials/names}}Context:
#hash{ (people . [ #hash{ (name ."Marty") } #hash{ (name ."Emmet") } #hash{ (name ."Einstein") } ]) }Partial file `partials/names’:
{{#people}},{{name}}{{/people}}
Output:
Hello, Marty, Emmet, Einstein
Thepartialkey can also be an URIs, as specified inRFC 2396. Thus Rastache uses`get-pure-port’ with redirection parameter set to1 to get the resource.
Template:
Hello{{>https://github.com/rcherrueau/rastache/raw/master/rastache/tests/partials/names}}Context:
#hash{ (people . [ #hash{ (name ."Marty") } #hash{ (name ."Emmet") } #hash{ (name ."Einstein") } ]) }Output:
Hello, Marty, Emmet, Einstein
Set Delimiter tags start with an equal sign and change the tag delimiters from{{ and}} to custom strings.
Consider the following contrived example:
*{{default_tags}}{{=<%%>=}}* <% erb_style_tags %><%={{}}=%>*{{ default_tags_again}}
Here we have a list with three items. The first item uses the default tag style, the second uses erb style as defined by the Set Delimiter tag, and the third returns to the default style after yet another Set Delimiter declaration.
I’ve given myself a project as I learn Racket. I’m particularly interested in Racket facilities for defining expander and reader and for packaging those two into a conveniently named language. For all these reasons, mustache implementation seems a good project.
Copyright (C) 2014 Ronan-Alexandre Cherrueau
This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
About
Racket implementation of Mustache templates
Resources
License
Uh oh!
There was an error while loading.Please reload this page.