Fork me on GitHub
#clojure-spec
<
2022-03-28
>
Oliver George04:03:55

Hello is there a way I can get better errors for something like this (below). Essentially, I'm looking to get-in a deeply nested data structure to run a predicate test on something. Wondered if someone has written some kind of spec-in which I can use.

(s/explain
  (s/and (s/cat :s map?)
         (s/and (s/conformer #(get-in % [:s :db :route :route-params :uuid])) string?))
  [{:db {:route {:route-params {:uuid 1}}}}])

1 - failed: string?  
Ideally, the explain-data should include a path which would indicate where in the nested data I should look.

colinkahn06:03:55

I think to control exactly the message you want you'd need to define a deftype implementing the spec protocols (Specize and Spec). There isn't any documentation really for how to do that since those protocols are not meant for public use (afaik). If you're ok with the message being more verbose, predicate specs are kind of self describing. For example:

(s/def ::s (s/and (s/cat :s map?)
                  #(string? (get-in % [:s :db :route :route-params :uuid]))))

(s/explain ::s [{:db {:route {:route-params {:uuid 1}}}}])
Will give you:
{:s {:db {:route {:route-params {:uuid 1}}}}} - failed: (string? (get-in % [:s :db :route :route-params :uuid])) spec: :cljs.user/s

Oliver George04:03:26

(this sort of thing gives me an incremental strategy to moving away from s/assert by mapping them over to s/fdef tests)

onetom10:03:36

Is there a way to automatically rename the unqualified keys to their fully qualified equivalent, eg. during conformance? For example:

(s/<something-like-conform>   (s/keys :req-un [:ns1/a :ns2/b])   {:a 1 :b 2})
  ;; => {:ns1/a 1, :ns2/b 2}
The idea would be to maximize the amount of code, which uses fully-qualified keys.

1
onetom08:04:33

I wonder if my question was unclear, or why hasn't it received any interaction?

Aron04:04:10

I would guess that the reason is simply people not having experience with this problem. Guessing again, I imagine that because the mapping from unqualified to qualified is always dependent on the context (could be that more than one place has unqualified that map to the same qualified, or could be that there are lots of qualified keywords but only a few places where there are unqualified versions of the, these two scenarios are indistinguishable just when looking at the keyword), and so such mappings are probably always written by hand, no one has tried to automate it. I would be very interested in the reality though, after all this guessing 😅

Linus Ericsson08:04:47

I did experience the problem. However, in my case, I found that I probably tried to overuse the conforms functionality in spec. However, there has been utility functions for update-keys https://github.com/clojure/clojure/blob/master/changes.md#33-update-keys-and-update-vals which could be used for qualifying keys. Also clojure.set/rename-keys could work`.`

thanks2 1
Aron04:04:10

I would guess that the reason is simply people not having experience with this problem. Guessing again, I imagine that because the mapping from unqualified to qualified is always dependent on the context (could be that more than one place has unqualified that map to the same qualified, or could be that there are lots of qualified keywords but only a few places where there are unqualified versions of the, these two scenarios are indistinguishable just when looking at the keyword), and so such mappings are probably always written by hand, no one has tried to automate it. I would be very interested in the reality though, after all this guessing 😅