Fork me on GitHub
#clojure-spec
<
2018-02-13
>
gfredericks01:02:05

there are generators for uniqueness, like gen/vector-distinct-by; and when it has trouble finding different IDs, it increases the size, which should be sufficient here

Jakub Holý (HolyJak)09:02:25

Is there a way to derive a spec from a spec? We have a checkout flow that in each step adds something to an order and a spec for the final order. I would like to have a spec for each step of the checkout process (ie the final spec with some keys either removed or changed from required to optional). The problem is that order is not a flat map and may itself contain maps that grow across multiple steps. I want to avoid copy&paste&modify of the end spec. Any ideas? Thanks!

gklijs09:02:23

Yes, you can do things like

(def label (s/and (s/spec string?) #(> (count %) 2) #(< (count %) 40)))
(s/def ::nl-label label)
(s/def ::label (s/keys :req [::nl-label]))
not sure if it helps, but that’s how I prevented a lot of copy-pasting

gklijs09:02:01

For specs of maps there is also merge, which seems more use-full re-reading you questionhttps://clojuredocs.org/clojure.spec.alpha/merge

stathissideris12:02:56

sounds like he’d need deep-merge (which doesn’t exist afaik)

slipset13:02:52

Oh, and while on the topic of merge

slipset13:02:26

I'm quite disappointed that this is closed as "working as intended" with a

slipset13:02:30

docstring fix

slipset13:02:20

Maybe I just need to understand the rationale behind why this is intentional behaviour?

vikeri13:02:37

Any way of overriding the generators so that different specs depend on each other? My use case is testing a function where the arguments have internal relations, i.e. argument 1 contains references to argument 2. Randomly generated arguments will not have this relation naturally.

Alex Miller (Clojure team)14:02:47

independently, no. but in a shared context like an args list, yes - you can use combinators like fmap or bind to achieve this

firstclassfunc17:02:56

hey @alexmiller still a little fuzzy here. Trying to build a generator that produces a common ::id field as in

(defrecord Subscriber [name id])
(defrecord Subscribed [article id])

(s/def ::name string?)
(s/def ::article uuid?)
(s/def ::id uuid?)

(s/def ::Subscriber
  (s/keys :req-un [::name ::id]))

(s/def ::Subscribed
  (s/keys :req-un [::article ::id]))


(defn generate-subscribers
  "Mock function to generate subscribers"
  []
  (gen/sample (s/gen ::Subscriber)))


(defn generate-subscribed
  "Mock function to generate subscribed"
  []
  (gen/sample (s/gen ::Subscribed)))


Alex Miller (Clojure team)17:02:46

sorry, don’t have time to reply today but recommend: https://www.youtube.com/watch?v=WoFkhE92fqc as an intro

misha21:02:44

@slipset if you will flow conformed values through merge's "components" - you will hit false-positive invalidation.

misha21:02:11

compare:

(s/def :foo/a (s/or :s string? :i int?))
(s/def :m/one (s/keys :req [:foo/a]))
(s/def :m/two (s/keys :req [:foo/a]))
(s/def :m/merged (s/merge :m/one :m/two))

;; not flowing conformed value
(let [m {:foo/a 1}]
  (and  ;; not accurate, but illustrates the idea
    (s/conform :m/one m)
    (s/conform :m/two m)))  ;; => #:foo{:a [:i 1]}

;; flowing conformed value
(let [m {:foo/a 1}]
  (->> m
    (s/conform :m/one)
    (s/conform :m/two))) ;; => :clojure.spec.alpha/invalid

misha21:02:49

(I hope @alexmiller will call me on my BS, if it's crazy talk)