2017-10-30 7 views
1

내 질문에 이미 답변되었지만 서브맵 사양이 붙어 있습니다.필드를 기반으로 서브맵의 내용을 지정하십시오.

나는 한마디로 그

{:type :a 
:spec {:name "a"}} 

{:type :b 
:spec {:id "b"}} 

같은 두 가지 가능성을 상상해 다음 :spec 키는 유형에 따라 달라집니다. :a 유형의 경우 :spec에는 :name 필드가 있어야하고 :b 유형의 경우에는 :id 필드가 있어야합니다. 어떤 방법을 ([: 사양 무기 호])

(s/def ::type keyword?) 

(defmulti input-type ::type) 
(defmethod input-type :a 
    [_] 
    (s/keys :req-un [::name])) 
(defmethod input-type :b 
    [_] 
    (s/keys :req-un [::id])) 
(s/def ::spec (s/multi input-type ::type)) 

(s/def ::input (s/keys :req-un [::type ::spec])) 

이 저를 알려줍니다 :

나는이 시도. 왜 나는지 생각합니다 : 어쩌면 유형이 접근 가능하지 않습니다. 그래서 (전체 맵을 기반으로 한) 더 높은 레벨의 다중 스펙을 만들려고 생각했습니다.

문제점 : 동일한 이름을 가지고 있으므로 :type을 기반으로 :spec을 정의하는 방법을 모르겠습니다. 이 작업을 수행하는 방법을 알고 있습니까?

감사

답변

0
(s/def ::type keyword?) 
(s/def ::id string?) 
(s/def ::name string?) 
(s/def :id/spec (s/keys :req-un [::id])) 
(s/def :name/spec (s/keys :req-un [::name])) 

:spec지도에 대한 두 개의 서로 다른 의미을 수용하기 위해, 우리는 다른 네임 스페이스 사람들을 정의 할 수 있습니다 :id/spec:name/spec을. 이 키워드의 비 네임 스페이스 접미사는 모두 spec이고 keys 사양은 네임 스페이스가없는 키워드를 사용합니다. 여기에있는 "가짜"네임 스페이스이지만 프로젝트의 다른 "실제"네임 스페이스에도 정의 할 수 있습니다.

(gen/sample (s/gen ::input)) 
=> 
({:type :a, :spec {:name ""}} 
{:type :b, :spec {:id "aI"}} ... 
:

(defmulti input-type :type) 
(defmethod input-type :a [_] 
    (s/keys :req-un [::type :name/spec])) 
(defmethod input-type :b [_] 
    (s/keys :req-un [::type :id/spec])) 

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

(s/valid? ::input {:type :a, :spec {:name "a"}}) 
=> true 

또한이 규격의 샘플을 얻을 수 있습니다