如何在胡子模板引擎中实现内省?

时间:2015-07-22 13:15:50

标签: clojure mustache

(def template "{{name}}.{{surname}}
  {{#data}}
    * {{.}}
  {{/data}}")

(introspect template) => {:name "" :surname "" :data []}

是否有内省实施?

1 个答案:

答案 0 :(得分:4)

如果问题是如何构建内省函数,instaparse是一种方法:

(require '[instaparse.core :as insta])

(def parse
  (insta/parser
    "<moustache> = (tagged-block / word / sp)*
     <tagged-block> = comment | section | var
     comment = <tag-open> <'!'> (word | sp)* <tag-close>
     section = section-block-open (current-item / var / comment / word / sp)* <section-block-close>
     <section-block-open> = <tag-open> <'#'> name <tag-close>
     section-block-close = tag-open '/' name tag-close
     var = <tag-open> name <tag-close>
     current-item  = <tag-open> <'.'> <tag-close>
     <word> = #'[^\\s{}]+'
     <sp> = #'[\\s]+' 
     name = #'[^\\s{}]+'
     tag-open = '{{'
     tag-close = '}}'"))

(def template "{{name}}.{{surname}}
  {{#data}}
  * {{.}}
  {{/data}}")

(parse template) ;=> ([:var [:name "name"]] "." [:var [:name "surname"]] "\n  " [:var [:name "#data"]] "\n  " "*" " " [:var [:name "."]] "\n  " [:var [:name "/data"]])

(defn introspect [parsed]
  (->> (tree-seq sequential? seq parsed)
       (filter sequential?)
       (filter #(#{:var :section} (first %)))
       (map (juxt first (comp keyword last second)))
       (map #(case (first %)
               :var [(second %) ""]
               :section [(second %) []]))
       (into {})))

(assert (= {:name "" :surname "" :data []}
           (introspect (parse template))))

我包括对评论的支持,其他胡子构造应该很容易添加:

(parse "Hello {{people}}!! {{! people could be the world!!}}")
;=> ("Hello" " " [:var [:name "people"]] "!!" " " [:comment " " "people" " " "could" " " "be" " " "the" " " "world!!"])

它并不涵盖整个胡须语法,但我认为这是一个好的开始。