如何始终为规范中的可选键生成数据?
How to always generate data for optional keys in a spec?
如果我有这样的规范
(clojure.spec/def ::person (clojure.spec/keys :req [::name ::address] :opt [::age]))
当我这样做时
(clojure.spec.gen/generate (clojure.spec/gen ::person))
有没有办法告诉生成器在为其生成数据时始终考虑可选键?
我知道这可以通过自定义生成器来完成,但我想知道是否已经有可用的功能,或者可能有更简单的方法,不需要我定义自定义生成器。
我认为对你的问题的简短回答是 "no" 但你可以 s/merge
你的规范需要可选键:
(s/def ::name string?)
(s/def ::age pos-int?)
(s/def ::person (s/keys :req [::name] :opt [::age]))
(gen/sample (s/gen ::person)) ;; ::age not always gen'd
(gen/sample ;; ::age always gen'd
(s/gen (s/merge ::person (s/keys :req [::age]))))
您可以编写一个宏来生成执行此操作的 s/keys
规范 w/generator。
我的方法是遍历该规范的形式(使用 clojure.spec.alpha/form
),如果规范是使用 clojure.spec.alpha/keys
创建的,则将可选键合并到必需键中,最后重新生成规范。
(defn merge-opt-keys
"Merges optional keys into requried keys (for specs which are created using `clojure.spec.alpha/keys`) using a spec's form/description"
[fspec]
(let [keymap (into {} (map (fn [pair] (vec pair)) (partition 2 (rest fspec))))]
(->> (cond-> {}
(contains? keymap :opt)
(assoc :req (vec (concat (keymap :req) (keymap :opt))))
(contains? keymap :opt-un)
(assoc :req-un (vec (concat (keymap :req-un) (keymap :opt-un)))))
(mapcat identity)
(cons 'clojure.spec.alpha/keys))))
(clojure.spec.alpha/def ::name string?)
(clojure.spec.alpha/def ::desc string?)
(clojure.spec.alpha/def ::book (clojure.spec.alpha/keys :req [::name] :opt [:desc]))
(clojure.spec.gen.alpha/generate (clojure.spec.alpha/gen (eval (merge-opt-keys (clojure.spec.alpha/form ::book)))))
如果我有这样的规范
(clojure.spec/def ::person (clojure.spec/keys :req [::name ::address] :opt [::age]))
当我这样做时
(clojure.spec.gen/generate (clojure.spec/gen ::person))
有没有办法告诉生成器在为其生成数据时始终考虑可选键?
我知道这可以通过自定义生成器来完成,但我想知道是否已经有可用的功能,或者可能有更简单的方法,不需要我定义自定义生成器。
我认为对你的问题的简短回答是 "no" 但你可以 s/merge
你的规范需要可选键:
(s/def ::name string?)
(s/def ::age pos-int?)
(s/def ::person (s/keys :req [::name] :opt [::age]))
(gen/sample (s/gen ::person)) ;; ::age not always gen'd
(gen/sample ;; ::age always gen'd
(s/gen (s/merge ::person (s/keys :req [::age]))))
您可以编写一个宏来生成执行此操作的 s/keys
规范 w/generator。
我的方法是遍历该规范的形式(使用 clojure.spec.alpha/form
),如果规范是使用 clojure.spec.alpha/keys
创建的,则将可选键合并到必需键中,最后重新生成规范。
(defn merge-opt-keys
"Merges optional keys into requried keys (for specs which are created using `clojure.spec.alpha/keys`) using a spec's form/description"
[fspec]
(let [keymap (into {} (map (fn [pair] (vec pair)) (partition 2 (rest fspec))))]
(->> (cond-> {}
(contains? keymap :opt)
(assoc :req (vec (concat (keymap :req) (keymap :opt))))
(contains? keymap :opt-un)
(assoc :req-un (vec (concat (keymap :req-un) (keymap :opt-un)))))
(mapcat identity)
(cons 'clojure.spec.alpha/keys))))
(clojure.spec.alpha/def ::name string?)
(clojure.spec.alpha/def ::desc string?)
(clojure.spec.alpha/def ::book (clojure.spec.alpha/keys :req [::name] :opt [:desc]))
(clojure.spec.gen.alpha/generate (clojure.spec.alpha/gen (eval (merge-opt-keys (clojure.spec.alpha/form ::book)))))