Fork me on GitHub
#clojure-spec
<
2017-04-27
>
danielcompton02:04:11

I'm not even sure exactly what this would mean, but is it possible to 'render' a spec for display in for example a Swagger UI? I'm wanting to build a web UI for displaying the specs of commands that could be sent to the system, but I'm not sure if this is even possible, as Spec is so flexible

ikitommi05:04:50

@danielcompton we have been working on the api-docs thing, just finished on the spec -> json schema and will do the -> openapi next. also have some tooling for the runtime conforming needed to support different wire-formats. But like Schema (and ring-swagger), spec is more powerful than the openapi spec, so some information will be lost. Might be a place to do full-clojure thing, with own “spec-ui”.

ikitommi05:04:17

any schedule for cljs-port of the spec-alpha?

danielcompton05:04:33

@ikitommi yeah, I don't specifically want Swagger, it was just the closest thing I could think of, a spec-ui would be what I was after

ikitommi05:04:20

I think the spec-ui could be done easily, as the spec forms can be serialized. Also, something like the https://github.com/metosin/schema-viz but for spec. Both on todo-list, but with million other things.

thheller06:04:19

@alexmiller I would like to add the var to the ex-data in clojure.core/macroexpand-check. so v in https://github.com/clojure/clojure/blob/master/src/clj/clojure/spec.clj#L686-L698

thheller06:04:13

so either the v itself or the (->sym v) that is currently used in the message for the ex-data call

thheller06:04:54

I'm experimenting with some different error presentations and currently the var isn't accessible so can't show the root spec that failed (other than "parsing" the (.getMessage ex))

thheller06:04:23

could either do this in the macroexpand-check or in the catch that wraps the error in Compiler.java

jindrichm08:04:09

Hi -- How do you make a spec for a particular value? (partial = :value) predicate doesn't seem very idiomatic.

dergutemoritz09:04:31

Unless your value is nil or false 🙂

dergutemoritz09:04:40

But then you have specific preds

jindrichm09:04:00

Thanks! This should work fine and looks more idiomatic than partial.

vandr0iy09:04:55

Hi clojurians! How does one make up a spec for a huge nested map that may have different values for the same key but in different places? like this:

{:a [{:foo "foo1" :bar 1}, {:foo "foo2" :bar 8}]
 :b {:baz  {:foo 3 :bar "quuz"}
     :quux {:foo [1 2 3] :baz 10}}
How do I say that :foo is usually a string, but inside a certain context (b/baz in this case) it's a number, and in certain others (b/quux) it's a vector?

dergutemoritz09:04:42

@vandr0iy If you're asking how you can make s/keys behave like that, the short answer is: it's not what it was designed for but rather it relies on namespaced keywords. However, you could define keywords of the same name in different namespaces representing your various contexts and piece the specs together accordingly with :req-un and :opt-un.

mbjarland10:04:44

@vandr0iy errr....ok, they might help, but don't think they solve your different values for the same key problem, @dergutemoritz answer seems to be it

ikitommi11:04:06

@vandr0iy @U4VDXB2TU: data-spec can do that, but I would use the normal s/keys if you need to reuse the attribute specs elsewhere. If it’s just a ~one-time thing, then something like this:

(require '[clojure.spec :as s])
(require '[spec-tools.core :as st])

(def spec
  (st/data-spec
    ::foo
    {:a [{:foo string? :bar int?}]
     :b {:baz {:foo int? :bar string?}
         :quux {:foo [int?] :baz int?}}}))

(def data
  {:a [{:foo "foo1" :bar 1}, {:foo "foo2" :bar 8}]
   :b {:baz  {:foo 3 :bar "quuz"}
       :quux {:foo [1 2 3] :baz 10}}})

(s/valid? spec data)
; true

vandr0iy11:04:34

in the end I just ended up doing specs for every single element that might be recognized as a pattern in its own namespace with the same name as it's called in the data structure I want to specify - but in its own namespace. For instance:

(s/def :type1/stuff string?)
(s/def :type1/foo (s/keys :req-un [:type1/stuff]))

(s/def :type2/stuff number?)
(s/def :type2/element (s/keys :req-un [:type2/stuff]))
(s/def :type2/foo (s/coll-of :type2/element))
this way stuff is a string in a type1 element and a number in type2 one. This data would match:
(s/valid? :type1/foo {:stuff "foo"})
=> true
(s/valid? :type1/foo {:stuff 2})
=> false
(s/valid? :type2/foo [{:stuff 2} {:stuff 4}])
=> true
(s/valid? :type2/foo [{:stuff 2} {:stuff "arst"}])
=> false

Alex Miller (Clojure team)11:04:22

@ikitommi re cljs, will happen soon, after clj is done

thheller11:04:25

@alexmiller not sure, will try it. thx

ikitommi11:04:27

thanks @alexmiller, looking forward to it.

thheller11:04:29

@alexmiller yep should do, I can get the name of the spec via the meta :clojure.spec/name

thheller11:04:44

which corresponds to the var

Alex Miller (Clojure team)12:04:04

I guess I'm not sure why you want the var vs the name

thheller13:04:10

for now just the name, maybe the var later. thinking that the var might contain more metadata, will see if I need that

thheller13:04:34

probably not though