Fork me on GitHub
Oliver George01:08:04

@mrkaspa clojure.spec provides a basis for that sort of thing but leaves other tools to craft user friendly messages.

Oliver George01:08:06

Expound is getting a bit of attention:

Oliver George01:08:10

There are others.

Oliver George01:08:40

The other JSON api consideration is that clojure.spec deals in clojure data structures (maps, sequences...) not javascript objects and arrays.

Oliver George01:08:29

You can do something like js->clj to translate the data into a format clojure.spec likes

Oliver George01:08:43

The error messages might be a little confusing where they say "this keyword is missing" when a JS consumer might expect "this property is missing"


@mrkaspa I'm returning everything (problems + extra info of the cause) to clients, specs can be serialized via s/form. Not sure how usefull this is thou. Spec-tools has utility for adding human readable :reason for specs (like struct does).


how can I properly delete the spec? (undo s/def, actually, undo s/fdef)


use case is: first, I get some function symbols from config, resolve them vars, and see if those are actually functions. next, I want to enforce common function signature on those, so I want to dynamically do (s/def 'some-handler :lib.specs/handler). This is all cool, but I want to clean specs registry from those dynamically set specs on some tear down event (some reload in REPL, or what not).


(or at least to know I don't have to do cleaning up at all, because spec registry thing was designed to not worry about it.)


actually, I control the call site, and can ensure args are ok, but does fspec actually check the arity of a function? or does it check args, and if a function (not args) does not conform to the spec – it will blow up, but not in the spec-way, but in usual invalid arity one?



(s/fdef user/foo  :args (s/cat :x int? :y int?)  :ret nil?)
;; => user/foo

(defn foo [x])
;; => #'user/foo

;; => [user/foo]

(apply foo [1 2])
;; clojure.lang.Compiler$CompilerException: clojure.lang.ArityException:


so the best UX I can provide, is to make "handler" fspec available, so user could instrument handlers during development at will.


Generating queue, am I doing it right?

   #?(:clj  [clojure.lang PersistentQueue])))

  (s/coll-of int?
       :kind #(instance? PersistentQueue %)
       :into (PersistentQueue/EMPTY))

;([#object[clojure.lang.PersistentQueue 0x66b3bed3 "[email protected]"]]
; (0 0 0 0 -1 -1 -1 0 -1 -1 0 0 -1 -1 0 0 0 -1 0 -1))


@misha Looks OK to me. I would have written :into PersistentQueue/EMPTY (no parens), but in practice, it doesn’t seem to make a difference


@bbrinck you might be right (originally I had a (q) cljc function call there, edited for brevity). Still need to see how it'd work in cljs.


to create spec for keyword with arbitrary namespace, I need to (create-ns ...) first, right (if there is no file for that ns in a project)?


@misha In CLJS you can do :kind #queue []


@misha I’m not sure if this works for your use case, but specs just need to be namespaced, but that namespace doesn’t have to be a clojure namespace. e.g. (s/def :user/name string?) is totally valid.


The jury is still out on the pros/cons, but I’ve tended to build my specs based on my logical domain, not my Clojure namespaces. I never get to use the :: syntax, but the plus side is that when I print out my specs (or get spec failures), things are a bit more succinct


For the example above, namespacing further by app or company helps avoid conflicts e.g. :my-app.user/name


@bbrinck ah, I went step further, and it complained about aliased namespace, which I need to create before aliasing. So if I want to use ::u/name, I need to (create-ns 'user) and (alias 'u 'user) first.

Alex Miller (Clojure team)17:08:18

that’s totally fine (and something Rich has ideas about ways to improve specifically re working with keyword namespace aliases)


@alexmiller any news on unregistering specs?

Alex Miller (Clojure team)17:08:47

yeah, there’s a ticket out there, should be in next spec batch

Alex Miller (Clojure team)17:08:57

plan is to have (s/def ::foo nil) do this


Question: I'm not sure I understand what fmap is for. When would I want to use it. Its one of the few functions that has no doc.

Alex Miller (Clojure team)17:08:33

all of the gen namespace functions are dynamically loaded and thus don’t have doc, but they are just aliases for the equivalent function in clojure.test.check.generators

Alex Miller (Clojure team)17:08:59

fmap is used to construct a generator based on applying an arbitrary function to some other generator

Alex Miller (Clojure team)18:08:37

although fmap is not really covered there


it appears that s/? breaks up the merging of the s/cat


You may want to add that test case if it's substantially different


(I haven't looked closely, just aware of the bug)


@alexmiller Thanks. I meant test.check doesn't have a doc for fmap. I get it now though.


Question: Is there a way I can specify that a spec can be one of a set of specs? Such as (s/def ::user-info #{::name ::address}). Where (s/def ::name (s/keys [::first ::last])) and (s/def ::address [::street ::city ::country]))


Okay, I think multi-spec is what I want: