简体   繁体   中英

Clojure spec maps

Having two following specs:

(s/def ::x keyword?)
(s/def ::y keyword?)
(s/def ::z keyword?)

(s/def ::a
  (s/keys :req-un [::x
                   ::y]
          :opt-un [::z]))

(s/def ::b
  (s/map-of string? string?))

how do I combine ::a and ::b into ::m so the following data is valid:

(s/valid? ::m
           {:x :foo
            :y :bar
            :z :any})

(s/valid? ::m
          {:x :foo
           :y :bar})

(s/valid? ::m
          {:x :foo
           :y :bar
           :z :baz})

(s/valid? ::m
          {:x :foo
           :y :bar
           :z "baz"})

(s/valid? ::m
          {:x :foo
           :y :bar
           :t "tic"})

additionally, how do I combine ::a and ::b into ::m so the following data is invalid:

(s/valid? ::m
          {"r" "foo"
           "t" "bar"})

(s/valid? ::m
          {:x :foo
           "r" "bar"})

(s/valid? ::m
           {:x :foo
            :y :bar
            :r :any})

Neither of :


(s/def ::m (s/merge ::a ::b))

(s/def ::m (s/or :a ::a :b ::b))

works (as expected), but is there a way to match map entries in priority of the spec order?

The way it should work is the following:

  1. take all the map entries of the value (which is a map)
  2. partition the map entries into two sets. One confirming the ::a spec and the other conforming the ::b spec.
  3. The two sub-maps should conform each the relevant spec as a whole. Eg the first partition should have all the required keys.

You can do this by treating the map not as a map but as a collection of map entries, and then validate the map entries. Handling the "required" keys part has to be done by s/and'ing an additional predicate.

(s/def ::x keyword?)
(s/def ::y keyword?)
(s/def ::z keyword?)

(s/def ::entry (s/or :x (s/tuple #{::x} ::x)
                     :y (s/tuple #{::y} ::y)
                     :z (s/tuple #{::z} ::z)
                     :str (s/tuple string? string?)))

(defn req-keys? [m] (and (contains? m :x) (contains? m :y)))

(s/def ::m (s/and map? (s/coll-of ::entry :into {}) req-keys?))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM