clojure-spec

About: http://clojure.org/about/spec Guide: http://clojure.org/guides/spec API: https://clojure.github.io/spec.alpha/clojure.spec.alpha-api.html
Felipe Marques 2020-06-05T14:09:01.133400Z

@ikitommi Hi, a few days ago you mentioned some other libs to perform spec coercion, but I forgot to take notes on its names to check it later. Could you share the names again? Also, I'm having some trouble with coercing some data using spec-tools. I'm not sure if I got the logic right. Do you have any resource explaining how the coercion works in spec-tools? Thanks very much!

ikitommi 2020-06-05T14:41:47.145400Z

Hi @marques.goncalves.fel! The slack history (& my message) is here: https://clojurians-log.clojureverse.org/clojure-spec/2020-05-19. I believe all spec-coercion libs are doing it in the same way, : given a spec, it's form is parsed and for all different specs (`or`, and, keys, integer?, any? etc.) a transforming function is selected and applied to the value. Corcion is recursive and best effort. With spec-tools:

(require '[clojure.spec.alpha :as s])
(require '[spec-tools.core :as st])

(s/def ::spec (s/nilable
                (s/nilable
                  (s/map-of
                    keyword?
                    (s/or :keys (s/keys :req-un [::c1])
                          :ks (s/coll-of (s/and int?) :into #{}))))))

(def value {"keys" {:c1 "1" ::c2 "kikka"}
            "keys2" {:c1 true}
            "ints" [1 "1" "invalid" "3"]})

(st/coerce ::spec value st/string-transformer)
;{:keys {:c1 "1", :test/c2 "kikka"}
; :keys2 {:c1 true}
; :ints #{1 "invalid" 3}}

(st/coerce ::spec value st/json-transformer)
;{:keys {:c1 "1", :test/c2 "kikka"}
; :keys2 {:c1 true}
; :ints #{"3" 1 "invalid" "1"}}

ikitommi 2020-06-05T14:43:39.146600Z

wrote few years back: https://www.metosin.fi/blog/spec-transformers/

Felipe Marques 2020-06-05T14:52:33.146900Z

Thanks for the links and explanation. Sorry for not finding the history. I looked only in slack! 😅

dev.4openID 2020-06-05T20:53:57.153300Z

Learner here. Dumb Question maybe, maybe a mindset I have a map (ex JSON) in it exists the following: {:status {:timestamp "2020-04-09T15:27:00" :status "abc"} Yes, I suppose I could change the data so that the 1st :status has a different name but that is not very elegant. If the structure remains the same, I assume you cannot redefine the :status again within the spec Is there a way int spec (some technique) that deals with this type of anomaly? I have a data set exactly like that. Any thoughts?

alexmiller 2020-06-05T21:08:14.154Z

s/keys with :req-un will match the short name of the provided spec but can use different qualified specs

alexmiller 2020-06-05T21:10:10.156100Z

(s/def :inner/status string?)
(s/def :inner/timestamp string?)
(s/def :outer/status (s/keys :req-un [:inner/status :inner/timestamp]))
(s/def :outer/map (s/keys :req-un [:outer/status]))

dev.4openID 2020-06-05T21:26:12.158200Z

(s/def :inner/status string?) (s/def :inner/timestamp string?) (s/def :outer/status (s/keys :req-un [:inner/timestamp :inner/status])) (s/def :outer/map (s/keys :req-un [:inner/status])) (s/valid? :outer/map {:status {:timestamp "2020-09" :status "abc" }}) Hi, @alexmillerseems to fail against the data. Perhaps I miss it? (s/explain-str :outer/map {:status {:timestamp "2020-09" :status "abc" }}) ;; => "{:timestamp \"2020-09\", :status \"abc\"} - failed: string? in: [:status] at: [:status] spec: :inner/status\n"

seancorfield 2020-06-05T21:47:29.159400Z

@dev.4openid That works for me:

user=> (require '[clojure.spec.alpha :as s])
nil
user=> (s/def :inner/status string?)
:inner/status
user=> (s/def :inner/timestamp string?)
:inner/timestamp
user=> (s/def :outer/status (s/keys :req-un [:inner/status :inner/timestamp]))
:outer/status
user=> (s/def :outer/map (s/keys :req-un [:outer/status]))
:outer/map
(s/valid? :outer/map {:status {:timestamp "2020-09"
                                                    :status "abc" }})
true
(s/explain-str :outer/map {:status {:timestamp "2020-09"
                               :status "abc" }})
"Success!\n"
user=> 
(you can use triple-backticks around your code to format it and make it easier to read)

dev.4openID 2020-06-05T21:59:13.161600Z

Hi @alexmiller and @seancorfield - thanks for the help - I am wrong: my fat fingers and compiling versions of the trial and error - I screwed up! 😭😀 - along day!