Как всегда генерировать данные для дополнительных ключей в спецификации?
Если у меня есть спецификации, как
(clojure.spec/def ::person (clojure.spec/keys :req [::name ::address] :opt [::age]))
И когда я делаю
(clojure.spec.gen/generate (clojure.spec/gen ::person))
Есть ли способ сказать генератору всегда учитывать дополнительный ключ (и) при генерации данных для него?
Я знаю, что это можно сделать с помощью пользовательских генераторов, но я хотел знать, есть ли уже доступные для него функциональные возможности или, возможно, более простой подход, который не требует от меня определения пользовательского генератора.
2 ответа
Мой подход состоял в том, чтобы пройти через форму (используя 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)))))
Я думаю, что короткий ответ на ваш вопрос "нет", но вы могли бы 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
Spec W / Generator, который делает это.