Fork me on GitHub
#clojure-spec
<
2017-01-10
>
luxbock06:01:08

if I want to use spec for runtime validation, in a situation where my functions accept a large map but only care about a few keys, I should probably create my own validation function rather than using s/valid? because it validates all of the keys in the map even if I'm looking to only validate a subset of them, right?

mpenet10:01:46

@luxbock I don't think so, it will just check what's in (s/keys ...) since map specs are "open" (can contain extra keys) there's no need to check all the entries.

mpenet10:01:11

At least that's what I assume given how it's defined

mpenet10:01:03

if you use map-of, it's another story

mpenet10:01:24

well that sucks, I wonder why it does this

mpenet10:01:07

@alexmiller any reason why this should happen?

mpenet10:01:41

In addition, the values of *all* namespace-qualified keys will be validated
(and possibly destructured) by any registered specs. Note: there is
no support for inline value specification, by design.
from the doc of s/keys

mpenet10:01:47

anyway, that's kind of odd ...

mpenet10:01:44

so using non ns keys will not trigger this

gfredericks12:01:45

currently test.check has a bunch of assertions sprinkled around for checking that the args to particular functions are generators

gfredericks12:01:27

which is something that could be somewhat accomplished with spec

gfredericks12:01:31

so I'm wondering if it's worthwhile to remove those assertions and just have specs; the downside being that error messages are worse when you haven't instrumented clojure.test.check.generators, which might not be something that users would naturally do

gfredericks12:01:58

should library authors expect that users will turn on instrumentation everywhere to debug a problem, and therefore do less runtime validation than they would otherwise do?

Alex Miller (Clojure team)13:01:27

@mpenet the whole idea behind s/keys is to register your attributes with known semantics and have them checked throughout your system. By having it validate all keys, your spec grows automatically with your system. If you want to narrow the scope, you can select-keys on the map before validating

Alex Miller (Clojure team)13:01:38

@gfredericks: I'm a little worried about the circularity issues of having specs in test.check but maybe it's fine with the dynamic loading gap

Alex Miller (Clojure team)13:01:12

I'd say you shouldn't rely on instrumentation in cases where you always want those checks (and this might be one of those places)

mpenet13:01:46

it's a bit of implicit vs explicit. So if you use ns keys you can (not that it's a good idea) just use (s/keys :req []) for your map validation

mpenet13:01:01

I personally find that odd, but I can live with it

Alex Miller (Clojure team)13:01:51

You don't even need the :req there, just (s/keys) is sufficient

gfredericks14:01:59

@alexmiller I'm pretty sure putting specs in test.check is as feasible as putting them in clojure.core 😉

gfredericks14:01:33

I can at least run the test.check test suite with instrumentation

tjtolton15:01:16

This channel needs a "quicklinks" section for newbs like me. I'm looking for materials on integrating core.spec test.check... can anyone offer me any leads? Is the core.spec workshop from the conj online anywhere?

tjtolton15:01:30

thanks, @donaldball I will take a look at that!

donaldball15:01:35

The second pinned item in this channel might also be useful

cgrand16:01:59

Hi, is there a handy way of writing a s/fdef for fns with multiple arities (and differing behaviors…)?

joshjones16:01:37

(s/alt ::arity-1 (s/cat :a int?)
       ::arity-2 (s/cat :a int? :b string?))
something like that?

joshjones16:01:19

that would be the :args of the fdef

cgrand16:01:36

I have something like

