Skip to content

Instantly share code, notes, and snippets.

@dpk
Created November 28, 2011 20:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dpk/1402006 to your computer and use it in GitHub Desktop.
Save dpk/1402006 to your computer and use it in GitHub Desktop.
Plan: the Mustache templating system
;; An implementation of the Mustache template system. (http://mustache.github.com/)
;; See http://mustache.github.com/mustache.5.html for the format documentation
;;
;; Usage: (mustache '{employees ({name "Bob" age "34"} {name "Jim" age "27"} {name "Sally" age "54"})} "{{#employees}}\n* {{name}} is {{age}} years old\n{{/employees}}")
;; ==> "\n* Bob is 34 years old\n\n* Jim is 27 years old\n\n* Sally is 54 years old\n"
(deffn (mustache-tokens tmpl)
(regexp-split (mustache-strip-comments tmpl) r“({{(?:{.+?}|[#&^/>]?.+?)}})”))
(deffn (mustache-strip-comments tmpl)
(regexp-subst tmpl r/{{!.*?}}/ "" t))
(deffn (mustache-token-kind tok)
(if (regexp-match tok r/^{{{/)
(list 'unescaped (symbol ((regexp-match tok r/^{{{\s*(.+)\s*}}}$/) 1)))
(regexp-match tok r“^{{[#&^/>]”)
(let m (regexp-match tok r“^{{([#&^/>])\s*(.+)\s*}}$”)
(list
(if (= (m 1) "#") 'open-sect
(= (m 1) "&") 'unescaped
(= (m 1) "^") 'open-neg-sect
(= (m 1) "/") 'close-sect
(= (m 1) ">") 'partial)
(symbol (m 2))))
(regexp-match tok r/^{{/)
(list 'var (symbol ((regexp-match tok r/^{{\s*(.+)\s*}}$/) 1)))
(list 'str tok))))
(deffn (mustache-group-sections toks)
(if (nil? toks) nil
(= (caar toks) 'open-sect)
(let group (mustache-build-section (cadar toks) (cdr toks))
(cons (append (list 'sect (cadar toks)) (mustache-group-sections (car group))) (mustache-group-sections (cadr group))))
(= (caar toks) 'open-neg-sect)
(let group (mustache-build-section (cadar toks) (cdr toks))
(cons (append (list 'neg-sect (cadar toks)) (mustache-group-sections (car group))) (mustache-group-sections (cadr group))))
(cons (car toks) (mustache-group-sections (cdr toks)))))
(deffn (mustache-build-section name toks)
(if (and (= (caar toks) 'close-sect) (= (cadar toks) name))
(list nil (cdr toks))
(let gd (mustache-build-section name (cdr toks))
(list (cons (car toks) (car gd)) (cadr gd)))))
(deffn (mustache-do-section data sect)
(if (nil? data) nil
(cons? data)
(s (map (fn (datum) (mustache-do-tokens datum sect)) data))
(dictionary? data)
(mustache-do-tokens data sect)))
(deffn (mustache-neg-section data sect)
(if (not data) (mustache-do-tokens data sect)))
(deffn (mustache-do-tokens data toks)
(s (map (fn (tok)
(let kind (car tok)
(if (= kind 'str) (cadr tok)
(= kind 'var) (escape-html (data (cadr tok)))
(= kind 'unescaped) (data (cadr tok))
(= kind 'sect) (mustache-do-section (data (cadr tok)) (cddr tok))
(= kind 'neg-sect) (mustache-neg-section (data (cadr tok)) (cddr tok))
(= kind 'partial) 'nothing-here-yet))) toks)))
(deffn (mustache data tmpl)
(mustache-do-tokens data
(mustache-group-sections (map mustache-token-kind (mustache-tokens tmpl)))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment