Fork me on GitHub
#clojure-spec
<
2020-04-11
>
credulous13:04:10

Hi! This is definitely a novice question, but I’ve struggled for a day or so trying to figure out the best way to use spec in my re-frame application. My problems stem from not grokking spec I think.

credulous13:04:48

I’m using my app db to store form information under a :form key. Forms are stored by form-id.

credulous13:04:21

In each field the “error” is set based on a spec that gets checked on each edit:

(s/def ::id (s/and string? #(> (count %) 0)) )
(s/def ::team (s/and string? #(> (count %) 0)) )
(s/def ::nickname (s/and string? #(> (count %) 0)))
(s/def ::password (s/and string? #(> (count %) 7)) )

credulous13:04:35

(Lengths are set to zero but will change)

credulous13:04:28

But I also want to define a spec for the form as a whole, so I can pass the “signup” form above to (s/valid?). But I can’t figure out how to define the structure above, where signup has four keys, each of which have the same structure

credulous13:04:30

in :signup :team for example, I want to say signup has a map that requires a :team key, and the team key is a map that has a :value key that is defined by ::team in the snippet pasted above

shooit16:04:44

I’m not sure that I understand 100% but you might need to put each :value key into a different namespace so that they can be a distinct spec e.g :foo/value, :bar/value. You could also check out multi-spec for multimethod like dispatch on the submaps

credulous13:04:37

I can’t define a ::value spec to include in (s/keys) for :team - because what :value is is different for each sibling key in :signup

alexmiller16:04:39

spec is primarily designed to associate semantic specs with namespaced keys, so by using :value in each of these places (instead of :id/value or whatever), you are outside the sweet spot

alexmiller16:04:21

you can do this with s/keys and :req-un for unqualified keys though, but you'll need to match up the name parts of the specs

alexmiller16:04:19

(s/def :team/value ::team)  ;; same for the others
(s/def :team/team (s/keys :req-un [::team/value])) ;; same for the others
(s/def ::signup (s/keys :req-un [:team/team ..etc..]))

alexmiller16:04:23

as I said, this is outside the expected pattern so it's more work for sure

credulous18:04:18

Thanks Alex. What is the preferred way to satisfy the goal I have here, which is to independently validate the form contents and the form data as a whole? Is the correct answer to my confusion “read more”? 🙂

alexmiller19:04:40

the preferred way is to have namespaced attributes with one meaning