如何创建一个规范,其中所有键都是可选的,但至少应包含一个指定键?

Ero*_*roc 0 clojure

我应该如何创建一个规范,在该规范中所有键都是可选的,但至少应存在一个指定的键?

(s/def ::my-spec (s/and (help-plz??)(s/keys :opt-un [::a ::b]))) 
(s/valid? ::my-spec {} => false
(s/valid? ::my-spec {:a 1}) => true 
(s/valid? ::my-spec {:b 1}) => true 
(s/valid? ::my-spec {:a 1 :b 1}) => true 
(s/valid? ::my-spec {:A1 :B 1}) => true
Run Code Online (Sandbox Code Playgroud)

Ale*_*art 6

根据文档keys

:req 键向量支持键组的“and”和“or”:

(s/keys :req [::x ::y (或 ::secret (和 ::user ::pwd))] :opt [::z])

你的代码应该是:

(s/def ::my-spec (s/keys :req-un [(or ::a ::b)]))
Run Code Online (Sandbox Code Playgroud)


Tay*_*ood 5

使用当前规范alpha,为了对keys规范和至少一个存在的检查使用相同的键集合,您将需要使用宏。(即将发布的规范2 Alpha通过公开更多用于创建规范的数据驱动API来解决此问题。)

这是您的特定示例的简要草图:

(defmacro one-or-more-keys [ks]
  (let [keyset (set (map (comp keyword name) ks))]
    `(s/and (s/keys :opt-un ~ks)
            #(some ~keyset (keys %)))))

(s/def ::my-spec (one-or-more-keys [::foo ::bar]))

(s/conform ::my-spec {:bar nil})
=> {:bar nil}
(s/conform ::my-spec {:baz nil})
=> :clojure.spec.alpha/invalid
Run Code Online (Sandbox Code Playgroud)

另外,您可以定义两次键集合,并使用一个类似的谓词s/and