Fork me on GitHub
#clojure-spec
<
2016-10-31
>
tcoupland12:10:58

I feel like there's a missing flag on s/keys, something like 'complete' or {:allow-unspecified false} as an option. A couple of times while using s/check i've spelled something wrong, in the spec, or set a key badly in the transform code, and spec isn't yelling at me about it, despite everything being spec'd up, it comes down to this for me:

(s/def ::key integer?)
(s/def ::other integer?)

(s/def ::map
  (s/keys :req [::key]
          :opt [::other]))

(s/valid? ::map {::key 1 ::others "2"}) => true
I've clearly got this wrong (::others instead of ::other), but it's really easy to just not notice something like this, but if I could do this:
(s/def ::map
  (s/keys :req [::key]
          :opt [::other]
          :complete true))
and have spec shout if it see's any key it's not ready for, then I'd be getting more out of my spec's! Just something that's bothered me this morning as i realised I'd mistakenly pluralised a key word 🙂

tcoupland12:10:26

hopefully someones going to tell me it already exists somewhere now!

donaldball14:10:25

The usual workaround is to combine the s/keys spec with an s/map-of spec

donaldball14:10:06

(I agree that a :complete flag would be a welcome addition to the s/keys macro, but Rich seems committed to open maps as the preferred general data structure)

Alex Miller (Clojure team)14:10:02

specs always make positive statements about data, not negative ones and we do not plan to add anything to s/keys along these lines

Alex Miller (Clojure team)14:10:27

however there is something we’re considering that would allow making these additional assertions easier

tcoupland14:10:54

@donaldball that does work, but is pretty ugly isn't it. Sound like a 'wait and see' situation

donaldball14:10:06

It’s not a hard macro to write, a keys variant that allows a complete? flag

tcoupland14:10:10

yeah i just started bashing it out 🙂

drewr14:10:58

{:clojure.spec/problems
  [{:path [:args :idx],
    :pred :clojure.spec/unknown,

drewr14:10:30

can anyone point me in the direction of tracking down why that's unknown?

drewr14:10:28

I get a caller, but I go to that line, and it's downstream from the function that :sym references :thinking_face:

drewr14:10:48

so I must be misunderstanding something fundamental

Alex Miller (Clojure team)15:10:19

the fact that it’s printing unknown there is a known issue with describing preds

Alex Miller (Clojure team)15:10:29

so that part is a known bug

Alex Miller (Clojure team)15:10:31

but you have the path so it should be pretty narrowly scoped to where the pred is failing?

drewr15:10:33

ok, that helps, so go through and perhaps exercise my specs to see if anything's funny?

drewr15:10:59

I'm probably doing this the worst way, by trying to migrate from schema instead of using on a fresh codebase

Alex Miller (Clojure team)15:10:48

as with most programming things, it’s best to start small and build up

drewr17:10:02

as a general comment, the jump to mandated generative testing is a bit of a leap

drewr17:10:22

maybe I'm doing something wrong, but I don't always need this

drewr17:10:26

with a lot of side-effects, traditional unit-testing can work just fine, and I just want to make sure functions deep in the call stack are getting the right arguments and returning something valid

drewr17:10:00

my impression after a couple weeks is that spec makes this some of this more difficult over, say, schema

drewr17:10:19

and maybe that's the intent: lower-level, more correct, more powerful, etc., it just also means there aren't yet companion libraries to help with the porcelain

drewr17:10:06

maybe I'm just spoiled by clojure's quality... alpha is usually good enough 😄

donaldball17:10:40

You don’t need to buy into generative testing to use clojure.spec. instrument with traditional example-based tests is pretty useful.

drewr17:10:57

@donaldball that was my early reaction as well, but I lost the ability to check return values, which I get, that's for check, but then that forces me into the generative style

drewr17:10:25

happen to have a piece of code you transitioned that you're happy with?

donaldball17:10:53

Alas, nothing public, sorry

donaldball17:10:59

IIRC clojure.java.jdbc uses this to good effect tho

jrheard17:10:35

i also kinda wish instrument checked return values

jrheard19:10:01

thanks for the link, haven’t seen this

drewr19:10:12

and I think I agree, I just have the same desire as this guy https://groups.google.com/forum/#!msg/clojure/RLQBFJ0vGG4/E0tHqVyQBgAJ

mattly19:10:33

is there any way to view those google groups links without having a google account?

shaun-mahood19:10:20

@mattly: The link works for me with no google account signed in

drewr19:10:26

@mattly I brought one up in incognito

mattly19:10:53

bah, ok, so it wants me to sign in with one of the google accounts I'm signed in as

mattly19:10:19

which doesn't work because I signed into my google accounts in the wrong order

mattly19:10:28

...sorry, wrong place for this rant

drewr19:10:59

I use chrome profiles, separate windows, yada yada

zane21:10:56

(s/def ::select
  (s/coll-of (s/or :attribute string?
                   :subselect (s/every-kv string? ::select :count 1))))
(clojure.pprint/pprint
 (s/conform ::select
            ["1"
             {"2" ["2.1"
                   {"2.2" ["2.2.1"]}]}]))
;; => [[:attribute "1"] [:subselect {"2" ["2.1" {"2.2" ["2.2.1"]}]}]]
Why does that inner ::select clause not tagged the way the outer one is?

seancorfield21:10:22

You need conform-keys

seancorfield21:10:18

Hmm, :conform-keys is only listed as an option for map-of but I would expect it to work here too...

zane21:10:41

Why would I need conform keys? "2.1" is being conformed by the s/or.

zane21:10:17

It's like conforming stops at the recursive step.

seancorfield21:10:20

Nope, only works with map-of — but if you change :subselect to be (s/map-of string? ::select :count 1 :conform-keys true) then you get this

[[:attribute "1"]
 [:subselect
  {"2"
   [[:attribute "2.1"] [:subselect {"2.2" [[:attribute “2.2.1”]]}]]}]]

zane21:10:22

I still don't understand why :conform-keys has anything to do with this.

zane21:10:27

It's the values that need conforming.

seancorfield21:10:47

Yeah, I think I misunderstood what you were saying didn’t work..

seancorfield21:10:08

Is the output I got with map-of what you want?

zane21:10:25

I would just expect that in my original example "2.1" would be [:attribute "2.1"].

zane21:10:01

Why is the recursive s/or not being conformed?

seancorfield21:10:04

(You’re right, you don’t need :conform-keys but you do need map-of, not every-kv)

zane21:10:07

It seems like it happens, but only sometimes.

seancorfield21:10:41

Per the docs, every-kv does not conform all values — map-of does.

seancorfield21:10:45

"Unlike 'every-kv', map-of will exhaustively conform every value."

zane21:10:16

I missed that in the docs.

seancorfield21:10:30

"Note that 'every' does not do exhaustive checking, rather it samples coll-check-limit elements. Nor (as a result) does it do any conforming of elements.” — and every-kv is like every

zane21:10:46

Phew. Thanks, Sean.

seancorfield21:10:17

(I must admit, I find it counter-intuitive that every / every-kv do not in fact check every element but coll-of / map-of do)

seancorfield21:10:43

After all, they have every in their name so you’d sort of expect them to check every item...

bhagany22:10:49

it is the least-intuitive thing. I wish I understood the rationale.

zane22:10:41

It's heartening that I'm not the only one. 😅

Alex Miller (Clojure team)22:10:21

"every" is an assertion of belief

Alex Miller (Clojure team)22:10:50

Not a statement of what they do