Fork me on GitHub
#clojure-spec
<
2017-01-26
>
ag00:01:37

oh, another total noob question.. I need a spec that generates vector of 1 to 5 elements, each element is of another spec (map), something like this:

(s/def ::col (s/keys :req-un [::id ::title]))

(gen/generate (s/gen (s/+ ::col)))
but it has to be 1) a vector 2) of 1 to 5 elements

ag00:01:14

oh, nevermind I think I got it…

ag00:01:39

dammit specs and test.check makes me feel stupid

ag00:01:18

meh, it seems I only got the generator part

ag00:01:44

(s/with-gen vector? #(gen/vector (s/gen ::col) 2 5)) ain’t good, I need spec to conform to vector of ::col

joshjones01:01:24

@ag this?

(s/def ::id (s/int-in 1 100))
(s/def ::title string?)
(s/def ::col (s/keys :req-un [::id ::title]))
(s/def ::cols (s/coll-of ::col :kind vector?
                               :min-count 1
                               :max-count 5))
(gen/generate (s/gen ::cols))

alexmiller02:01:48

@ag for your prior question, see s/fspec

mrcnc16:01:54

is it preferable to use s/assert over s/valid? so you can disable it at runtime?

mrcnc16:01:00

they seem pretty similar

seancorfield17:01:22

To me they have very different uses: we use spec for input validation (and some coercion) so we have error handling that says (if (s/valid? ::spec value) (do-good-stuff) (handle-error)) — that’s not the same as (s/assert …)

seancorfield17:01:58

I personally don’t much like asserts — I’ve never liked them in any language — and part of that is because folks tend to turn them off in production, which is when it’s even more critical that your code doesn’t attempt to operate on invalid data. Seems backwards to me...

mrcnc17:01:16

good points @seancorfield…thx!

spieden18:01:53

same — usually check valid? then throw an ex-info with explain-data

moxaj20:01:03

specs cannot be created at runtime, right? since the api is mostly macros

schmee20:01:27

I think you can get it done with quoting and eval

moxaj21:01:31

well, maybe as a last resort .. eval is evil

bfabry21:01:33

specs being macros is what gives them reasonable reporting on failures, a spec created at runtime would have to either do away with a lot of the error description, or have a very clunky api. there was some talk of some non-macro versions of some of the spec api maybe in the future though

spieden21:01:18

seems to guide the intended usage as something static, too

spieden21:01:35

.. in a world of dynamism =)

tbaldridge21:01:08

@moxaj why is eval evil?

moxaj21:01:48

@tbaldridge well, most of the time when you use it, there's a better solution (there are exceptions of course)

tbaldridge21:01:29

That doesn't make it evil though 🙂

moxaj21:01:34

i'm pretty sure there's a workaround for my issue which does not include eval

moxaj21:01:51

well yeah, it's perfectly fine, but sometimes abused

tbaldridge21:01:34

I say this because the "eval is evil" trope is mis-applied in Lisps. Eval is evil in a language like Javascript (where the phrase comes from) where eval means concat-ing strings together. In Clojure eval is akin to something like stored procs in SQL. It makes code injection really hard

tbaldridge21:01:29

So all that being said, macros + eval works pretty well for dynamic specs, and done correctly you could even get pretty good source code mappings

moxaj21:01:23

also, i'm targeting cljc, and eval only works in bootstrapped cljs afaik