Is it possible to make generator for only some parts of a keys spec and register that as default generator? Example:
(s/def ::foo int?)
(s/def ::foo- int?)
(s/def ::bar (s/with-gen ;; must be default
(s/and
;; imagine having more keys than this
(s/keys :req-un [::foo ::foo-])
;; foo- depends on foo
(fn [{:keys [foo foo-]}]
(= foo (inc foo-))))
(fn []
(gen/bind (s/gen ::foo)
(fn [foo]
(s/gen ::bar ;; just override generator for foo-, keep all other
{::foo (fn [] (gen/return foo))
::foo- (fn [] (gen/return (dec foo))})))))))
(s/valid? ::bar {:foo 1 :foo- 0}) ;;=> true
(s/valid? ::bar {:foo 1 :foo- 1}) ;;=> false
(gen/generate (s/gen ::bar)) ;;=> StackOverflowErrorOne solution is to repeat spec in s/gen for ::bar, but that is verbose:
(s/def ::bar (s/with-gen
(s/and
(s/keys :req-un [::foo ::foo-])
(fn [{:keys [foo foo-]}]
(= foo (inc foo-))))
(fn []
(gen/bind (s/gen ::foo)
(fn [foo]
(s/gen (s/keys :req-un [::foo ::foo-]) ;; REPEAT
{::foo (fn [] (gen/return foo))
::foo- (fn [] (gen/return (dec foo)))}))))))pull the s/keys of bar out into another spec?
This: (eval (s/form ::bar)) also works:
(s/def ::bar (s/with-gen
(s/and
(s/keys :req-un [::foo ::foo-])
(fn [{:keys [foo foo-]}]
(= foo (inc foo-))))
(fn []
(gen/bind (s/gen ::foo)
(fn [foo]
(s/gen (eval (s/form ::bar))
{::foo (fn [] (gen/return foo))
::foo- (fn [] (gen/return (dec foo)))}))))))that does not seem better :)
you want to reuse something, so just pull it out and give it a new name
Yeah, s/form may not be evaluable, e.g.
(eval
(s/form
(let [bound 10]
(s/and int? #(< % bound)))))
;; => Unable to resolve symbol: bound in this context