这是我为语法打嗝编写的clojure规范。
(:require
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as st]
))
(s/def ::tag (s/and
keyword?
#(re-matches #":[a-z]+([0-9]+)?"
(str %))))
(s/def ::org-content (s/cat
:tag ::tag
:content (s/+ (s/or
:str string?
:content ::org-content
))))
我在这里写了一个简单的函数规范 -
(s/fdef org-headers-h3
:args (s/cat :contact ::org-content)
:ret keyword?)
(defn org-headers-h3 [doc]
(first doc))
(st/instrument `org-headers-h3)
(org-headers-h3 [:div [:h1 "d"]])
导致以下错误 -
*Call to #'modcss2.parser/org-headers-h3 did not conform to spec:
In: [0] val: [:div [:h1 "d"]] fails spec: :modcss2.parser/tag at:
[:args :contact :tag] predicate: keyword? :clojure.spec.alpha/spec
#object[clojure.spec.alpha$regex_spec_impl$reify__1200 0x6613f384
"clojure.spec.alpha$regex_spec_impl$reify__1200@6613f384"]
:clojure.spec.alpha/value ([:div [:h1 "d"]])
:clojure.spec.alpha/args ([:div [:h1 "d"]])
:clojure.spec.alpha/failure :instrument*
我似乎对我说,我因错误的参数类型而得到错误。 但我对以下声明的看法是正确的。
(s/valid? ::org-content [:div [:h1 "d"]]) => true
答案 0 :(得分:2)
另一个s/cat
并不代表他们的嵌套,他们只是连接起来。这适用于所有正则表达式规范。
(s/conform (s/cat :foo (s/cat :bar int?)) [1]) ;=> {:foo {:bar 1}}
(s/conform (s/cat :foo (s/cat :bar int?)) [[1]]) ;=> ::s/invalid
您的:args
规范扩展为:(s/cat :contact (s/cat :tag ::tag ,,,))
要嵌套它们,您可以使用s/spec
。
(s/conform (s/cat :foo (s/spec (s/cat :bar int?))) [[1]]) ;=> {:foo {:bar 1}}
所有正则表达式规范都是这样连接的。在这种情况下,使用s/and
来检查它是否为向量并使其成为非正则表达式规范以使其正常嵌套是有意义的。
(s/conform (s/cat :foo (s/and vector? (s/cat :bar int?))) [[1]]) ;=> {:foo {:bar 1}}
所以,要解决你的问题:
(s/def ::org-content
(s/and vector?
(s/cat
:tag ::tag
:content (s/+ (s/or
:str string?
:content ::org-content)))))