Fork me on GitHub
#clojure-spec
<
2020-02-06
>
kenny01:02:51

I just spend a solid 2 hours trying to figure out how to make a schema -> select work in Spec1. Started diving deeper into the Spec2 code to land on this https://github.com/clojure/spec-alpha2/blob/495e5ac3238be002b4de72d1c48479f6bec06bb3/src/main/clojure/clojure/alpha/spec/impl.clj#L421. I think this makes sense. I'm curious if there is more reasoning behind it since it seems like there isn't a technical reason as to why you can't have a select within a schema.

kenny01:02:42

I guess it's more of a fundamental thing -- a schema is always a set of optional attributes. If attributes become required, it cannot be a schema.

💯 4
Ben Hammond16:02:01

I'm working on generators for a spec like

(spec/keys :req-un [::interval/start
                    ::interval/end])
but I want to create linkage between the start/end dates. I've written a generator `
(defn sqlinterval-generator
to give me the interval boundaries that I want, but what is the best way to poke them in to the overal keys structure ? In the past I've used a bind and fmap to overwrite the interval boundaries AFTER the default generator has given me random ones; seems a bit non-intentional though; is there a better way?

alexmiller17:02:34

go the other way

alexmiller17:02:08

I guess you kind of are

alexmiller17:02:28

I don't think what you're doing is bad necessarily

alexmiller17:02:51

and it might be the easiest way in this situation

👍 4
Ben Hammond17:02:16

so I have this to daisy-chain the generators

(defn generator-decorate-sqlinterval
  "overwrites the gen-in values with values from the interval generator"
  [gen-in start-key end-key interval-generator]
  (test.gen/bind gen-in
    (fn [o] (test.gen/fmap
              (fn [[start end]] (assoc o start-key start
                                         end-key end))
              interval-generator))))

Ben Hammond17:02:39

I guess I'm asking if there is something like (test.gen/tuple but that will give me a map instead of a vector

Ben Hammond17:02:24

nah that wouldn't be any easier would it?

Ben Hammond17:02:33

I'll keep hacking away at it then

waffletower19:02:46

Does clojure.spec.alpha support defining a spec for a map where keys are not known in advance, but a spec exists for their values?

seancorfield19:02:22

@waffletower For qualified keys, yes, if I'm understanding you correctly. Not for unqualified keys.

seancorfield19:02:29

user=> (require '[clojure.spec.alpha :as s])
nil
user=> (s/def :my/key int?)
:my/key
user=> (s/def ::bag (s/keys))
:user/bag
user=> (s/valid? ::bag {})
true
user=> (s/valid? ::bag {:my/key "a"})
false
user=> (s/valid? ::bag {:my/key 1})
true
user=> 

4
👀 4
seancorfield19:02:41

Spec checks any (qualified) keys' values against existing specs, even if s/keys doesn't list them. But if you generate/exercise ::bag, you will only get empty maps.

waffletower19:02:07

Thanks Sean, I need something like a wildcard key, such that every key in a map would validate against a specific spec.

waffletower19:02:55

{:unknown 1
 :mystery 4
 :unspecified 7} etc.

waffletower19:02:48

And somehow link any key to be validated against (s/def ::wildcard-key int?)

seancorfield19:02:21

(s/map-of keyword? ::wildcard-key)

seancorfield19:02:51

(instead of s/keys)

waffletower19:02:13

let me test that out, thanks

waffletower19:02:10

(s/def ::wildcard-key int?)
(s/valid?
 (s/map-of keyword? ::wildcard-key)
 {:unknown 1
  :mystery 4
  :unspecified 7})
true

waffletower19:02:15

nice, many thanks!