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
kenny 2020-02-06T01:06:51.149600Z

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.

kenny 2020-02-06T01:15:42.150400Z

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.

💯 1
alexmiller 2020-02-06T03:50:06.150700Z

yes, that

1
2020-02-06T16:57:01.155700Z

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?

alexmiller 2020-02-06T17:04:34.156Z

go the other way

alexmiller 2020-02-06T17:05:08.156500Z

I guess you kind of are

alexmiller 2020-02-06T17:05:28.157Z

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

alexmiller 2020-02-06T17:05:51.157400Z

and it might be the easiest way in this situation

👍 1
2020-02-06T17:06:16.157900Z

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))))

2020-02-06T17:07:39.159Z

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

2020-02-06T17:08:24.159400Z

nah that wouldn't be any easier would it?

2020-02-06T17:08:33.159700Z

I'll keep hacking away at it then

2020-02-06T17:08:33.159900Z

thanks

2020-02-06T19:09:46.161600Z

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?

seancorfield 2020-02-06T19:14:22.162200Z

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

seancorfield 2020-02-06T19:15:29.162400Z

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=> 

👀 1
1
seancorfield 2020-02-06T19:16:41.163400Z

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.

2020-02-06T19:27:07.164300Z

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

2020-02-06T19:33:55.165900Z

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

2020-02-06T19:34:48.166700Z

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

seancorfield 2020-02-06T19:35:21.167400Z

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

seancorfield 2020-02-06T19:35:51.167800Z

(instead of s/keys)

2020-02-06T19:36:13.168Z

let me test that out, thanks

2020-02-06T19:43:10.168800Z

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

2020-02-06T19:43:15.169Z

nice, many thanks!