Welcome! Please see the About page for a little more info on how this works.

0 votes
in Spec by
Consider the following spec

(s/def :example/name string?)
(s/def :example/age pos-int?)
(s/def :wine/age (s/and pos-int?
                        #(< 100)))
(s/def :example/employee (s/keys
                          :req [:example/string]
                          :req-un [:example/age]))

(s/explain-data :example/employee {})
;; #:clojure.spec.alpha{:problems ({:path [], :pred (clojure.core/fn [%] (clojure.core/contains? % :example/string)), :val {}, :via [:example/employee], :in []} {:path [], :pred (clojure.core/fn [%] (clojure.core/contains? % :age)), :val {}, :via [:example/employee], :in []}), :spec :example/employee, :value {}}

The explain-data in this case does give the precise problem: the map is required keys. But the user requires at least two actions to resolve the problem with ":age": either add some fake value for the required keys and look at the new explain-data OR guess which :age spec was intended and look up the spec.

The default "explain" message is fine in this case, but other spec printers may want to give users hints on how they can resolve this problem in one step. This is easy in the case of ":req" because the spec is fully qualified, but not possible in general for ":req-un".

A solution is to include the fully-qualified spec along with the failing predicate in the "problem" data above.

1 Answer

0 votes
Reference: https://clojure.atlassian.net/browse/CLJ-2277 (reported by bbrinck)