Fork me on GitHub
David Pham05:05:33

Is it possible to share spec over wire? Or to serialize them?


@neo2551 You can get the code form of a spec with s/form -- and encode that send it over the wire -- but any predicates are going to depend on the code itself (anything beyond simple core predicates).


I'm not sure how easy it is in Spec 1 to reconstitute a spec from its form tho'. That's something that is easier with Spec 2.

Alex Miller (Clojure team)12:05:39

Just eval the form you get

David Pham05:05:10

Great! Thanks a lot!


Hmm. I think I understand the "global semantics" goals, but what about the specific case I have now? I think I am falling into answer (3) in Alex's list above. I am preparing API responses and I do want to preserve the same key names, as they will be sent to the API callers somewhere down the way. However, those responses fall outside of my app semantics boundary, and some fields will contain data in a different form (like timestamps). That is OK, but I would still like to verify some aspect of those responses — whether they are a valid ::status/status, for example. I think there is also a conflict with the "open maps" idea that Rich has been talking about. I would like to be able to validate data as being valid in terms of the supplied spec, and whatever else is in the map should not matter. I do understand the global semantics idea, just pointing out that these two might sometimes clash. I would find the ability to check only "is this a valid ::bar ?" very useful. Anyway, just wanted to describe the use case, as material for thinking.


@jrychter FWIW, Spec 2 has support for checking specs with closed maps as an option (it's a check-time option, not a spec definition time option).


Also, if it helps: what we do at work is have different (but related) sets of specs for domain, API, and persistence -- since API and persistence are constrained by external systems whereas domain is not.


Then we transform data at the boundaries between those layers as needed.

Kyle Brodie22:05:57

I am trying to spec CSV rows that are parsed into Clojure maps but I'm hitting StackOverflowError in (s/keys :req-un [::kw1 ... ::kw156]) and right now the keywords are all (s/def ::kwN string?). I mostly want this for generating examples while developing so I don't have to use spec. It works if I give Java more stack space (I'm giving it -Xss512k to match Heroku's smallest dynos) but I think I'm using spec wrong


@kyle That's certainly a lot of keys in a hash map to require all be present... I assume they have more meaningful names than kw1, kw2, etc?

Kyle Brodie22:05:53

Yeah its because the CSVs are denormalized so the columns are always there even if there is no data. I can get example data and make them into Clojure maps for my development. Just thought it would be cool to test out my functions with generated data

Kyle Brodie22:05:12

The data will be reduced to less keys after a few steps so those I should be able to spec then


If you wanted random key/value rows with random keywords and random strings, just for testing stuff, you could use

(s/def ::csv (s/map-of keyword? string? :min-count 156 :max-count 156))


I guess you could make a set of all the known keys and replace keyword? there with the set.


(s/def ::csv (s/map-of #{:kw1 :kw2 ,,, :kw156} string? :min-count 156 :max-count 156))
I think that would work (you could make the set of keys into a separate spec)

Kyle Brodie23:05:06

(s/def ::simple-row (s/map-of (set columns) string? :min-count 156 :max-count 156)) (s/exercise ::simple-row 1)

Error printing return value (ExceptionInfo) at clojure.test.check.generators/fn (generators.cljc:435).
Couldn't satisfy such-that predicate after 100 tries.
class clojure.lang.ExceptionInfo


@kyle Ah, yeah, that's because it is trying to randomly generate elements from the full set for each key but each key in the generated map needs to be distinct 😞


You'd have to wrap the key part spec with a generator that produces the full set (in some random order, if you cared).


I suspect it would be easier to wrap the whole s/map-of spec in a custom generator since all it really needs to do is zip together that set of keys with a bunch of random strings...