Fork me on GitHub
#clojure-spec
<
2023-06-01
>
greg12:06:16

Hi, I noticed this behaviour that even if the keyword is not explicitly included in s/key, it is implicitly included:

(s/def :person/name string?)
(s/def :person/surname string?)
(s/def :person/email string?)
(s/def ::profile
  (s/keys :req [:person/name
                :person/surname]))

(comment
 (s/explain ::profile {:person/name "Tom"
                       :person/surname "Wilkins"
                       :person/age 29})
 ; => Success!
 
 (s/explain ::profile {:person/name "Tom"
                       :person/surname "Wilkins"
                       :person/email nil})
 ; => nil - failed: string? in: [:person/email] at: [:person/email] spec: :person/email 
In the above example :person/email is not included in ::profile but the spec is complaining about it. Can it be disabled?

Alex Miller (Clojure team)13:06:19

This is by design (see the docstring of s/keys)

greg13:06:30

Thank you @U064X3EF3, I read it. Can I compose a spec to validate a map in some other way so these namespaced spaces are not implicitly included?

greg13:06:35

The problem I'm facing is that I can't control the data I receive, and in the codebase I work with, there is lots of specs namespaced by category, here and there, often duplicated (another issue with overriding entries in registory). I'm trying to tackle these issues one by one, instead of making big changes in one go. One of these namespace specs conflicts with keys used in maps I try to validate.

Alex Miller (Clojure team)13:06:25

In short, no, with s/keys. You can instead select-keys the data to just the keys you want to check before validating

greg14:06:10

Yes, unfortunately this strategy would not work with instrumenting functions 😞

greg01:06:54

Ok, I managed to find a workaround to this problem. What I did was writing a wrapper to wrap Malli schema under Spec protocol. That map validation is performed by Malli despite the instrumentation is executed via Spec api. This way I managed to avoid s/keys behaviour. The other issue I had in the same repo was that these subspecs (`:person/name`, :person/surname , etc) were defined multiple times in different parts of the project resulting in overriding global registry. Thanks to that wrapper I also managed to avoid that problem.