clojure-spec

About: http://clojure.org/about/spec Guide: http://clojure.org/guides/spec API: https://clojure.github.io/spec.alpha/clojure.spec.alpha-api.html
2021-04-11T03:42:43.016500Z

The most annoying thing is when I make a simple example to see where it breaks down it works fine.

ikitommi 2021-04-11T06:13:35.016700Z

the data-spec is not safe as it mutates the global registry. If you have two documents with different min & max, the last one overrides the first.

ikitommi 2021-04-11T06:13:49.016900Z

How did you make it work @matti.uusitalo?

2021-04-11T20:01:07.018900Z

I'm trying to spec a large, complicated map for a bunch of game data. there are several possible states the game might be in, and the fields vary depending on which state we're in. I want a spec something like (s/def ::state-pregame (s/merge ::state-core (s/keys pregame-specific-things) {::state :states/pregame}))

2021-04-11T20:01:22.019300Z

where the key is that last bit, specifying a particular key and value pair for the pregame state.

2021-04-11T20:08:05.019600Z

oh, TIL about multi-spec, which is exactly this.

benoit 2021-04-11T20:10:20.019700Z

Yes, you have to be careful to not use data-spec for multiple documents at once. Sometimes it is an acceptable trade-off.

benoit 2021-04-11T20:35:17.019900Z

I'm not seeing a way around it if you want to use s/keys and the global registry. It does not make sense to me to define a spec on the global keyword ::values that is specific to a given map. The contract that the integers in ::values must be between :min and :max is a property of the map, not the global ::values keyword. If you still want to benefit from the s/explain infrastructure, you can always write a "local spec" like this:

(defn validate-map
  [{:keys [min max values] :as data}]
  (let [s (s/coll-of (s/int-in min max))]
    (when-not (s/valid? s values)
      (throw (ex-info "Invalid map."
                      {:explain (s/explain-data s values)})))))