如何编写规范,其中地图具有基于另一个键具有异构内容的键

时间:2017-06-29 10:20:47

标签: clojure clojure.spec

我很确定我需要一个多规格,这有效。但我不确定如何说作为矢量的键值可以包含异构映射。

我的源数据是我想要的:

(def int-attr { :type "int" :validations [{ :min 0 } { :max 100 }] })
(def string-attr { :type "string" :validations [{ :presence true }] })

我遇到问题的validations密钥,取决于type密钥,"int""string",我想在{{1}中使用不同的规范密钥。

我很确定我必须使用validations。这是我尝试过的:

multi-spec

2 个答案:

答案 0 :(得分:4)

使用命名空间关键字来允许相同的密钥,但使用两个不同的规范来指定值,即int/validationsstring/validations。要允许包含地图的矢量,一个好的选择是使用s/coll-of

(def int-attr { :type "int" :validations [{ :min 0 } { :max 100 }] })
(def string-attr { :type "string" :validations [{ :presence true }] })

(defmulti attribute-type :type)
(defmethod attribute-type "string" [_]
  (s/keys :req-un [::type :string/validations]))
(defmethod attribute-type "int" [_]
  (s/keys :req-un [::type :int/validations]))

(s/def :int/validations (s/coll-of :int/validation))
(s/def :string/validations (s/coll-of :string/presence))

(s/def :int/validation (s/keys :opt-un [:int/min :int/max]))
(s/def :int/min number?)
(s/def :int/max number?)
(s/def :string/presence (s/keys :req-un [::presence]))

(s/def ::attribute (s/multi-spec attribute-type ::type))

(s/explain ::attribute int-attr)    ;; => Success!
(s/explain ::attribute string-attr) ;; => Success!

答案 1 :(得分:0)

我对你的问题玩了一下,我找不到根据::validations获得::type密钥的不同规范的方法。我实际上认为不可能。

我做了什么:

我将int-validationsstring-validations定义如下:

(s/def ::int-validations (s/cat :min (s/keys :req-un [::min]) 
                                :max (s/keys :req-un [::max])))
(s/def ::string-validations (s/every (s/keys :req-un [::presence]) :count 1))

;; TESTING:
(s/valid? ::int-validations [{ :min 0 } { :max 100 }]) ;; => true
(s/valid? ::string-validations [{ :presence true }])   ;; => true

然后我定义了multi-spec attribute-type

(defmulti attribute-type ::type)

(defmethod attribute-type "int" [_]
  (s/keys :req [::type ::int-validations]))

(defmethod attribute-type "string" [_]
  (s/keys :req [::type ::string-validations]))

(s/def ::attribute (s/multi-spec attribute-type ::type))

(def int-attr { ::type "int" ::int-validations [{ :min 0 } { :max 100 }] })
(def string-attr { ::type "string" ::string-validations [{ :presence true }] })

(s/valid? ::attribute int-attr) ;; => true

就像我说的那样,我认为没有办法在::validationsint-attr中使用string-attr密钥。这就是我为他们定义::int-validations::string-validations的原因。

也许我错误的是根据类型无法为::validations制定不同的规范,如果是这样的话,我很乐意找到可行的方式。

当然,您可以将::validations定义为(s/or ::int-validations ::string-validations),但这并不能解决问题。