Fork me on GitHub

@roklenarcic can you give an example, where/how it limits you?


Let's say you define (s/def ::date-time (s/conformer to-date-time-string from-date-time-string)). This conforming spec will print date time object into a string (or vice versa on unform call). If you define several s/keys specs each containing some fields of this type and then you defined a merged spec with s/merge you will end up with having a situation where after conforming an object only a third of date time properties will be conformed to strings the rest will remain datetime objects and it will fail.


This sounds reasonable, although alexmiller stated many times that conformers are not for (this kind of) data transformation.


(s/def :foo/s-int (s/conformer #(Integer/valueOf ^String %) str))
(s/def :foo/a :foo/s-int)
(s/def :foo/b :foo/s-int)
(s/def :foo/merge
    (s/keys :req [:foo/a])
    (s/keys :req [:foo/b])))

(s/conform :foo/s-int "1") ;; => 1
(s/unform :foo/s-int 1) ;;=> "1"

(s/valid? :foo/merge {:foo/a "1"})  ;;=> false
(s/valid? :foo/merge {:foo/a "1" :foo/b "2"}) ;; => true
(s/conform :foo/merge {:foo/a "1" :foo/b "2"})  ;;=> #:foo{:a 1, :b 2}
(s/unform :foo/merge {:foo/a 1 :foo/b 2}) ;;=> #:foo{:a "1", :b "2"}


If data transformation is not the intent, then what IS the intent of conforming?


To tell you how exactly data is valid or invalid. The line is somewhat blurry though.


Read up threads linked in SO answer


you might be able to use s/and, which "flows" conformed values as part of validation:

(s/conform   (s/and (s/or :k keyword? :i int?) vector?)  1)
=> [:i 1]
(s/valid?  (s/and (s/or :k keyword? :i int?) vector?)  1)
=> true


(but intent readability suffers, imo)

Diego Melendez17:07:22

how do I write a s/fdef for a function that does not receive args?

Jakub Holý (HolyJak)17:07:15

I guess leave out args or eg (s/coll any? :count 0)?