This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-02-09
Channels
- # beginners (55)
- # boot (173)
- # clara (3)
- # cljs-dev (10)
- # cljsjs (3)
- # clojars (11)
- # clojure (110)
- # clojure-austin (5)
- # clojure-berlin (13)
- # clojure-chicago (2)
- # clojure-dusseldorf (3)
- # clojure-france (24)
- # clojure-italy (4)
- # clojure-portugal (1)
- # clojure-russia (60)
- # clojure-serbia (8)
- # clojure-spec (150)
- # clojure-uk (129)
- # clojurescript (87)
- # core-logic (1)
- # cursive (75)
- # datavis (1)
- # datomic (75)
- # devcards (4)
- # dirac (17)
- # emacs (50)
- # events (2)
- # hoplon (9)
- # jobs (4)
- # jobs-discuss (37)
- # lein-figwheel (3)
- # luminus (5)
- # off-topic (54)
- # om (9)
- # om-next (5)
- # onyx (10)
- # perun (11)
- # protorepl (11)
- # quil (2)
- # rdf (2)
- # re-frame (14)
- # reagent (58)
- # ring (13)
- # ring-swagger (10)
- # rum (52)
- # spacemacs (8)
- # test-check (10)
- # untangled (17)
- # yada (34)
Hello! If i have regular fn which returns some number, how to wrap it into generator for spec?
Like, random number? This is pretty much not the point of generators. To my understanding, you're supposed to extend some existing generator by using it as a seed for your generator.
look at clojure.spec.gen/fmap
@not-raspberry i know about fmap. Can you provide some example how to use it in my question? I have fn (e.g. block-number-fn) which can produce block numbers. I have a spec for block. How to express block-number-fn as gen for block spec?
what's a block number?
an id?
it is objects
more complex structure
and without clojure.spec, how would you generate it? {:www (random) :zzz (random)}
?
i have a Java constructor
(Block. "bla" "bla")
more simple example
can you generate it based on 1 random integer/double?
forget blocks
another example
i need gen for uuid
i know that gen for uuid already in spec
but if there no one?
(UUID/randomUUID) fn return uuid
how to wrap fn with (UUID/randomUUID) into gen?
Let's limit ourselves to textual uuids.
you write a spec for a character allowed in uuid, e.g. a set of those, you get a gen for free
i understand it, this sounds like workaround
then you write a spec for a coll of those chars with rexactly 24 chars (let's say uuids have 24 chars, i dunno)
how to wrap fn above into gen?
then you write your own genetrator with fmap that maps the previous generator with a function that inserts hyphens blocks with
you miss the point - don't use null-ary functions in specs. That makes them impossible to reproduce.
be reproducable is mandatory?
(defn gen-string-thats-somewhat-funny []
(sgen/fmap
do-something-funny-with-string
(sgen/string-alphanumeric)))
where do-something-funny-with-string
is not funny itself but the results of it should be. Also it's pure.Is reproducible mandatory? Nothing is pretty much. But it's inconvenient to stand out.
I haven't found an easy way to write "non-pure" generators.
you can always discard the argument the function passed to fmap gets.
But the API overall seems to have been designed to discourage that.
reproducibility and shrinking are the two big features you get by constructing generators using the combinators
@not-raspberry thanks. went to "hammock"
@mike1452 to address your specific example, I would generate a UUID by generating a pair of longs and calling the UUID constructor
which is essentially what the builtin UUID generator does
@gfredericks can you provide source of builtin gen?
link i mean
i saw macros name in sources but can't find particular code for this
@mike1452 https://github.com/clojure/test.check/blob/test.check-0.9.0/src/main/clojure/clojure/test/check/generators.cljc#L1256
thanks
as the comments say, the jvm code there is lower level because it's faster; that wouldn't be a normal way to build generators
@gfredericks thank you, I will try it
Hello!
I have a question about the clojure.spec guide
it says: > The map spec never specifies the value spec for the attributes, only what attributes are required or optional.
but then it does look like the values are being specified
the next sentence is: > When conformance is checked on a map, it does two things - checking that the required attributes are included, and checking that every registered key has a conforming value.
you mean s/keys
?
it specifies keys that specify values
@ericnormand so what is the question eric?
they seem to contradict
does the s/keys specify values or not?
it seems that it does
no, it does not, only keys. however, when a map itself is validated or checked, the check is done to ensure that the keys specs are present, and that the values that those key specs specify are correct
ok, that's what I'm saying
the first sentence says it doesn't specify the value
it's a direct contradiction
it does
you just said it does
here's my example:
(s/def ::name string?)
(s/def ::person (s/keys :req-un [::name]))
(s/explain ::person {:name 3})
this fails with this message: In: [:name] val: 3 fails spec: :foo.core/name at: [:name] predicate: string?
the value is clearly expected to be a string
perhaps it's just a problem with the wording of that sentence
> The map spec never specifies the value spec for the attributes, only what attributes are required or optional.
to me, that means that s/keys
only deals with existence of keys, not their values
you quoted the guide which says: “The map spec never specifies the value spec for the attributes” — is this the part that you say is confusing?
@ericnormand it means that s/keys never contains specs for the values, aside from the values spec'd by the keys themselves
@tbaldridge I see, I totally misunderstood
(s/def ::mymap (s/keys :req [::mykey]))
(s/def ::mykey number?)
::mymap
does not specify the value spec for the attribute above. It only specifies which key is required.My favorite analogy: A "Car" is (s/keys [::wheels ::seats ::engine]), doesn't say what a ::wheel is, it just says "A car contains these things"
but it implicitly says the value has to be a number
ok, thanks
but I still think it's unclear enough to warrant a rephrasing
But if you say "Is this a car?", it has to check to make sure that what you say is a ::wheel is actually a ::wheel
if I had trouble with it, others probably will too
@ericnormand isn't that all covered in the spec guide? From the section on entity maps:
"Clojure programs rely heavily on passing around maps of data. A common approach in other libraries is to describe each entity type, combining both the keys it contains and the structure of their values. Rather than define attribute (key+value) specifications in the scope of the entity (the map), specs assign meaning to individual attributes, then collect them into maps using set semantics (on the keys). This approach allows us to start assigning (and sharing) semantics at the attribute level across our libraries and applications."
that combined with the sentence I quoted allows for the interpretation I made
that keys are what matter
and that if you want to conform the value yourself, you can
please take my suggestion for what it is
I think it's unclear and would help others if it were rephrased
I don't want to argue about it 🙂
I can understand why it’s confusing — (s/valid ::somemapspec {…})
could only check that the keys are there. then another (s/validextra ::somemapspec {…})
could validate both that the keys are present, and that the keys themselves are valid. i get it … but that’s not how it works
I don't understand: https://clojure.org/guides/spec already explains this about 5 different ways in the section labeled "Entity Maps". I'm not trying to argue, I'm just not sure how it could be any more explicit.
it explains it five different ways, but the first way it is explained can be read the wrong way
and it can color how the rest are interpreted
i’ve not heard anyone ask this question before, but I’m sure some people have wondered. more people are confused about how keys that are in the map are checked, even if they’re not given in :req
and :req-un
thanks for your help!
But I mean....that's the 3rd paragraph in the section. And your initial question about "the map spec never specifies" is tied to a code example as context.
To be frank, I think "read from top to bottom taking context into account" is assumed as part of the guide. At least that's my opinion.
yeah I got surprised by this one once (s/def ::foo string?) (s/valid? (s/keys) {::foo 1})
-> false
Yeah, that one is a bit surprising
(didn't know about it till I read the guide just now)
one could argue it goes against the "specify what you want in there and ignore the extras" direction spec took
specifying against extra keys makes it impossible to write backwards-compatible specs
(actually, future-proof, not backwards-compatible - it forces you to synchronize 2 services when adding an extra key)
@not-raspberry not sure we're talking about the same thing tho. I was referring to the example I mentioned, not to the fact that s/keys allows extra (unespecified) keys to be valid
I was just guessing the rationale for s/keys behaviour.
It is an interesting topic. One one hand I do like that any value of my map will be valid after I've run it through conform.
On the other hand it is silent behavior (code that is executed not based on any specs I wrote in this context).
@joshjones because the overall language around spec has been "specify what you want to check, and allow the rest to be whatever".
in my book, this is a bit too surprising. Unless you read the doc very carefully you wont know about this behavior
but the spec guide clearly states that all keys in a map will be checked for conformance
it’s definitely a “gotcha” but it’s something that is pretty quickly found, if you’re writing specs, IME
well the fact that @tbaldridge didn't know about it might be revealing 🙂
Funny enough I've been writing specs for months, and although I've encountered this, I've never understood it until now.
that's really my fault though for never reading the guide 🙂
the usual case is, write a key spec, write a map spec that doesn’t include that key, and put an invalid value for that key — that’ll uncover the “gotcha"
For better or worse, I tend to skim guides. So I like my APIs to be explicit. I can handle (s/keys :req [...] :also-check true), since I can go look up what :also-check does. It's silent behavior that can become a "gotcha"
I never encountered it personally, we have probably thousand of lines of spec and it's 99% un-* keys
i do agree that the behavior is not the most intuitive — but because i’m dense, i usually read the guides very thoroughly 😉
although all of this is also in the doc string, so double bad on me for not reading that either 🙂
well, normally when you write specs for regular situations, you’re not going to put a key in the map that is not spec’d in the map spec. but when you’re learning and “tinkering around”, trying to figure things out, it’s pretty normal thing to do imo
It has one big drawback tho, if you have a "giant map" and need to only validate 1 key it will still try to do its thing on all the others
this won't show on synthetic benchmarks like the one that's on github, but i am not sure the other frameworks do this
:opt is also useful for gen, as I don't think s/keys gens other keys, only :req and :opt
Just a random note on the open-maps discussion: I discovered that TypeScript allows open js objects but has an interesting feature called “excess property checks” - essentially, it only disallows extra keys at compile-time for literal values. This way it catches typos etc, but doesn’t prevent future growth. A pretty neat solution, I think.
We just had an awesome introduction to spec
at the Clojure Remote 2017 conference!
Adoption will increase for sure 🙂
@ericnormand just skimming the backchat, is there something that needs to be clarified in the guide? if so, let me know or file an issue at https://github.com/clojure/clojure-site/issues
issue welcome even if not sure
thanks, alex!