2017-04-13 40 views
1

讓我們看看在Clojure的規格Guide給出的例子爲clojure.spec/merge發生器的兩套鑰匙的聯盟使用Clojure規格命名參數

(require '[clojure.spec  :as spec] 
     '[clojure.spec.gen :as gen]) 

(spec/def :animal/kind string?) 
(spec/def :animal/says string?) 
(spec/def :animal/common (spec/keys :req [:animal/kind :animal/says])) 
(spec/def :dog/tail? boolean?) 
(spec/def :dog/breed string?) 
(spec/def :animal/dog (spec/merge :animal/common 
            (spec/keys :req [:dog/tail? :dog/breed]))) 

從這個規範我們都可以產生數據,進而對其進行驗證:

(gen/generate (spec/gen :animal/dog)) 
=> {:animal/kind "bB", :animal/says "z9C0T465Q8OPXn5dUB8Wqk8K5Jnn", 
    :dog/tail? false, :dog/breed "B2MLQnj"} 

(spec/valid? :animal/dog 
      {:animal/kind "bB", :animal/says "z9C0T465Q8OPXn5dUB8Wqk8K5Jnn", 
       :dog/tail? false, :dog/breed "B2MLQnj"}) 
=> true 

但是,如果我們稍微修改的規範,這樣,這是對的命名參數而不是地圖的序列,像

(spec/def :animal/common (spec/keys* :req [:animal/kind :animal/says])) 
(spec/def :animal/dog (spec/merge :animal/common 
            (spec/keys* :req [:dog/tail? :dog/breed]))) 

,我們仍然可以驗證數據,對規範:

(spec/valid? :animal/dog 
      '(:animal/kind "dog" 
       :animal/says "woof" 
       :dog/tail? true 
       :dog/breed "retriever")) 
=> true 

但我們確實失去了產生數據的能力:

(gen/generate (spec/gen :animal/dog)) 

; 1. Unhandled clojure.lang.ExceptionInfo 
; Couldn't satisfy such-that predicate after 100 tries. 

這是站在我這邊的錯誤,在規範的執行錯誤,或只是clojure.spec/merge的意圖工作的方式?我們可以通過附加發生器來解決這個問題嗎?

回答

1

看看規範/合併的實現,似乎有一個特殊情況在那裏生成地圖,但不是用於生成序列的鍵/值對。我猜這是因爲它仍然是alpha,甚至沒有穩定的API,更不用說完全實現了。儘管如此,提供自己的發電機似乎仍然有用。例如:

(gen/generate (spec/gen :animal/dog {:animal/dog #(clojure.test.check.generators/return '(:animal/kind "2qAW61r3030B", :animal/says "7k", :dog/tail? true, :dog/breed "00Y8C9T25cRrSQsnjOn26a"))}))