Is there a function to test whether a value is valid and conformed to a spec? For example, given (s/valid? ::myspec val) => true , is there an equivalent such that (s/<something>? ::myspec (s/conform ::myspec val)) => true , or alternatively a way to generate a spec for the conformed value such that (s/valid? (s/<something> ::myspec) (s/conform ::myspec val)) => true?
The problem I'm trying to solve is that I have a family of functions which expect to receive conformed values but, because user inputs are involved, need to confirm the inputs are conformed.
if you have conformed values, then s/unform should give you the unconformed value
so (s/valid? ::myspec (s/unform ::myspec conformed-value)) ?
Cool! Lemme give that a shot. Thanks!
Works, thanks! So, is this an idiomatic use of spec? Or am I running into this because I'm misusing conform?
this is an api provided for un-conforming values, so seems idiomatic to me
In case it's at all interesting, here's what I came up with:
(defn conformed-or-throw
"If x is a valid and conformed returns x. If x is valid and un-conformed,
returns (spec/conform spec x). Otherwise throws an ex-info with msg."
[spec msg x]
(if (s/valid? spec x) (s/conform spec x)
(let [unformed (try (s/unform spec x)
(catch Exception _ (throw-with-spec spec (str msg " (unable to unform)") x)))]
(if (s/valid? spec unformed) x
(throw-with-spec spec (str msg " (unformed)") unformed)))))Where throw-with-spec is:
(defn throw-with-spec [spec msg x]
(throw (ex-info (str msg "\n" (exp/expound-str spec x)
"-------------------------\n"
(with-out-str (pprint x))
"-------------------------")
{:spec spec :x x})))