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
2020-01-14T11:57:42.042700Z

is there a way to spec a map according to its key? example: if key is a number, value should be a number, if key is something else then value should be a string

alexmiller 2020-01-14T13:34:33.043500Z

Yes, although it’s a little complicated

alexmiller 2020-01-14T13:36:02.045400Z

The structure is to spec it as a s/coll-of s/tuples, where each tuple is an s/or of whatever key/value is allowed

alexmiller 2020-01-14T13:36:38.046100Z

The coll-of should also have an :into {}

favila 2020-01-14T13:47:55.048100Z

something like

(s/coll-of (s/or :num-val (s/tuple number? number?)
                 :string-val (s/tuple (s/and any? (complement number?)) string?))
           :into {})

alexmiller 2020-01-14T13:57:10.048300Z

yep

2020-01-14T16:59:27.048600Z

got it, tks!

2020-01-14T17:03:02.051400Z

I ran across something unexpected when using spec alpha v1:

(s/def ::foo number?)
(s/def ::bar-ret ::foo)
(gen/generate (s/gen ::bar-ret {::bar-ret #(gen/return 100)}))
;; => -2123123
this seems to be because when overrides are applied it determines the key to pull from the overrides map using something like this:
(let [s (@#'s/specize ::bar-ret)]
  (@#'s/spec-name s))
;; => ::foo
and like that shows ::bar-ret returns ::foo. My question is whether this is by design or perhaps a bug, and is it too hacky using something like (s/def ::bar-ret (s/spec ::foo)) to get this to work?

alexmiller 2020-01-14T17:41:33.051800Z

this is a known bug (there's a ticket for it) and we plan to fix in spec 2

alexmiller 2020-01-14T17:41:42.052100Z

your workaround is fine

2020-01-14T17:41:50.052300Z

Awesome, thanks!