Hoa*_*ael 5 clojure clojurescript
大部分情况下,我与 clojure.spec 相处得很好。然而,在处理的过程中,我遇到了一个无法解决的问题unform
。这是一个让我们行动起来的 Hiccup 的宽松规范:
(require '[clojure.spec :as s])
(s/def ::hiccup
(s/and
vector?
(s/cat
:name keyword?
:attributes (s/? map?)
:contents (s/* ::contents))))
(s/def ::contents
(s/or
:element-seq (s/* ::hiccup)
:element ::hiccup
:text string?))
Run Code Online (Sandbox Code Playgroud)
现在,在我们得意忘形之前,让我们看看它是否适用于小型路过的情况。
(def example [:div])
(->> example
(s/conform ::hiccup))
;;=> {:name :h1}
Run Code Online (Sandbox Code Playgroud)
奇迹般有效。但我们可以撤销我们的一致性吗?
(->> example
(s/conform ::hiccup)
(s/unform ::hiccup))
;;=> (:div)
Run Code Online (Sandbox Code Playgroud)
嗯,那应该是一个向量。我错过了什么吗?让我们看看规范对此有什么规定。
(->> example
(s/conform ::hiccup)
(s/unform ::hiccup)
(s/explain ::hiccup))
;; val: (:div) fails spec: :user/hiccup predicate: vector?
;;=> nil
Run Code Online (Sandbox Code Playgroud)
确实,它失败了。所以问题是:我怎样才能让它正常工作?
为了有价值,我制定了一个规范来检查向量并对向量进行非形式化:
(defn vector-spec
"Create a spec that it is a vector and other conditions and unforms to a vector.
Ex (vector-spec (s/spec ::binding-form))
(vector-spec (s/* integer?))"
[form]
(let [s (s/spec (s/and vector? form))]
(reify
s/Specize
(specize* [_] s)
(specize* [_ _] s)
s/Spec
(conform* [_ x] (s/conform* s x))
(unform* [_ x] (vec (s/unform* s x))) ;; <-- important
(explain* [_ path via in x] (s/explain s path via in x))
(gen* [_ overrides path rmap] (s/gen* s overrides path rmap))
(with-gen* [_ gfn] (s/with-gen s gfn))
(describe* [_] (s/describe* s)))))
Run Code Online (Sandbox Code Playgroud)
在您的示例中,您将像这样使用它:
(s/def ::hiccup
(vector-spec
(s/cat
:name keyword?
:attributes (s/? map?)
:contents (s/* ::contents))))
Run Code Online (Sandbox Code Playgroud)