Fork me on GitHub
#clojure-spec
<
2019-08-03
>
hjrnunes17:08:52

Hi. Do predicates need to accept MapEntry arguments to be used with s/or? This predicate

(defn str-date-time? [v]
  (try
    (some? (f/parse (f/formatters :date-time) v))
    (catch IllegalArgumentException _
      false)))
Causes ClassCastException: clojure.lang.MapEntry cannot be cast to java.lang.String when used in an or spec. If I change the catch to Exception I get a failed validation with
Part of the value

  {:post/updated "2017-05-05T11:55:00.000Z", ...}

when conformed as

  [:str-date-time "2017-05-05T11:55:00.000Z"]
with spec
(s/def :post/updated (s/or :date-time ::tspec/date-time
                                             :str-date-time str-date-time?))
used as :req in a s/keys form. Any thoughts? Thanks

seancorfield18:08:18

@hjrnunes That sounds like you're passing a conformed value into str-date-time?

hjrnunes18:08:10

Yes it does. But it's utterly puzzling. I'm merely calling s/valid? on a map

hjrnunes18:08:48

Does s/or conform values?

seancorfield18:08:59

The result of s/or is a tagged pair, yes.

hjrnunes18:08:14

so, I should cater for this in the predicate?

seancorfield18:08:47

I need to see more of your specs to see where you're flowing a conformed value into that spec.

hjrnunes18:08:55

actually, I have the same result with string? or int?

seancorfield18:08:46

Show the context.

hjrnunes18:08:45

yes, I'm trimming stuff down. Thanks for the help

seancorfield18:08:34

Do you have s/and somewhere? That's often where a conformed value ends up flowing into another predicate.

hjrnunes18:08:57

(s/def :post/published (s/or :date-time ::tspec/date-time
                             :str-date-time str-date-time?)) ;; should be DateTime or :date-time format

(s/def :post/updated (s/or :date-time ::tspec/date-time
                           :str-date-time str-date-time?))  ;; should be DateTime or :date-time format


(s/def ::post-found (s/keys :req [:post/published
                                  :post/updated]))

(s/def :post/missing coll?)

(s/def ::post-missing (s/and ::post-found
                             (s/keys :req [:post/missing])))

seancorfield18:08:50

You probably want s/merge not s/and there.

hjrnunes18:08:41

Hmm, perhaps. So the idea is to re-use ::post-found and add another key - which is what actually happens to the data

hjrnunes18:08:56

so s/merge is the right way then?

seancorfield18:08:02

That's what s/merge is for -- to blend two s/keys specs.

hjrnunes18:08:55

I see, I read somewhere, the mailing list I think, that s/and would work. Perhaps it was in a previous version

hjrnunes18:08:51

Yep. That does it. Thank you very much!

hjrnunes18:08:44

BTW, I listened to the defn podcast you were on recently - very interesting! Best of luck and thanks for all the work!

4
seancorfield18:08:05

s/and is specifically for flowing a conformed value into another spec. For example, you might s/and one s/keys-based spec and then a predicate that checks two keys have distinct values perhaps.

seancorfield18:08:38

s/merge is for extending an s/keys-based spec with additional key specs -- like merge for maps.