Fork me on GitHub
#clojure-spec
<
2019-11-05
>
murtaza5206:11:53

I am trying to specify that atleast one key should be present, ex -

(def ::city string?)
(der ::name string?)

(def my-input (s/keys :opt-un [::city ::state])
The above makes both of them optional, I want to specify that atleast one should be present in the input.

misha10:11:15

(s/def ::a string?)
(s/def ::b string?)
(s/def ::m (s/keys :req-un [(or ::a ::b)]))

(s/explain ::m {:a "1" :b "2"})
;; Success!

(s/explain ::m {:a "1" :b 2})
;; 2 - failed: string? in: [:a] at: [:b] spec: :user/b

(s/explain ::m {:a "1"})
;; Success!

(s/explain ::m {})
;; {} - failed: (or (contains? % :a) (contains? % :b)) spec: :user/m

jeremys13:11:18

Hey guys I ran into something I’d like to ask you about. I wanted to “merge” to s/keys specs using s/and. It didn’t work as I thought it would. Here is an example showing what I wanted to do:

(ns example
  (:require [clojure.spec.alpha :as s]))

(s/def ::type (s/or :s string? :i int?))

(s/def ::a ::type)
(s/def ::b ::type)

(s/def ::t1 (s/keys :req [::a]))
(s/def ::t2 (s/keys :req [::b]))

(s/def ::v1 (s/and ::t1 ::t2))
(s/def ::v2 (s/and #(s/valid? ::t1 %)
                   #(s/valid? ::t2 %)))

(def example {::a "1" ::b 2})
(s/valid? ::v1 example)
;=> false
(s/valid? ::v2 example)
;=> true
(s/explain ::v1 example)
;[:s "1"] - failed: string? in: [:example/a] at: [:example/a :s] spec: :example/type
;[:s "1"] - failed: int? in: [:example/a] at: [:example/a :i] spec: :example/type
;[:i 2] - failed: string? in: [:example/b] at: [:example/b :s] spec: :example/type
;[:i 2] - failed: int? in: [:example/b] at: [:example/b :i] spec: :example/type
;=> nil
Do I use s/and in an unintended way? Is ::v2 the correct way to do it? Did I miss something in spec’s api?

sgerguri13:11:09

@jeremys Sounds to me like you want s/merge.

jeremys13:11:32

@sgerguri as usual I missed something in the api... Thanks a lot mate

👍 4
jeremys14:11:30

It’s so logical also, as you merge maps, you merge specs about maps...

colinkahn17:11:46

Is it a good idea to define your generators in the same file as your specs? Sometimes I have generators that need my specs and vise-versa. Couldn’t tell if it was good practice to keep them together though.