(s/fdef my-function
  :args (s/alt :1 (s/tuple ::x) :2 (s/tuple ::x ::y))
  :ret (s/alt :1 ::something :2 ::other)
  :fn #(= (key (:ret %)) (key (:args %)))
and I’d like to disentangle the two arities

cgrand16:01:32

I could wipe a macro to do

(fdef+ my-function
  (:args (s/tuple ::x) :ret ::something)
  (:args (s/tuple ::x ::y) :ret ::other))

joshjones16:01:00

for the level of separation you seem to want, that might be useful

crimeminister17:01:53

Hi folks, this is my current conundrum: https://www.refheap.com/124571

crimeminister18:01:57

Trying to figure out what the idiomatic way to validate something while "transforming" it, i.e. validate a string using a regex, and then checking that the capture groups have the required values using (spec/cat)

joshjones18:01:25

are you able to work with actual instant objects, or must it be strings?

crimeminister18:01:38

Strings would be ideal in that I could avoid a transformation step, but if that would make life easier I'd try it out

joshjones18:01:04

is your goal to just get validation of dates/times, or are you looking to leverage spec to generate data, etc.?

crimeminister18:01:31

Primary goal is to get validation, but if I could get the latter as well I'd be pretty happy

crimeminister18:01:02

If need be I could write a little transformer fn that turned my string data into, say, a map for easy validation, and another transform the map value into a string to assist with data generation

crimeminister18:01:55

I just worry that it introduces an extra step each time I make a (spec/…) call

crimeminister18:01:27

Another (bad?) option might be some macro magic to allow spec to take a :pre-transform hook

joshjones18:01:57

I think what you have now is headed in the right direction. With things like date/time, I always long to use existing libraries. The clojure.instant library (specifically the read-instant-timestamp might be of use) can be used to parse a string into a date/time. for data generation, spec provides inst-in to generate dates within a range.

crimeminister18:01:27

Thanks for the suggestion @joshjones. I think I need to take that idea away and hammock on it for a few 🙂

seancorfield18:01:55

What are folks doing for atoms in terms of spec? I thought I read about an atom-of function but can’t find any context for that now.

seancorfield18:01:48

(I recall the “don’t spec atoms, only spec their dereferenced values” advice but that doesn’t help when I have a map that contains two atoms 🙂 )

Alex Miller (Clojure team)18:01:26

It's possible that we might add something like atom-of

gfredericks18:01:10

agent-of ref-of var-of future-of promise-of generator-of

seancorfield18:01:44

@alexmiller Cool. Do you have any interim advice until that happens? 🙂

tjtolton22:01:27

anyone who has taken a look at this -- http://spootnik.org/entries/2017/01/09_an-adventure-with-clocks-component-and.html could someone explain why authorized-request has a separate, specialized test using a different function spec?

tjtolton22:01:32

err, okay, it seems kind of weird

tjtolton22:01:03

its specifying that the return value is not just a boolean, but specifically that the return is true

tjtolton22:01:42

but how can that be guaranteed since the input is generated randomly based on the spec?

schmee22:01:01

tjtolton the spec has a bunch of custom generators supplied through gen-overrides

schmee22:01:45

which ensures that only “valid” domain values get generated

tjtolton22:01:50

huh. Isn't that beyond the purview of a schema or function spec? Ensuring that data is not only in a given form, but correct according to application logic?

tjtolton22:01:16

Maybe I just need to read that a bit more carefully

gfredericks22:01:29

if it's just for testing, then that's not really part of the spec

gfredericks22:01:48

you might want your generators to be rather more specific/fancy than the specs

gfredericks22:01:14

more or less because of what you just said

bbloom23:01:22

heh, i just found a pretty interesting spec bug....

bbloom23:01:49

apparently if you define a spec for ::keys, it interferes with destructuring’s spec

bbloom23:01:55

… filing a ticket

michaeldrogalis23:01:21

Is there a preferred way to expression mutual exclusion of the presence of two keys in a map?

bbloom23:01:02

my guess would be no

michaeldrogalis23:01:21

Missed this piece on the docs:

bbloom23:01:21

xor inherently involves a “not"

michaeldrogalis23:01:26

> The :req key vector supports 'and' and 'or' for key groups: > > (s/keys :req [::x ::y (or ::secret (and ::user ::pwd))] :opt [::z])

bbloom23:01:37

oh, that’s interesting

bbloom23:01:52

it’s still not an xor tho 😉

michaeldrogalis23:01:57

It’s not quite mutual exclusion in that both can be absent, but that’s closer.

michaeldrogalis23:01:05

Heh. Stay out of my brain Brandon!

bbloom23:01:21

p xor q = (p or q) and not(p and q)

bbloom23:01:31

that not is sorta against the whole open ethos of spec

bbloom23:01:55

but of course you can do that with a predicate

michaeldrogalis23:01:16

Thanks for the thoughts 🙂 See you this week, probably.