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
Quest 2020-03-24T01:33:06.132400Z

Specific question about the "data specs" feature in spec-tools: https://github.com/metosin/spec-tools/blob/master/docs/02_data_specs.md I want to specify a vector of elements where the vector's count = 2. Is this possible to specify using data-specs?

seancorfield 2020-03-24T01:44:01.133400Z

@quest You can certainly specify that with clojure.spec. No idea about spec-tools.

Quest 2020-03-24T01:46:00.135900Z

Yeah, the :min-count option works fine in normal specs... I'm trying to cast to clojure specs from an EDN business schema I have, proving difficult

Quest 2020-03-24T01:46:33.137200Z

I know spec2 has much improved support for runtime specs, but I need the CLJS side unfortunately

seancorfield 2020-03-24T01:47:00.137500Z

Ah, so you can't eval either...

seancorfield 2020-03-25T02:46:12.000400Z

Sounds like a good compromise for now!

Quest 2020-03-24T01:48:04.139200Z

Yeah. I had some success by doing funky things using the spec private "impl" functions, but it completely mangles the error messages when data fails validation

2020-03-24T18:03:39.141900Z

Is it possible to spec a map where either a namespaced key or another unnamespaced key is required? e.g {:my/a 1} ok, {:my-a 1} ok, {:my/a 1, :my-a 2} should also be fine, {:b 2} invalid.

kszabo 2020-03-24T18:40:29.142200Z

not directly

kszabo 2020-03-24T18:40:55.142800Z

you have to spec that with additional predicates. (s/keys) doesn’t have support for that AFAIK across req/req-un groups

2020-03-24T20:00:31.143Z

Spec V1 doesn’t really have a way to say “this map can’t contain :b”. For aliasing :my-a to :my/a you could choose a single “canonical” version of your map and use a conformer when you expect there to be variations of it.

(s/def :my/a number?)
(s/def ::m (s/keys :req [:my/a]))

(s/def ::->normalize-keys (s/conformer #(clojure.set/rename-keys % {:my-a :my/a})))

(s/valid? (s/and ::->normalize-keys ::m) {:my-a 1})   ;-> true
(s/valid? (s/and ::->normalize-keys ::m) {:my/a 1})   ;-> true
(s/valid? (s/and ::->normalize-keys ::m) {:my-a "1"}) ;-> false
(s/valid? (s/and ::->normalize-keys ::m) {:my/a "1"}) ;-> false
Depending on what your needs are for generation though this can be troublesome.

2020-03-24T20:07:22.143300Z

Yeah, it’s nice, but I wanted (s/explain) to mention the unnamespaced key if both are missing

2020-03-24T20:19:05.143500Z

@yonatanel this is kind of convoluted but:

(s/def :my/a number?)
(s/def ::my-a :my/a)

(s/def ::m (s/merge (s/nonconforming (s/or :v1 (s/keys :req [:my/a])
                                           :v2 (s/keys :req-un [::my-a])))
                    (s/keys :opt [:my/a]
                            :opt-un [::my-a])))

(s/valid? ::m {:my/a 1}) ; true
(s/valid? ::m {:my-a 1}) ; true
(s/valid? ::m {:my/a 1 :my-a 2}) ; true
(s/valid? ::m {:b 2}) ; false

(s/explain-data ::m {:b 2})
(s/exercise ::m)

2020-03-24T20:58:55.143800Z

@colinkahn Thanks. I wasn’t aware of nonconforming. Gave me some options anyway.

ag 2020-03-24T21:08:46.145900Z

how do I make a (s/coll-off ::foo), making sure that the elements are distinct by one given field? e.g.: if (s/def ::foo (s/keys :req-un [:name])), I want that all the names in the generated collection are unique.

ag 2020-03-24T21:11:59.146700Z

nevermind… figure it out… used: (s/and (s/coll-of ,,,, ) #(apply distinct? (mapv :name %)),,,