Fork me on GitHub
#clojure-spec
<
2019-01-31
>
seancorfield00:01:31

FWIW, from spec-alpha2, latest SHA:

user=> (require '[clojure.spec-alpha2 :as s])
nil
user=> (s/def :user/foo string?)
:user/foo
user=> (s/def :user/bar :user/foo) ;;alias
:user/bar
user=> (s/exercise :user/bar 1 {:user/bar #(s/gen #{"quux"})}) ;;=> (["" ""])
(["" ""])
user=> (s/exercise :user/bar 1 {:user/foo #(s/gen #{"quux"})}) ;;=> (["quux" "quux"])
Execution error (IllegalArgumentException) at clojure.spec-alpha2.protocols/eval173$fn$G (protocols.clj:11).
No implementation of method: :gen* of protocol: #'clojure.spec-alpha2.protocols/Spec found for class: clojure.lang.PersistentHashSet
user=> (s/def :user/bar string?) ;;not alias
:user/bar
user=> (s/exercise :user/bar 1 {:user/foo #(s/gen #{"quux"})}) ;;=> (["quux" "quux"])
(["" ""])
user=> 

seancorfield00:01:50

and your custom generator example:

user=> (s/def :user/foo string?)
:user/foo
user=> (s/def :user/bar (s/with-gen :user/foo #(s/gen #{"bar"})))
:user/bar
user=> (s/exercise :user/bar 1)
Execution error (IllegalArgumentException) at clojure.spec-alpha2.protocols/eval173$fn$G (protocols.clj:11).
No implementation of method: :gen* of protocol: #'clojure.spec-alpha2.protocols/Spec found for class: clojure.lang.PersistentHashSet
user=> (s/exercise :user/bar 1 {:user/bar #(s/gen #{"quux"})})
Execution error (IllegalArgumentException) at clojure.spec-alpha2.protocols/eval173$fn$G (protocols.clj:11).
No implementation of method: :gen* of protocol: #'clojure.spec-alpha2.protocols/Spec found for class: clojure.lang.PersistentHashSet
user=> 

Alex Miller (Clojure team)01:01:41

I haven’t changed anything since we last talked

seancorfield03:01:34

That was for @misha not you @alexmiller, since he asked how his code would behave on spec2 🙂

♥️ 5
Alex Miller (Clojure team)04:01:24

ah, well the thing still to do on aliases for you affects it :)

butterguns18:01:17

I'd like to substitute a generator for an "inner" spec while testing. i.e.

;; src file
(s/def ::zip pos-int?)
(s/def ::address (s/keys :req [::zip]))
(s/def ::person (s/keys :req [::address]))

;; test file
(gen/sample (s/gen ::person) 1)
=> {::address {::zip 1}}

;; pseudo code
(gen/sample (redefine-a-spec (s/gen ::person) ::zip #{10001 10002}))
=> {::address {::zip 10001}}
How can I do this?

taylor18:01:08

s/gen takes an overrides map

borkdude18:01:31

@mattmorten stest/check also takes an overrides map in case you need that

taylor18:01:33

something like (s/gen ::person {::zip new-spec}) I think?

butterguns19:01:22

That was even simpler than I hoped for. Thanks!

👏 5
butterguns20:01:05

I have a related question. I have a coll-of ::animal, where ::animal is a multi-spec. How do I provide overrides to force the ::animal that is generated?

butterguns20:01:09

(s/def ::animal-type #{:dog :cat})
(s/def ::cat-attribute #{"very catty"})
(s/def ::dog-attribute #{"dog dog"})

(defmulti animal-type ::animal-type)
(defmethod animal-type :cat [_] (s/keys :req [::cat-attribute ::animal-type]))
(defmethod animal-type :dog [_] (s/keys :req [::dog-attribute ::animal-type]))
(s/def ::animal (s/multi-spec animal-type ::animal-type))

(s/def ::animals (s/coll-of ::animal))
(s/def ::petshop (s/keys :req [::animals]))

(gen/sample (s/gen ::petshop) 1)
=>(#:{:animals [#:{:cat-attribute "very catty", :animal-type :cat}
                #:{:dog-attribute "dog dog", :animal-type :dog}]})

;; How do I override s/gen to get a list of :cat's only? 
(gen/sample (s/gen ::petshop {??}) 1)

borkdude20:01:59

Narrator: and this was harder than he hoped for.

🤕 5
borkdude20:01:50

so the spec for cat is (s/keys :req [::cat-attribute ::animal-type])?

borkdude20:01:38

I don’t have experience with spec and multimethods, so I’ll shut up now

Alex Miller (Clojure team)20:01:47

name the spec returned by the defmethod and override it?

Alex Miller (Clojure team)20:01:24

or you’re looking for a particular branch of the multimethod to be poked?

butterguns20:01:11

I just need cats!

Alex Miller (Clojure team)20:01:16

override ::animal with the generator for the spec returned by (animal-type {::animal-type :cat}) ?

borkdude20:01:42

is multi-spec relevant here?

butterguns20:01:04

(gen/sample (s/gen ::petshop {::animal #(s/gen (animal-type {::animal-type :cat}))}) 1)