expound
expound copied to clipboard
When `keys` spec fails, the entire map is printed out (not the summary form)
When a keys spec fails, there is no need to print out the values, and doing so means that a huge map will be printed.
There isn't a clean way to do this currently, since code to print a value is currently independent of the type of failure (in this case, the failure type is that there are missing keys).
In general, it's not possible to always summarize a map by hiding unimportant values. Consider the case where the user adds a predicate that checks the values of a map - we wouldn't want to hide those values.
However, it is true that for many predicates, it would be fine to summarize the map - if you pass in a large map and the spec expects a vector, there's no need to print all the values.
There's a balance here between making Expound easy to read in a relatively common case of large data structures, but also having a simple set of rules and not getting bogged down in special cases.
@borkdude's was to write a custom value printer:
(declare my-expound-value-str)
(def expound-opts
{:show-valid-values? false
:value-str-fn #'my-expound-value-str
:print-specs? true})
(defn my-expound-value-str
"Prints only keys if system map, else defaults to expound."
[_spec-name form path value]
(if (and (map? value)
(every? (fn [ns]
(when ns
(str/starts-with? ns "dre.app")))
(map (fn [k]
(and (keyword? k)
(namespace k)))
(keys value))))
(str (keys value))
(#'expound/value-in-context expound-opts _spec-name form path value)))
(defn my-explain-out
[explain-data]
((expound/custom-printer
expound-opts) explain-data))
(defn activate-specs
"Check spec asserts and fdefs"
[]
(alter-var-root #'s/*explain-out*
(constantly #'my-explain-out))
(s/check-asserts true)
(st/instrument))
A few things to note:
-
value-in-context
is currently private, so it's awkward to use it - The code special-cases an app-specific data structure (just prints the keys) but then falls back to Expound by default