Fork me on GitHub
#clojure-spec
<
2017-04-15
>
Alex Miller (Clojure team)01:04:40

(s/and (s/keys ...) #(xor ... %))

Alex Miller (Clojure team)01:04:07

Not that xor is a thing, but you get the idea

seancorfield01:04:47

A concrete example from our codebase @stand

(s/def :criteria/general (s/and (s/keys :req-un [(or :criteria-item/value :criteria-item/values)
                                                 :criteria-item/weight])
                                #(not (and (:value %) (:values %)))))

seancorfield02:04:53

A general criteria map must have :weight but can only have one of :value or :values.

stand02:04:54

I don't believe that would work in my case. I need a situation where neither :value or :values need appear but if one appears the other cannot. I don't think you can do an or in a keys :opt, can you?

seancorfield02:04:39

Ah, no, you cannot.

seancorfield02:04:13

But they would both just be :opt keys and you could still s/and the check that they are not both present

seancorfield02:04:53

like this

(s/def :criteria/general (s/and (s/keys :opt-un [:criteria-item/value :criteria-item/values
                                                 :criteria-item/weight])
                                #(not (and (:value %) (:values %)))))

seancorfield02:04:26

That would work for the neither case, the either case, and prevent the both case I think?