Fork me on GitHub
#clojure-spec
<
2022-08-05
>
Dan Boitnott17:08:04

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.

Alex Miller (Clojure team)17:08:10

if you have conformed values, then s/unform should give you the unconformed value

Alex Miller (Clojure team)17:08:51

so (s/valid? ::myspec (s/unform ::myspec conformed-value)) ?

Dan Boitnott17:08:52

Cool! Lemme give that a shot. Thanks!

Dan Boitnott18:08:06

Works, thanks! So, is this an idiomatic use of spec? Or am I running into this because I'm misusing conform?

Alex Miller (Clojure team)18:08:51

this is an api provided for un-conforming values, so seems idiomatic to me

👍 1
Dan Boitnott22:08:01

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)))))

Dan Boitnott22:08:02

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})))