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

rozważyć następujące dane:Analizowanie z clojure.spec

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

Jest to hash-mapa z jednego klucza: Nazwy o wartości wektora wektorów. Wektory wewnętrzne muszą zawierać ciąg jako pierwszy element i mogą opcjonalnie zawierać słowo kluczowe: lucky jako drugi element.

Poprzednie dwa zdania powinny być opisane z clojure.spec - Zacznijmy elementów w wektorze:

(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 

To działa. Jeśli jednak jest tylko jedna opcja. Czy analizowany wynik nie będzie wyglądał lepiej:

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

Czy można to zrobić w clojure.spec?

Dzięki temu można prowadzić:

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

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

Jednak wygląda na to, że przechodzi test ale dlaczego elementy nie są przetwarzane więcej?

Edit:ten może być rozwiązany poprzez przełączenie z alfa7 do uwolnienia alpha10, gdzie pot-of zajmuje tylko jeden argument

Wreszcie moja specyfikacja wygląda, mając wcześniej opisanych Ostrzeżenia:

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

Tylko boczna uwaga - '# (=: lucky%)' jest lepiej określona jako '# {: lucky}'. –

Odpowiedz

2

Spec nie jest zaprojektowany do zapewnienia arbitralnej transformacji danych (można do tego użyć biblioteki rdzeniowej Clojure).

Można to osiągnąć za pomocą s/conformer, ale nie zaleca się używania tej funkcji do arbitralnych transformacji w ten sposób (jest ona lepiej dostosowana do takich rzeczy, jak tworzenie niestandardowych specyfikacji).