This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-11-01
Channels
- # aleph (1)
- # bangalore-clj (5)
- # beginners (24)
- # boot (113)
- # cider (42)
- # cljs-dev (2)
- # cljsjs (2)
- # cljsrn (3)
- # clojure (37)
- # clojure-austin (4)
- # clojure-brasil (3)
- # clojure-france (55)
- # clojure-greece (15)
- # clojure-ireland (4)
- # clojure-italy (13)
- # clojure-russia (37)
- # clojure-spec (50)
- # clojure-uk (31)
- # clojurescript (49)
- # component (12)
- # consulting (1)
- # cursive (6)
- # datascript (9)
- # datomic (27)
- # editors (2)
- # garden (1)
- # hoplon (18)
- # jobs (1)
- # klipse (25)
- # lein-figwheel (1)
- # leiningen (1)
- # luminus (2)
- # om (53)
- # om-next (8)
- # onyx (5)
- # parinfer (4)
- # perun (4)
- # re-frame (13)
- # remote-jobs (1)
- # ring (1)
- # ring-swagger (3)
- # rum (52)
- # spacemacs (36)
- # specter (13)
- # sql (3)
- # untangled (49)
- # vim (11)
- # yada (9)
I'd like to conform this vector [["John" 20] ["Jane" 30] ["Bob" 40]]
into [{:name "John" :age 20} {:name "Jane" :age 30} {: name "Bob" :age 40}]
. how should I write my spec?
(def john-jane-bob [["John" 20] ["Jane" 30] ["Bob" 40]])
(s/def ::person (s/cat :name string? :age integer?))
(s/def ::persons (s/coll-of ::person :kind vector?))
(s/conform ::persons john-jane-bob) => [{:name "John", :age 20} {:name "Jane", :age 30} {:name "Bob", :age 40}]
How does clojure-spec work with the reloaded workflow / tools.namespace? I notice both that: 1. https://clojurians-log.clojureverse.org/clojure-spec/2016-09-09.html#inst-2016-09-09T18:34:11.000362Z 2. specs aren't/can't be, deleted or unloaded in any way. Any success with getting it to work in some way?
is there something like s/keys, but instead of looking up specs via global names, I can pass it a spec for the value of each key?
I have these tests that result in a data structure that is sort of a log of activity, and the result of the test is determined by checking that log
the log is a sequence of maps, and it has a :messages
key, and at each entry in the log, I know that key should have a specific value
if I have to define the value globally (use s/def and s/keys) then all I can say is that it could be any of a number of different values
@hiredman what do you mean "at each entry in the log", like you dynamically know what it should be or you have a list of things it should be in certain circumstances? because if the latter you could always use :req-un
globally all I can say is the value for the key should be either x y or z, but locally I know exactly what the value for the key should be
@curlyfry thanks
(s/def ::messages-1 (s/keys :req-un [:messages-1/message])) and then switch in the spec you need later on
I was hoping to use spec as a sort of a data regex to validate these test results, but having to globally define map validators is a pain
like if you had to globally define your capture groups before you could use them in a regex engine
and if I had followed "best practices" and namespaced the :messages
key, that work around wouldn't work at all
also clojure.spec has a declare of map-spec, which is never defined https://github.com/clojure/clojure/blob/master/src/clj/clojure/spec.clj#L348 maybe a left over from a previous version
(s/fdef update*
:args (s/cat :m map?
:k keyword?
;; I want to say:
;; The function needs to take at least one arg,
;; the current value in the map,
;; and can take zero or more extra arguments.
:f (s/fspec :args (s/cat :value-in-map any?
:args (s/* any?)))
:args (s/* any?)))
(defn update* [m k f & args]
(apply update m k f args))
(test/instrument)
(update* {:a 10} :a inc)
;;=> Call to #'foo.core/update* did not conform to spec: In: [2]
val: (nil) fails at: [:args :f] predicate: (apply fn)
:clojure.spec/args ({:a 10} :a #function[clojure.core/inc])
:clojure.spec/failure :instrument :clojure.spec.test/caller
{:file "form-init8332152340913865653.clj", :line 342, :var-scope
foo.core/eval12509}
maybe something with http://clojure.org/guides/spec#_multi_spec
From that example I'm having truble seeing how I could apply multi-spec
to my problem
maybe not, multi-spec would only be useful if you knew the set of keys you would be pass to update*
I guess that is not entirely true, if you knew the set of keys entirely before hand, you could use an s/alt or s/or, the advantage using multi-spec would be that choice would be open ended
(defmulti update-multi-spec (fn [m k fun & args] k))
(s/fdef update*
:args (s/multi-spec update-multi-spec)
:ret any?)
(defmethod update-multi-spec ::a [m k fun & args]
(s/cat
:map (s/keys :req [::a])
:key #{k}
:fun (s/fspec :args ...)
:args ...
))
I think I explained myself badly, what I want to do is say that the function passed to update needs to take at least one argument, and may take more.
@hiredman Doesn't work..
(s/fdef update*
:args (s/cat :m map?
:k keyword?
:f (s/fspec :args (s/+ any?))
:args (s/* any?)))
(defn update* [m k f & args]
(apply update m k f args))
(test/instrument)
(update* {:a 10} :a inc)
Call to #'foo.core/update* did not conform to spec: In: [2]
val: (nil) fails at: [:args :f] predicate: (apply fn)
:clojure.spec/args ({:a 10} :a #function[clojure.core/inc])
:clojure.spec/failure :instrument
:clojure.spec.test/caller {:file
"form-init8954135211496312533.clj", :line 478, :var-scope
foo.core/eval13250}
your function is inc
, in the spec you say it can take an any?, so spec is checking that by feeding it all kinds of values
Right, what I wan't to say that this function needs to take at least one arg, but doesn't necessarily take any more args.
In this case that passing (fn [] (rand-int 10))
to update will fail, but inc
will work, as will (constantly true)
.
the problem is when you turn instrumentation on, spec is validating inc
against your fspec
a spec that is general enough isn't going to be valid against a specific function, you will generate very general inputs that the specific function won't handle