Fork me on GitHub
#clojure-spec
<
2017-04-05
>
qqq09:04:03

in spec, how do I say "obj" is a map, where the values are also maps ?

qqq09:04:10

i.e. it's valid to write (get-in obj [k1 k2])

bronsa09:04:06

user=> (s/def ::foo (s/map-of any? map?))
:user/foo
user=> (s/valid? ::foo {:a {:b 1}})
true

qqq09:04:28

here I could also do (s/map-of any? (s/map-of any? any?)) but the inner (s/map-of any? any?) is equiv to map? right?

qqq09:04:30

this is neat

thheller09:04:37

@qqq (s/def ::map (s/map-of any? ::map) to make it recursive

qqq09:04:52

@thheller: but that'd be wrong šŸ™‚

shafeeq09:04:06

Is there a way to send clojure spec over the wire? Iā€™m looking to dynamically fetch specs from a clojure service via a HTTP request, into my clojurescript app that needs to use these specs for validation, etc.

shafeeq09:04:32

Unfortunately, I canā€™t share these specs via cljc, because the server, and the client apps should be decoupled. So itā€™s a runtime dependency.

thheller09:04:32

@shafeeq you can put your specs into a .cljc file so they can be shared, but serializing a spec will not work

thheller09:04:39

doh šŸ˜‰

qqq09:04:41

@thheller: I (perhaps incorrectly) thought specs are just data and can be passed around like data.

ikitommi09:04:43

the s/form is the serialization format for specs. You need to recursively fetch all the related specs too.

thheller09:04:56

the specs yes but the predicates they use are not

thheller09:04:26

(s/def ::foo #(= % :foo)) cannot be serialized and transferred over the wire

ikitommi09:04:41

spiked that with a custom rmi-style ā€œspec-loaderā€ that is used to negotiate the specs over the wire.

qqq09:04:29

@thheller: ah; besides functions, are there other things that need to be serailized? (and it seems like functions can be serialized if you have a giant hashmap of keyword to functions)

qqq09:04:40

[I'm not saying this is a good idea; I'm now just curious whether it can be done.]

viesti10:04:47

user=> (let [x :foo ] (s/form (s/spec #(= % x))))
(clojure.core/fn [%] (clojure.core/= % x))

viesti10:04:51

there was discussion about dynamic scope somewhere in channel history but slack eats it šŸ™‚

shafeeq10:04:15

Well in my case, I only use clojure.core predicates, since I also need the spec to be representable via swagger as well.

shafeeq10:04:05

Iā€™m recursively walking down specs, and doing an s/form on them.

shafeeq10:04:31

On the clojurescript side, now I have to walk through this list of specs and make definitions.

shafeeq10:04:19

Would something like this work? Am I missing some other perspectives or edge cases (apart from custom functions)?

ikitommi10:04:20

nice. did similar spike before the s/form bugs were fixed, now might work on most/specs already.

ikitommi10:04:43

you eval those on the client, right?

shafeeq10:04:31

yeah, will need to do that. trying that now.

ikitommi10:04:57

that opens up a security concernā€¦ running eval on something that has come over the wire.

thheller10:04:38

you can't really eval these on the CLJS side

thheller10:04:59

that is reading not eval

thheller10:04:27

you have a symbol clojure.core/string? but now what

ikitommi10:04:29

does the upcoming spec-of-specs help here?

thheller10:04:27

as @qqq suggested you could make this work if turn everything into keywords and then define those keywords on both ends

thheller10:04:43

but really ... use .cljc (just turn the specs into a library the client/server can share)

ikitommi10:04:17

oh, true @thheller i had test evalā€™ing the forms, but only in the clj-side.

shafeeq10:04:51

@thheller from a higher level perspective: the specs on the server side will evolve with time, and we shouldnā€™t really have to compile, and build the client. The client should ideally be oblivious to changes in the specs. It should pull it down (via http), and use it.

shafeeq10:04:05

thatā€™s the idea, at least.

thheller10:04:34

then validate on the server and send the explain-data back, that is just data

shafeeq10:04:37

well, the specs are my API specification at the moment. Apart from getting a catalog of requests, Iā€™m building and coercing requests on the clojurescript side based on the spec.

shafeeq10:04:00

pretty much swagger.json, but in spec

shafeeq10:04:40

I already have this functionality implemented for swagger.json. Iā€™m moving to spec now.

qqq10:04:21

@thheller: I'm impressed by how flexible spec is. I can't imagine even asking this question in Haskell. šŸ™‚

odinodin12:04:18

Is it possible to get full spec instrumentation during ClojureScript development in your running app? (using Figwheel). Iā€™ve run cljs.spec.test/instrument which returns a list of fdefā€™ed functions, but none of the fdef functions trigger when the contract is broken.

rovanion12:04:56

Hi, I've been trying all day to figure out how to correctly spec a variable-length vector as described here: http://stackoverflow.com/questions/43230546/a-clojure-spec-that-matches-and-generates-an-ordered-vector-of-variable-length I can only seem to create a matching spec with spec/cat but it in turn will only generate lists šŸ˜•

thomas12:04:26

@rovanion can't you use the seq regex's for that?

thomas12:04:43

or is that not what you need?

shafeeq12:04:07

Iā€™m rewriting my prismatic-schema spec into clojure.spec. Thereā€™s a lot of it. Has anyone here heard of or used some utility to help with this?

rovanion12:04:47

thomas: I'm able to match them using the seq regexes, but not generate data since they generate lists and I can't seem to be able to message them that I want vectors instead.

thomas12:04:51

@rovanion just looked at our SO post... and if you do something like gen/vector ?

rovanion12:04:25

thomas: I'd have to look up how that works first. The docs are very empty when it comes to explaining its use.

Alex Miller (Clojure team)14:04:14

itā€™s not uncommon to run into this when specā€™ing a macro (the need exists in a few places in the clojure.core specs) and as you can see in the example, itā€™s quite tedious to properly solve (even that example is missing what you really want for describe/form). Weā€™ve been discussing something like s/vcat for this but Rich has several competing ideas for how to implement it and Iā€™m not sure where he will end up going with it.

ghadi17:04:21

Are they design alternatives or impl alternatives @alexmiller ?

slipset18:04:34

Following http://dev.clojure.org/jira/browse/CLJ-2141, it seems to me that Clojure is missing a predicate namespaced? which returns true if a thing is, well, namespaced.

ikitommi19:04:33

what kind of data does a (s/coll-of string? :into {}) expects?

ikitommi19:04:38

(def spec (s/coll-of string? :into {}))

(s/explain-data spec {"1" "2"})
; #:clojure.spec{:problems ({:path [], :pred string?, :val ["1" "2"], :via [], :in [0]})}

(s/explain-data spec ["1" "2"])
; nil

(s/conform spec ["1" "2"])
; CompilerException java.lang.ClassCastException

Alex Miller (Clojure team)19:04:47

@ikitommi if using :into {}, you should be using a spec for a map entry (like a 2 element tuple)

Alex Miller (Clojure team)19:04:18

Like (s/coll-of (s/tuple string? string?) :into {})

Alex Miller (Clojure team)19:04:03

@slipset I don't think that's generally useful enough

ikitommi19:04:24

thanks alex

Alex Miller (Clojure team)20:04:53

That's effectively how map-of is implemented

takeoutweight23:04:46

Is there any (idiomatic) way to attach custom s/explain data for user specs? Use case is a predicate that supplies its own context information that I'd like to have preserved in the failure message.

ghadi23:04:55

@alexmiller can you elaborate around design alternatives for vcat?

Alex Miller (Clojure team)23:04:56

@ghadi at this point I just donā€™t remember the details (and Rich did not fully elaborate on them anyways)

Alex Miller (Clojure team)23:04:11

we did talk about it for a while. I mostly remember that he didnā€™t like any of my ideas. :)

ghadi23:04:41

sounds legit