Skip to content

Instantly share code, notes, and snippets.

@5alamander
Created March 13, 2017 09:42
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 5alamander/8167f82d93536b58d622a8c74813d2fa to your computer and use it in GitHub Desktop.
Save 5alamander/8167f82d93536b58d622a8c74813d2fa to your computer and use it in GitHub Desktop.
A cool template in clojure
(ns console-demo.template)
(def delimiters ["<%" "%>"])
(def parser-regex
(re-pattern
(str "(?s)\\A"
"(?:"
"(.*?)" (first delimiters) "(.*?)" (last delimiters)
")?"
"(.*)\\z")))
(defn emit-string [s]
(print "(print " (pr-str s) ")"))
(defn emit-expr [expr]
(if (.startsWith expr "=")
(print "(print " (subs expr 1) ")")
(print expr)))
(defn- parse-string [src]
(with-out-str
(print "(do ")
(loop [src src]
(let [[_ before expr after] (re-matches parser-regex src)]
(if expr
(do (emit-string before)
(emit-expr expr)
(recur after))
(do (emit-string after)
(print ")")))))))
(defn compile-fn [args src]
(core/eval
`(core/fn ~args
(with-out-str
~(-> src parse-string read-string)))))
(defmacro template-fn
"Compile a template into a function that takes the supplied arguments."
[args source]
`(compile-fn '~args ~source))
(defn template
"Evaluate a template using the supplied bindings."
([source]
(template source {}))
([source bindings]
(let [keys (map (comp symbol name) (keys bindings))
func (compile-fn [{:keys keys}] source)]
(func bindings))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment