(ns spec-test.core
(:require [clojure.spec :as s]))
(s/def :user/name string?)
(s/def :common/user (s/keys :req [:user/name]))
; first version of name (using :pre)
(defn name [user]
{:pre [(s/valid? :common/user user)]}
(-> user :user/name))
; This statement works ok and returns "Elon":
(name {:user/name "Elon"})
; but this statement...
(name {:x "Elon"})
;...will throw:
CompilerException java.lang.AssertionError:
Assert failed: (s/valid? :common/user user)
; ...but then I don't get as much information
; about the error as if I would have called:
(s/explain :common/user {:x "Elon"})
;...which also contains the predicate:
val: {:x "Elon"} fails spec: :common/user
predicate: (contains? % :user/name)
; (second version of name - more verbose)
; or do I need to wite it like this:
(defn name [user]
(let [parsed (s/conform :common/user user)]
(if (= parsed ::s/invalid)
(throw (ex-info "Invalid input" (s/explain-data :common/user user)))
(-> user :user/name))))
; so that:
(name {:x "Elon"})
; ...will return:
CompilerException clojure.lang.ExceptionInfo:
Invalid input #:clojure.spec{:problems}
({:path [], :pred (contains? % :user/name),
:val {:x "Elon"}, :via [:common/user], :in []})
; It should be nice if I could be able to write it like this
; (or similar, to get a better error message):
(defn name [user]
{:pre [(s/explain :common/user user)]}
(-> user :user/name))
(ns spec-test.core
(:require [clojure.spec :as s]))
(s/def :user/name string?)
(s/def :common/user (s/keys :req [:user/name]))
;; with this little helper function...
(defn check [type data]
(if (s/valid? type data)
true
(throw (AssertionError. (s/explain type data)))))
;; I can use it in my :pre condition
(defn aname [user]
{:pre [(check :common/user user)]}
(-> user :user/name))
;; when I call name with an illegal arguement...
(aname {:x "Elon"})
;; ...it not fails and returns a better error message:
CompilerException java.lang.AssertionError: null, compiling:(/Users/joakimtengstrand/IdeaProjects/spec-test/src/spec_test/core.clj:19:1)
val: {:x "Elon"} fails spec: :common/user predicate: (contains? % :user/name)
Agreed; I was just following up on your previous comments.
But, it is useful to have something that can be used in a precondition and also shows an explanation.
I’m using, basically, (or (s/valid? spec x) (s/explain spec x)). It would be good to have this built-in too.
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit
https://groups.google.com/d/topic/clojure/H9tk04sSTWE/unsubscribe.
To unsubscribe from this group and all its topics, send an email to
clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.