Fork me on GitHub
#clojure-spec
<
2017-08-09
>
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: https://github.com/bhb/expound

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"

ikitommi10:08:25

@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).

misha12:08:57

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

misha12:08:29

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).

misha12:08:18

(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.)

misha12:08:27

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?

misha12:08:44

yup

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

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

(st/instrument)
;; => [user/foo]

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

misha12:08:06

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

misha13:08:46

Generating queue, am I doing it right?

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

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

;([#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))

bbrinck14:08:28

@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

misha14:08:12

@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.

misha14:08:55

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)?

bbrinck15:08:15

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

bbrinck15:08:19

@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.

bbrinck15:08:32

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

bbrinck15:08:36

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

misha15:08:36

@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)

misha17:08:29

@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

didibus17:08:02

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

dspiteself21:08:14

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

ghadi22:08:43

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

ghadi22:08:01

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

didibus23:08:37

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

didibus23:08:41

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]))

didibus23:08:44

Okay, I think multi-spec is what I want: https://clojure.org/guides/spec#_multi_spec