This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-06-26
Channels
- # adventofcode (2)
- # beginners (69)
- # boot (37)
- # cider (6)
- # clara (31)
- # cljs-dev (75)
- # cljsrn (5)
- # clojure (72)
- # clojure-dev (7)
- # clojure-italy (11)
- # clojure-nl (8)
- # clojure-russia (2)
- # clojure-spec (56)
- # clojure-uk (54)
- # clojure-za (1)
- # clojurescript (156)
- # cursive (2)
- # datomic (34)
- # emacs (1)
- # fulcro (227)
- # hoplon (74)
- # jobs (1)
- # jobs-discuss (16)
- # leiningen (5)
- # lumo (17)
- # off-topic (9)
- # om (3)
- # onyx (10)
- # other-languages (1)
- # portkey (2)
- # re-frame (2)
- # reagent (36)
- # reitit (1)
- # remote-jobs (1)
- # ring-swagger (8)
- # shadow-cljs (85)
- # slack-help (2)
- # spacemacs (6)
- # specter (3)
- # sql (17)
- # test-check (15)
- # tools-deps (80)
@blance I was working on a library for managing generators separately from spec definitions a couple of months ago. If you’re interested, take a look at it! https://github.com/athos/genman
question about spec-tools.data-spec
. it seems like with data-spec there are now two namespaces: the one in the spec registry and the symbol i define in my own code. this makes sense with the one example in the readme because it is a map. but what about for code like
(def hit-box-spec
(ds/spec ::hit-box [number?]))
It seems like both ::hit-box
and hit-box-spec
are now symbols that refer to a spec. I’m just getting a bit confused about how to use this library with non-map specs.::hit-box is a keyword, specs resolve via a central registry that uses keywords. hit-box-spec is a var, containing whatever ds/spec returns (not necessarily the same value stored under that key in the spec registry, but maybe?)
yea. that’s how i understand it. i think i’m just confused why ds/spec
doesn’t rely on the fact that it creates a side effect in the spec registry. i’m not sure why i’d want to also have a var in my namespace that points to a value that is apparently interchangeable (at least it is when using s/valid?
but it also points to the literal data,that ds/ functions can use to create other specs, right?
I'd assume that's the reason
I don’t think so. In the readme, they use a different var to point to the data used to create the spec. So they might write the above as (def hit-box-spec (ds/spec ::hit-box hit-box))
but it might have to do with these transformations, which I’m not using and don’t understand. that would make sense
hm what it is doing is more complex than this. my statement above that ::hit-box
and hit-box-spec
are interchangeable for valid?
is wrong
@lee.justin.m side-effects are bad, I think the data-specs could benefit from a local-keys
variant that doesn’t need to register the keys. data-specs are anyway not in align to the Spec filosophy of reusable keys, so why not go further down the road…
but for the original:
(ds/spec ::hit-box [number?])
can be written:
(ds/spec
{:name ::hit-box
:spec [number?]})
… and as there are no keys, the :name can be omitted:
(ds/spec
{:spec [number?]})
@U055NJ5CC ah i see. i should be using the map syntax.
the thing i’m not getting right now is this:
(def banana-spec
(ds/spec ::banana {:id integer?
:name string?}))
(st/registry #".*banana.*"))
=> (:seekeasy.app-state$banana/name :seekeasy.app-state$banana/id)
if you try to put a map somewhere in the data-spec and don’t provide a :name
, it will fail-fast:
(ds/spec
{:spec [[[[[[[{:a int?}]]]]]]]})
; CompilerException java.lang.AssertionError: Assert failed: spec must have a qualified name
; (qualified-keyword? n), compiling:(data_spec_test.cljc:380:3)
basically i was expecting an unmunged :seekeasy.app-state/banana
given that i provided it that as the name of the spec. although i guess that’s consistent with the readme, now that i think about it. the only thing that got registered were the subspecs.
if there would be the local-keys
, there would be no registering of any specs. that in mind, having a function called spec
doing registration of the top-level would be bit odd.
but here it’s just a function so we need to def it ourselves. okay. this is coming together for me.
I guess I thought there was a separate data structure for the specs. But they are just stored on normal vars?
.. unless you register them and get a name than can be used in s/keys
. I think it’s the only one that requires a spec to be registered?
basically, the thing that confused me is that if you do (s/def ::something ...)
that will show up in the registry even it if isn’t meant to be used as a key but if you do (def something (ds/spec ...))
it doesn’t show up. but both work. i hadn’t appreciated the fact that nothing cares about the registry except for s/keys
btw, thanks for spec tools. i really really really prefer the self-documenting format of schema, and now i have my cake and eat it too
thanks! it’s kind of a roque lib, I hope the final version of spec will make much of it redundant.
what types of functions do you guys normally spec? do you spec utility functions?
the answer you’ll hear most commonly is “at data boundaries” or something like that. e.g. reading data from a file or network or moving from one chunk of code to another, rather than doing it wholesale on every internal function
I'd put it as "system boundaries" rather than "data boundaries" but yes, exactly that
where system boundaries are has a lot to do with your design, but if your system is designed it should have some :D
thanks 🙂
won't your system boundaries keep changing?
as you compose functions with functions
if your system boundaries are changing those weren't your system boundaries
another question! how do you define an fspec
where you don't care about the name of the argument, but you care about the type?
ah thanks that sounds right haha
the idea is that it isn't a system if you don't define some limit or border, that's really the first step. What the boundaries are, and which things cross them, should be one of the first things defined, and often you'll want to define things so it changes relatively rarely
@ackerleytng for the names of things in specs, the reason to have the names is for the error messages you get without a match. Otherwise the output of a failure turns into a soup of data types that isn't very helpful.
oh! so it doesn't actually match against the name of the actual parameter?
if it is the thing I'm thinking of it's a series of name / type for each arg right?
the name is used in generating the message, it doesn't have to match the arglist or anything