expound icon indicating copy to clipboard operation
expound copied to clipboard

When `keys` spec fails, the entire map is printed out (not the summary form)

Open bhb opened this issue 6 years ago • 2 comments

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.

bhb avatar Oct 18 '18 19:10 bhb

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.

bhb avatar Oct 27 '18 21:10 bhb

@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:

  1. value-in-context is currently private, so it's awkward to use it
  2. The code special-cases an app-specific data structure (just prints the keys) but then falls back to Expound by default

bhb avatar Oct 27 '18 21:10 bhb