如何在 mustache 模板引擎中实现自省?

How can one achieve introspection in mustache template engine?

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

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

introspect实现吗?

如果问题是如何构建内省函数,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!!"])

它没有涵盖整个 mustache 语法,但我认为这是一个好的开始。