clojure-spec

About: http://clojure.org/about/spec Guide: http://clojure.org/guides/spec API: https://clojure.github.io/spec.alpha/clojure.spec.alpha-api.html
2020-02-20T18:21:29.260800Z

hmm… I’m wanting to spec some data that is coming from a 3rd party library, the Ataraxy router. It always uses the namespaced keyword :ataraxy/result to contain the parsed parameters for the route; however because ataraxy is configured on a route by route basis; the exact data structure differs, yet the ring request map always contains the same namespaced keyword. It strikes me that this is an unfortunate mistake; in that the same global keyword is being used to name different data. What is the best way to spec such a thing? I’m thinking a multispec is really the only option, that could dispatch on the first argument. :ataraxy/result is a vector of the form [:route/id ,,,route-params,,,]

2020-02-20T18:22:58.261900Z

or I suppose I could coerce it into something else first 😞

2020-02-20T18:26:05.262400Z

actually thinking it’s better to just spec the functions after it, that don’t depend on the :ataraxy/result key.

alexmiller 2020-02-20T18:45:04.263200Z

you could just do something like (s/cat :route-id ::route-id :params (s/* any))

alexmiller 2020-02-20T18:45:26.263500Z

but it depends a lot what route-params is

alexmiller 2020-02-20T18:45:39.263800Z

if it's kwargs, then keys* would work great

2020-02-20T21:47:29.265100Z

my data looks like {::type "foobar" ::a ... ::b ... ::c ...} I want different s/keys validation based on the value of ::type whats the feature i'm looking for

2020-02-20T21:47:42.265500Z

it's like ~ conditional spec validation polymorphic to field value

2020-02-20T21:47:58.265900Z

i guess some sort of mulitmethod on the spec

2020-02-20T21:48:16.266100Z

reading about multi-spec now, this looks like it

2020-02-20T21:57:23.266300Z

for the :default case

2020-02-20T21:57:29.266600Z

what would be a canonical way to fail spec validation

2020-02-20T21:57:32.266900Z

defmethod tagmm :default

alexmiller 2020-02-20T21:58:20.267800Z

(s/keys*) would automatically handle all registered specs for the tail of that

2020-02-20T21:58:30.268100Z

i want default case to fail

2020-02-20T21:58:33.268300Z

validation

alexmiller 2020-02-20T21:59:01.269Z

you can definitely use multi-spec for this if that makes sense

2020-02-20T21:59:29.269800Z

what is a canonical way to implement :default

2020-02-20T21:59:36.270100Z

besides a conformer that always throws exceptions

alexmiller 2020-02-20T21:59:45.270400Z

I don't understand enough what you're doing

alexmiller 2020-02-20T21:59:49.270600Z

what does :default mean?

2020-02-20T22:00:06.271100Z

(s/def ::tag #{:a :b :c :d})
(s/def ::example-key keyword?)
(s/def ::different-key keyword?)

(defmulti tagmm :tag)
(defmethod tagmm :a [_] (s/keys :req-un [::tag ::example-key]))
(defmethod tagmm :default [_] (s/keys :req-un [::tag ::different-key]))

(s/def ::example (s/multi-spec tagmm :tag))
(gen/sample (s/gen ::example))
here's the example

2020-02-20T22:00:13.271500Z

can I do :default ::s/invalid ?

alexmiller 2020-02-20T22:00:20.271800Z

oh, you mean multi-method default

2020-02-20T22:00:30.272200Z

(defmethod tagmm :default [_] ::s/invalid) 
will test that out

alexmiller 2020-02-20T22:00:42.272600Z

the multimethod returns specs so you need to return a spec that always fails

alexmiller 2020-02-20T22:01:19.273200Z

so probably more (constantly false) would work

2020-02-20T22:01:32.273500Z

ok great

alexmiller 2020-02-20T22:02:00.273800Z

or #{}

2020-02-20T22:02:08.274300Z

that seems more canonical

alexmiller 2020-02-20T22:02:11.274500Z

a set of no values :)

2020-02-20T22:02:14.274600Z

particular in the spec explanations

2020-02-20T22:02:19.274800Z

it'd be nice to get something that made sense

vemv 2020-02-20T23:45:32.278900Z

a q out of curiosity more than anything else: (spec/valid? (spec/coll-of char? :min-count 1 :max-count 20) "abc") doesn't work (and a straightforward impl would underperform anyway?) are there spec-related libraries offering a coll-of-like API that efficiently works on strings? I just like coll-of's API, in that it doesn't resemble regex