Fork me on GitHub
#clojure-spec
<
2017-02-26
>
ag01:02:32

Hey guys, so if I have s/keys spec, that enforces a predicate on one of the keys (so it actually requires a generator, since it cannot satisfy predicate after so many tries), how the generator part would look like for the spec like that? trivial example:

(s/with-gen
  (s/and
   (s/keys :req [:foo :bar :baz :qux :zap :dap])
   (fn [m]) (= (:foo m) 42))
  (fn []
    ;; how the generator would look like?
    ))
Do I have to generate a hashmap with (s/gen) for each key and then some logic that satisfies the constraint? Is there a better way?

ag01:02:11

I guess I would create a spec without the field(s) that I want to constraint and then merge it with another spec (with the constraint(s) and generator)

seancorfield01:02:36

Yeah, splitting it in two would be my suggestion.

seancorfield01:02:19

Since then you can (g/fmap #(assoc % :foo 42) (s/gen ::base-spec)) or something like that...

Oliver George22:02:11

It seems like I can't unform collections. What am I missing?

(require '[clojure.spec :as s])

(s/def ::text
  (s/and string?
         (s/conformer
           (fn [s] {:type ::text :value s :errors []})
           (fn [m] (:value m)))))

; GOOD: string conforms correctly
(s/conform ::text "blah")
=> {:type :user/text, :value "blah", :errors []}

; GOOD: map unforms back to string
(s/unform ::text (s/conform ::text "blah"))
=> "blah"

; Bad: collection unform has no effect
(s/unform (s/coll-of ::text) (s/conform (s/coll-of ::text) ["blah" "blah"]))
=> [{:type :user/text, :value "blah", :errors []} {:type :user/text, :value "blah", :errors []}]