Fork me on GitHub
#clojure-spec
<
2017-11-03
>
James Vickers01:11:04

What is the shape of the data that gets passed to the :fn argument of s/fdef? Does someone have an example of that (or a way to print it)?

taylor01:11:57

it’s a map with :ret and :args keys

taylor01:11:39

the :args value is the conformed value of the args I think

taylor01:11:36

:fn (fn [{:keys [args ret]}]
              ...

James Vickers01:11:45

Thanks. Is that in the docs somewhere?

Alex Miller (Clojure team)01:11:52

That is all correct - the values of the map are the confirmed values of the args and ret specs

Alex Miller (Clojure team)01:11:25

I’m not sure where it would be doc’ed in the docstrings

taylor01:11:46

:fn A spec of the relationship between args and ret - the
  value passed is {:args conformed-args :ret conformed-ret} and is
  expected to contain predicates that relate those values

taylor01:11:52

fdef docstring

James Vickers01:11:41

So, if the function returns a single value (like a number), then (% :ret) in the :fn spec should yield the return value?

Alex Miller (Clojure team)01:11:41

Depends on the ret spec

taylor01:11:51

it might be tagged/conformed though I guess?

Alex Miller (Clojure team)01:11:52

If it’s a simple pred then yes

James Vickers01:11:16

Sweet, thanks.

James Vickers01:11:48

I was surprised that putting a do expression with a println in the :fn spec didn't print anything when the function was called (instrumentation on)

taylor01:11:12

the :fn spec doesn’t come into play re: instrument calls

taylor01:11:45

it does get used if you check the function though

taylor01:11:30

> Instrumentation validates that the :args spec is being invoked on instrumented functions …

taylor01:11:59

> check will generate arguments based on the :args spec for a function, invoke the function, and check that the :ret and :fn specs were satisfied.

James Vickers01:11:55

Cool. I ran a check and it printed out what was passed to :fn.

zclj13:11:06

If I have a production spec of say an email address, it will require a custom generator if I want to generate test data. Since a generator typically will not be used in production would it be a good practice to redefine the production spec in i test ns that will include the generator, keeping any generators out of production code? Can this lead to problems if I have nesting and to be able to generate the top level spec I need to redefine lower levels with the generator in my tests?

Alex Miller (Clojure team)14:11:18

Another thing to consider is using generator overrides at the point of testing. That way you don’t have to redefine a spec, you just supply a set of alternate generators.

zclj14:11:33

But in the case of a nested spec such as a person having an email, and I am testing the person don't I have to redefine the email spec refered by the person spec? Is generator overriding done by using with-gen or are there other ways I have missed?

Alex Miller (Clojure team)14:11:45

no, you can supply custom generators in exercise, instrument, check, etc

Alex Miller (Clojure team)14:11:03

in stest/check for example, you can supply a :gen map in the options: “map from spec names to generator overrides”

Alex Miller (Clojure team)14:11:27

so that way you can supply overrides just in the context of a test

zclj14:11:48

ah I see, will try that out, thanks for your help!

seancorfield21:11:01

Good to be reminded of that. So far, we've tended to write wrappers for generators so we can lazy load the testing library (and therefore keep the actual "testing generator" in the production code without needing the testing libraries in production).

wilkerlucio13:11:47

hello, has anyone here though about the idea of specing nested structures? currently s/keys only supports flat structures, if I need a nested I have to define the nested structure ahead of time on that key, this prevents different nesting structures depending on the context

wilkerlucio13:11:35

maybe we could support via a syntax like the datomic pull syntax, eg: (s/keys :req [:user/name {:user/address [:address/line1 :address/city]}])

ikitommi14:11:43

@U066U8JQJ have you checked https://github.com/metosin/spec-tools/blob/master/README.md#data-specs ? nests also vectors and sets. In the end, just generates specs with alternative (macro free) syntax.

ikitommi14:11:01

also would like to see support for nested keys-specs in spec itself.

Alex Miller (Clojure team)14:11:51

that’s not in line with the “set of attribute” thinking and no plans for that

wilkerlucio14:11:34

the issue I'm facing is that for the "container" specs I might want different subsets of keys, depending on the context

wilkerlucio14:11:43

so by not having a fixed for the children, it gets tricky

Alex Miller (Clojure team)15:11:57

you don’t need a fixed spec for the children

Alex Miller (Clojure team)15:11:10

an empty (s/keys) is sufficient to cover an open set of attributes

Alex Miller (Clojure team)15:11:22

or use s/multi-spec to select the spec based on the contents

Alex Miller (Clojure team)15:11:30

or s/or multiple choices, etc

wilkerlucio15:11:58

thanks for the tips Alex, I like the open one, but at same time, if I want to require different sets of keys depending on the context, that doesn't work, the multi-spec can work, but its a lot more involved

wilkerlucio15:11:20

I love the idea of living by just attributes, but if I need to give a name to a context of sub-attributes, I feel like backing again to the "box" (class, entity, whatever...) constraints again

wilkerlucio15:11:38

@U055NJ5CC thanks for pointing that out, I'll look it up

Alex Miller (Clojure team)15:11:17

what you’re saying is that they key at the top level does not have a stable semantic meaning so I would think about what that means and whether it’s a good idea

wilkerlucio15:11:58

yeah, in general terms, any sub-set might be unstable, if what you care is just about the leaf attributes validation

wilkerlucio15:11:09

I've been writing a considerable amount of code regarding to data fetching apis (om.next style), and many times I see that the sub-set of keys of a child element can vary wildly, in my case I'm embracing this and it's working pretty good, but I can't get the specs around to match it in the way it is

wilkerlucio15:11:58

the problem is the children, for example, working in micro-service architecture

wilkerlucio15:11:12

I have many endpoints across services that can return different sub-sets of the data

wilkerlucio15:11:32

and altough they share some root keys, what comes in the children is variable, some endpoints give more, some give less information

wilkerlucio15:11:57

and in current spec way, I can't define what is required for each return (or input) on a case-to-case bases

wilkerlucio15:11:57

in the same way we can't have a good definition of what are the required fields for an user (a login might be user/password, a signup would require much more)

wilkerlucio15:11:18

I feel the same problem when trying to specify requirements for a nested item

Alex Miller (Clojure team)15:11:30

I think that’s all ok, and you should not try to define every key set aggregation

wilkerlucio15:11:26

but that's the problem, if I have one key like :user/address, I expect this key to be the same always, but what I expected to be inside of it can change from case to case

wilkerlucio15:11:38

on the top level, just create a new set and we are all good

wilkerlucio15:11:46

for the nested, there is no way to override the requirements

wilkerlucio15:11:00

to say that the sub-set is different a separated case, makes sense?

Alex Miller (Clojure team)15:11:19

why not just (s/def :user/address (s/keys)) ?

Alex Miller (Clojure team)15:11:35

then rely on your address attribute specs to do the work

wilkerlucio15:11:16

the only issue there is that we can't make some attributes required for a context that way

wilkerlucio15:11:28

so the validation gets too loose

Alex Miller (Clojure team)15:11:08

if you need that then it sounds like s/multi-spec to me, or state all the possibilities with s/or, or add outer constraints s/and’ed at the top level

wilkerlucio15:11:34

humm, the top level constraint sounds like a good path for the cases I'm thinking

wilkerlucio15:11:52

thanks, I'll try that and see how it goes

Alex Miller (Clojure team)15:11:56

always come back to “state the truth about what it’s in your data” - what can occur in your actual data? say that in the spec.

wilkerlucio13:11:19

had anyone felt the desire to specify the kinds on that way?