2017-06-29 19 views
1

我非常确定我需要一个多规格,它的工作原理。但我不确定如何说一个向量的关键值可以包含异构地图。如何编写一个规格,其中一个地图有一个密钥基于另一个密钥具有异构内容

我的是我的源数据我想规格:

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

这是我有问题,这取决于typevalidations键,"int""string",我想在validations不同规格键。

我很确定我必须使用multi-spec。这是我曾尝试:

(defmulti attribute-type :type) 
(defmethod attribute-type "string" [a] ::string-validations) 
(defmethod attribute-type "int" [a] ::int-validations) 

;; how to say this is a vector of int-min-validation, or int-max-validation etc. 
;; (s/+ ...) and (s/or ...) maybe? 
(s/def ::int-validations (...) 
(s/def ::string-validations (...) 

;; not sure how to incorporate these...  
(s/def ::int-min-validation (s/keys :req-un [::min])) 
(s/def ::int-max-validation (s/keys :req-un [::max])) 
(s/def ::string-presence-validation (s/keys :req-un [::presence])) 

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

(s/explain ::attribute int-attr) 
(s/explain ::attribute string-attr) 
+0

你所拥有的规格有点奇怪,如果你可以给出一个你想要规范的实际数据的例子,它会让你的意图更清晰和更容易帮助。 – Josh

+0

实际数据位于顶部,“int-attr”和“string-attr”。 – Kris

+0

好吧,我明白了 - 我似乎想要使用spec进行验证,事实上,它是用于*进一步验证的属性。也许'int-attr'和'string-attr'会在你的系统的其他部分使用,这种验证类型是有意义的,但在这里看起来很奇怪。例如,如果你想验证0到100之间的整数,使用spec,你只需要使用内置的'(s/int-in 0 101)'。 “存在”有点奇怪,甚至使用“验证”这个词似乎也表明“规范”与“验证”是等同的,这并不准确。 – Josh

回答

0

我身边与你的问题有点玩过,我没有找到一个方法来对视::type::validations键不同的规格。我其实不认为这是可能的。

我做了什么:

我定义int-validationsstring-validations如下:所以

(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 

就像我说的,我不认为:

(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-specattribute-type有一种方法可以在int-attr和中使用::validations密钥。这就是为什么我为他们定义了::int-validations::string-validations

也许我错了,不能基于类型有::validations不同的规格,如果是的话,我会很乐意找出它是可能的方式。

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

2

使用命名空间关键字允许相同的密钥,但符合规范使用两种不同的规格,即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! 
相关问题