2016-08-29 4 views
5
(require '[clojure.spec :as s]) 

рассмотрит следующие данные:Синтаксических с clojure.spec

(def data {:names [["Anna"  :lucky] 
        ["Peter"] 
        ["Jon"  :lucky] 
        ["Andre"  :lucky]]}) 

Это хэш-карта с одним ключом: имена, имеющим значение вектора векторов. Внутренние векторы должны содержать строку в качестве первого элемента и необязательно содержать ключевое слово: lucky, как второй элемент.

Предыдущие два предложения должны быть описаны с clojure.spec - Давайте начнем с элементами в векторе:

(s/def ::item (s/cat :name string? :lucky (s/? #(= :lucky %)))) 

(s/conform ::item ["Tom"]) 
;; {:name "Tom"} 
(s/conform ::item ["Tom" :lucky]) 
;; {:name "Tom", :lucky :lucky} 
(s/conform ::item ["Tom" :sad]) 
;; :clojure.spec/invalid 

Это работает. Однако, если есть только один вариант. Не будет ли анализируемая результат выглядеть лучше так:

`{:name "Tom", :lucky true}` or `{:name "Tom", :lucky false}` 

Можно ли это сделать в clojure.spec?

С этим, можно продолжить:

(s/def ::items (s/coll-of ::item '())) 

(s/conform ::items [["Tom" :lucky] ["Tim"]]) 
[["Tom" :lucky] ["Tim"]] 

Однако, похоже, что он проходит тест, но почему пункты не разобран больше?

Edit:Это может быть решена за счет перехода от alpha7 к высвобождению alpha10, где Coll-только из принимает один аргумент

Наконец моя спецификация выглядит, имея ранее описанные предостережений:

(s/def ::my-spec (s/keys req-un [::items])) 
+0

Просто сторона примечания - '# (=: lucky%)' лучше spec'ed как '# {: lucky}'. –

ответ

2

spec не предназначен для обеспечения произвольного преобразования данных (для этого может использоваться базовая библиотека Clojure).

Этого можно достичь с помощью s/conformer, но не рекомендуется использовать эту функцию для произвольных преобразований, подобных этому (это лучше подходит для таких вещей, как создание пользовательских спецификаций).