This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-07-07
Channels
- # admin-announcements (2)
- # boot (111)
- # capetown (5)
- # cider (15)
- # clara (15)
- # cljs-dev (8)
- # clojure (78)
- # clojure-brasil (1)
- # clojure-dev (2)
- # clojure-greece (25)
- # clojure-hk (1)
- # clojure-russia (5)
- # clojure-seattle (1)
- # clojure-spec (120)
- # clojure-sweden (3)
- # clojure-uk (63)
- # clojurescript (161)
- # data-science (1)
- # datomic (21)
- # editors (43)
- # emacs (3)
- # funcool (1)
- # hoplon (72)
- # instaparse (11)
- # jobs (1)
- # off-topic (2)
- # om (212)
- # onyx (9)
- # other-languages (129)
- # proton (5)
- # re-frame (15)
- # reagent (18)
- # slack-help (4)
- # spacemacs (18)
- # untangled (224)
- # yada (21)
I thought alias
had been updated so you didn’t have to have a real namespace for the second argument?
It seems not. I was hoping to use alias
to shorten a lot of qualified keywords (without having to actually load a namespace).
no, we’re just considering that
Now we’re beginning to use namespace-qualified keywords a lot more, I can say that would be a very convenient addition! 🙂
as a short-term workaround you can do something like this: https://github.com/clojure/clojure/blob/master/src/clj/clojure/spec/test.clj#L17-L19
That’s an interesting hack! 🙂
I was wondering how I would spec an async function (a function returning a core.async channel). Would I need to write an async version of fdef or is there another way?
I'm a bit struggling to choose between :foo.vocabulary/term-uri
and :foo.vocabulary.term/uri
or just :term/uri
. I know it's probably a bit soon, but any best practices for choosing the name(space)s?
@wagjo: I've been taking advantage of the new ::alias/some-keyword feature. So I'd probably call it ::term/uri and map the term alias in all namespaces using it to foo.vocabulary.term.
How can I reference the first argument of a function in fdef :arg
when the argument does not have a name since I’m destructuring it immediately with {:keys [a b]}
?
@wagjo if you're in a lib or other public project, you should add enough context to be distinguishable from anyone else (something like your maven group/artifact id). If in a private app, I would probably do less just for typing sake. I think it will be useful to put specs for the domain in a small number of namespaces (maybe 1). It might be useful to separate generic specs from domain attributes (which alias them) too.
@mandragoran: we will probably have some async related specs eventually. Until we do I think it's better to do type checks on ReadPort and WritePort than specifically on ManyToManyChannel as those are more generic
ad-hoc higher-order specs?
How do I write a spec for a map of unqualified keywords where the keyword itself is something dumb that’s going to collide a lot? In particular, swagger (the api format) has a toplevel key, also called “swagger”.
can you give an example? not getting the question.
(def sample-swagger
{:swagger "2.0"
:info {:title "my sample api for puredanger"
:version "elventy flive"}})
Let’s say I’m in a ns defining swagger in general (doesn’t matter much, could also be :swagger/whatever
). I’m doing something like:
(spec/def ::swagger
(spec/keys :req-un [:swagger/swagger
::info]))
(spec/def :swagger/swagger
;; The top-level key is called swagger. This feels dumb.
#{"2.0"})
(spec/def ::info
(spec/keys :req-un [::api-title
::api-version]))
(spec/def ::api-title string?)
(spec/def ::api-version string?)
It seems like I’m naming :swagger/swagger
what it is because :req-un
expects to find the names of map keys that way, but having a ::swagger and a :swagger/swagger
looks confusing
Similarly, ::api-title
actually needs to be :
or something, but the tons of ns’es make it annoying to type
I guess I’m asking if there’s a way to distinguish between the key under which something appears in a map, and its spec name
IIUC there are some new reader macros in the current alpha, I don’t know if they help with this
they might limit the typing to just the spec defs so at least the destructuring looks good, I suppose?
if I had a choice, in this code, I would refer to that specced value (esp. after conform) as ::api-title
— the only reason I wouldn’t do that is because the JSON I’m getting from swagger (a standard, so I can’t change it) uses keys that don’t collaborate well with that
If I could provide, say, an alias, or say that under key :title
I’m expecting to see spec ::api-title or something, that’d help too
bailing out and using a fn to just assert that some keys are some particular value doesn’t feel very idiomatic either
I guess you can define specs in terms of other specs? That doesn’t seem to help a lot but I’ll play with it
Has anyone run across or is writing a lib of commonly useful strong specs, e.g. for urls, hostnames, unix ports, valid sql identifiers, etc.?
I haven't seen anyone doing so yet but it seems like a reasonable and perhaps inevitable thing to do
@lvh aliasing is a good and useful thing, so creating api-title and api-version are just fine as base specs (you may want to use some other namespace though like :swagger/api-title
or :swagger.api/title
), then s/def code-localized versions to match the unqualified attributes that alias those base specs, like (s/def ::title :swagger/api-title)
OK, so I define the “real” spec under :swagger.ap/title, and then a local alias. Makes sense. Thanks!
if you create the keyword namespace as an actual namespace, you can alias it, then use the alias in the autoresolved keyword like ::sw/api-title
(after something like (alias ‘sw ‘swagger.api)
)
the key there is that alias currently has to refer to a real (loaded) namespace. That might change still but a workaround is what you see here https://github.com/clojure/clojure/blob/master/src/clj/clojure/spec/test.clj#L17-L19
switch to (and thus create) the namespace, then switch back, and alias
Today we wanted to create a spec that validates a percentage in five percent steps. It occured to us that int-in doesn't support a step argument like range does. Has this been discussed or is a ticket worth a shot?
Before I get too far in reinventing the wheel, is anyone else out there working on converting spec to Datomic/Datascript schema?
@leongrapenthin: no, it's not going to do that
@dave.dixon: I have thought about it and realized that generating a spec from Schema is likely more desirable
I’m not sure what I’m doing wrong with this simple spec:
(s/def ::foo (s/spec #(= :foo %) :gen (gen/return :foo)))
:user/foo
user> (s/gen (s/get-spec ::foo))
ClassCastException clojure.test.check.generators.Generator cannot be cast to clojure.lang.IFn clojure.spec/spec-impl/reify--13361 (spec.clj:800)
@alexmiller: Ok, thanks
@leongrapenthin: just do (set (range 0 100 5))
Oops, I misread the contract for s/spec, carry on
@donaldball: Wrap (gen/return ...) in a (fn [] )
yep, or put # at the beginning
(s/def ::foo (s/spec #(= :foo %) :gen #(gen/return :foo)))
(gen/sample (s/gen ::foo))
@alexmiller: Yeah, but that's gonna be quite the error message 🙂 - We came up with (s/and (s/int-in 0 101) #(zero? (mod % 5))) if I remember correctly. Generator worked. Projecting this scenario on per permille or larger spaces was what made us wonder why a step is not supported.
because it’s a min/max check, and you’re specifying enumerated values. that’s just not what it is intended to do.
I think your spec is better anyways
you could combine int-in with it too
nvm, you’re doing that
Yeah, the reasoning makes sense
the hard part of int-in is generating uniformly across a well defined set and you’re leveraging that by building on top of it
Looking at that from a different perspective it is only enumerated because of the min-max check
You could argue that everything in a min-max interval is enumerated then
well enumerations have obvious usage issues when there are a lot of values :)
My case is a very specific enumeration and can't be discarded as just any enumeration. Every step range of allowed values is a subset of an integer range with the same boundaries.
So from that perspective I think it still makes sense as a feature of a min/max check.
The min/max check is also an enumeration with a step of 1, then.
Better said, for our usecase it would be preferable if it was an in-range check than a min/max check with the word range meant in the same way as in clojure.core/range
well, range does a lot of stuff (reverse ranges, infinite ranges, half-open ranges, support for all number types, etc)
in-range implies to me a check that would need to enumerate the range to determine conformance and gen would be a lot harder.
int-in is intentionally much narrower
Agreed. I think what I want to say is that int-in as a name doesn't necessarily limit the spec to a min/max check
A fully featured in-range is likely an overkill for the rare amount of usecases
Thanks for discussing. Having thought about it I won't be able to resist to submit a small patch over the weekend for reconsideration, though 🙂
I think Rich is unlikely to ok that
I am running stest/check on an fdef that never finishes. It just keeps going and I don't know If its stuck or what is the deal. I have independently tested the input and output specs for possible problems and am getting nowhere. Any tips on how to debug this?
@kidpollo: Isolating the problem by starting with dumbed down specs and adding until the problem occurs?
@kidpollo: Probably recursion in s/map-of or every-kv?
Might be that it just takes so long to print the result because it prints a huge generated value
You could eliminate this quickly with setting print-length
dump stack and see what it’s doing
I think intellij has a button for it
I guess maybe that’s only in the debugger mode
(map println (.dumpAllThreads (java.lang.management.ManagementFactory/getThreadMXBean) false false))
will serve in a pinch
I guess i need to find what spec is going crazy. Start with simpler specs maybe? The input and output to this fn are multispecs. The maps are not so complicated maps.
@alexmiller @leongrapenthin the problem seems to be happening in alpha-9. I went back to alpha 8 and the test finishes. It takes a while but it finishes
I think check
changed from 100 to 1000 iterations in alpha9
That count is an option you can pass to check though iirc
Nothing categorical. Qualified keywords have utility - if they make sense for you, use them
I think spec and the other syntax changes have increased their utility and decreased their verbosity, maybe changing that equation
And their visibility 🙂
Well I don't think that changes their utility :)
I can see us (World Singles) using qualified keywords very heavily as it will make some of our code much more explicit. Hence the recent changes to java.jdbc
to make it easier to get qualified keywords back in result sets (the new :qualifier
option to everything that produces result sets).
In spec/fdef, is there any way to make one element of :args depend on another? I've got a function that takes two maps, but wants the keys of each map to be the same.
(For example, I have functions that take a grid and a coordinate within that grid, and obviously the coordinate must be within the bounds of the grid to be valid. But I don’t think there’s a way of expressing that.)
Sounds similar to the ranger-rand
example in http://clojure.org/guides/spec#_spec_ing_functions
@glv you can s/and an arbitrary predicate in the :args spec
and flows conformed values so it should already be nicely destructured if you add it last