在很大程度上,我和clojure.spec相处得很好。然而,我遇到了一个在处理unform时无法解决的问题。这里有一个松散的规范,让我们继续前进:
(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?))现在,在我们忘乎所以之前,让我们看看它是否适用于一个小的通过案例。
(def example [:div])
(->> example
(s/conform ::hiccup))
;;=> {:name :h1}就像一种护身符。但是,我们可以撤销我们的一致性吗?
(->> example
(s/conform ::hiccup)
(s/unform ::hiccup))
;;=> (:div)嗯,那应该是一个向量。我是不是遗漏了什么?让我们看看spec对此有什么看法。
(->> example
(s/conform ::hiccup)
(s/unform ::hiccup)
(s/explain ::hiccup))
;; val: (:div) fails spec: :user/hiccup predicate: vector?
;;=> nil事实上,它失败了。所以问题是:我怎样才能让它正确地工作?
发布于 2020-04-17 18:19:29
这里是延迟响应。我没有意识到这个问题有多老了,但既然我已经写了回复,我不妨提交它。
采用您为::hiccup提供的规范
(s/def ::hiccup
(s/and
vector?
(s/cat
:name keyword?
:attributes (s/? map?)
:contents (s/* ::contents))))and中的vector?规范将根据该谓词测试输入数据。不幸的是,正如您所经历的那样,它不会变形为向量。
为了解决这个问题,您可以添加一个中间规范,该规范在符合时将充当标识,而在不符合时将按照所需的方式运行。例如。
(s/def ::hiccup
(s/and vector?
(s/conformer vec vec)
(s/cat
:name keyword?
:attributes (s/? map?)
:contents (s/* ::contents))))
(s/unform ::hiccup (s/conform ::hiccup [:div]))
;;=> [:div]对于满足vector?的所有内容,(s/conformer vec vec)都将是无操作的,并且使用vec作为conformer中的不一致函数将确保取消对整个and规范的结果仍然是一个向量。
我刚开始规范自己,这就是我是如何让它按照你的意图工作的。请记住,它可能不是spec设计者打算使用的方式。
发布于 2017-02-20 23:29:33
为了更有价值,我制定了一个规范,用于检查向量并将其转换为向量:
(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)))))在您的示例中,您将像这样使用它:
(s/def ::hiccup
(vector-spec
(s/cat
:name keyword?
:attributes (s/? map?)
:contents (s/* ::contents))))https://stackoverflow.com/questions/39147258
复制相似问题