@seancorfield i'm not sure how to force s/check
to use my conformer
but yes that would seem to work if it were possible to do so.
i wonder if there is a "conformer registry" i could write into ?
No, I mean directly in your Spec. So it always runs when a Spec is conformed.
suppose i have a spec defined like so:
(s/def ::an-entity
(s/with-gen
::a-base-entity
#(gen/let [...] (with-meta a-base-entity-conforming-structure {:some :metadata}))))
are you suggesting to use s/and
to weave in a conformer like so:
(s/and (s/conformer ...) ::a-base-entity)
??
or something else?the base entity in this case looks like this:
(s/def ::re-frame-event
(s/and vector?
(s/cat :event-name qualified-keyword?
:params (s/* any?))))
actually i can also just share the derived event:
(s/def ::callback-func-event
(s/with-gen
::re-frame-event
#(gen/let [params (s/gen (s/coll-of any?))
triggers-failure? (gen/frequency [[1 (gen/return true)] [9 (gen/return false)]])
event-name (s/gen qualified-keyword?)]
(with-meta
(concatv [event-name] params)
{:triggers-failure? triggers-failure?}))))
Put s/conformer
in the second/last slot of s/and
That allows you to modify the (conformed) value as part of the conform process without affecting the validation.
ah, ok
(s/and ... (s/conformer #(with-meta % {:what :ever})))
-- untested but that's what I had in mind.
hmm, ok. let me try that
the problem with that is that the meta depends on a generated value
and i need to somehow "attach" that value to the generated structure
while allowing it to survive the first "conform" in the s/and
i.e., the following doesn't work because ::re-frame-event has already stripped away the meta and destructured into labeled data
(s/def ::callback-func-event
(s/with-gen
(s/and ::re-frame-event (s/conformer identity))
#(gen/let [params (s/gen (s/coll-of any?))
triggers-failure? (gen/frequency [[1 (gen/return true)] [9 (gen/return false)]])
event-name (s/gen qualified-keyword?)]
(with-meta
(concatv [event-name] params)
{:triggers-failure? triggers-failure?}))))
i could "cheat" and stuff it into the last "param" and allow my conform to strip it out of there and put it in the meta
but that kind of violates a sense of purity 🙂
and would also only work for some specific subset of cases; i.e., we're lucky in the sense that params is an s/*
of s/any
which could accommodate the data
perhaps i just make the single conformer the "spec" and forget about using s/and ?
then do the base conform within that conform
True, you could have a completely custom "predicate" that conforms as a spec...
yea, i think i'll go that route. probably the path of least resistance at this point
this works:
(defn metadata-preserving [spec]
(s/conformer
(fn [v]
(let [m (meta v)
res (s/conform spec v)]
(if (= res ::s/invalid)
res
(with-meta res m))))))
used like so:
(s/def ::a-spec
(with-gen
(metadata-preserving ::a-base-spec)
#(with-meta ( ... generation here ) {:some :meta})))
thanks!
Nice!