This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-06-22
Channels
- # beginners (124)
- # boot (7)
- # cider (73)
- # cljs-dev (37)
- # cljsrn (6)
- # clojure (85)
- # clojure-greece (4)
- # clojure-italy (67)
- # clojure-nl (6)
- # clojure-russia (4)
- # clojure-spec (6)
- # clojure-uk (48)
- # clojurescript (26)
- # cursive (5)
- # data-science (23)
- # datomic (63)
- # editors (5)
- # emacs (4)
- # graphql (13)
- # immutant (2)
- # lumo (4)
- # mount (3)
- # off-topic (1)
- # onyx (4)
- # pedestal (7)
- # portkey (10)
- # re-frame (14)
- # reagent (10)
- # ring-swagger (18)
- # shadow-cljs (97)
- # spacemacs (1)
- # tools-deps (9)
- # vim (1)
- # yada (13)
I want to turn a map like this…
{:foo ["a" "b"], :bar ["x" "y"]}
… into a vector like this…
[{:foo "a", :bar "x"} {:foo "b", :bar "y"}]
The size of the vectors in the map’s values is the same for all elements. Any ideas for how to solve this idiomatically?
@msolli :
(let [data {:foo ["a" "b"], :bar ["x" "y"]}
ks (keys data)]
(->> (vals data)
(apply map vector) ;; Transpose the matrix of values
(mapv (partial zipmap ks))))
The above will not work, however, if keys
and vals
may return elements in different order
Hm, thanks, seems like they do for a regular hash-map. Docstring for both keys
and vals
state that they return things “… in the same order as (seq map)“.
Yeah, missed that part.
Thanks a lot, @alexyakushev!
Well I wasn’t there but all data structures use their name as the constructor function - vector, hash-map, hash-set, list, array-map, etc
I think of vec and set as coercers
We typically use literal syntax instead of constructors whereas the coercing is more common so it’s convenient to have those be shorter
But that’s all just me post-rationalizing
In Clojure zip that convention wasn't followed, if I am interpreting correctly. We were trying to name some functions for coercing and creating Java periods. A shortened version is hard to contrive.
zip-map is map as in map (the operation), not as in hash-map (the collection) - that is, it’s seen as a sequence function more than as a constructor (but I totally get why people say that too)
It appears Clojure zip went for a make- prefix.
zip almost certainly is echoing that use in other functional langs
I need to read and write TOML files. I see that there are already several Clojure libraries for this. Is there any reason to prefer one of them over the others, or are they all pretty much interchangeable?
I've never used that but quickly looking at options only the last one seems to support writing: * https://github.com/lantiga/clj-toml/blob/0.4.0-instaparse/src/clj_toml/core.clj * https://github.com/manicolosi/clojoml * https://github.com/ilevd/toml That's also the one most recently updated.
I’m having an odd issue with stest/instrument
and :stub
in the context of deftest
.
On the line where I call stest/instrument
in a test I get this error: Caused by: java.lang.ClassCastException: clojure.lang.AFunction$1 cannot be cast to clojure.lang.MultiFn
Yet executing that very line in the REPL correctly instruments the function in question, along with the stubbing behavior.
The stacktrace is deep within spec -> test.check, and I cannot figure out the reason for the difference in behavior.
Maybe instrument
is meant for use in test.check
but not clojure.test
?
If you’re running in lein, you may be running into lein’s monkey patching of clojure.test
if so, you can try :monkeypatch-clojure-test false
in project.clj (and most likely lose nothing you care about)
That’s good to know!
Hm here's a weird problem. If I turn on reflection warnings, and I evaluate ring-core
file src/ring/middleware/session/cookie.clj
I get two reflection warnings:
Reflection warning, crypto/random.clj:28:12 - call to static method encodeHex on org.apache.commons.codec.binary.Hex can't be resolved (argument types: unknown).
Reflection warning, crypto/random.clj:28:3 - call to java.lang.String ctor can't be resolved.
But then if I check out crypto-random
project and evaluate that random.clj
file, I get no reflection warnings.Figured it out. cryto-random
uses ancient commons-codec
1.6, and ring-core
uses newer commons-codec
1.11, which has more overloads of encodeHex, which causes the old code to produce reflection warnings.
Seems like lib authors should annotate java interop with types even when not needed, because it can cause grief later.
@weavejester submitted PR in crypto-random
.
I second heroku. Very easy deploy.
Hey all, I am looking for advice on spec generation: I have a data structure like this
{:item_count 53 :items [ {} {} ...53 times]}
My goals is to write a spec to help generate this data structure, but I need to have item_count
to be the total number of items in provided by the :items
property...is this possible?Totally, you can s/and any arbitrary predicate
(s/def ::item_count int?)
(s/def ::item map?) ;; whatever
(s/def ::items (s/coll-of ::item))
(s/def ::item-map
(s/and (s/keys :req-un [::item_count ::items])
#(= (:item_count %) (count (:items %)))))
(s/valid? ::item-map {:item_count 2 :items [{} {}]}) ;; => true
sorry, I didn’t read all of that above
can also gen, using fmap
(s/def ::item-map
(s/with-gen
(s/and
(s/keys :req-un [::item_count ::items])
#(= (:item_count %) (count (:items %))))
#(gen/fmap
(fn [items] (hash-map :item_count (count items) :items items))
(s/gen ::items))))
that is gen the items list, then use fmap to produce the right shaped map
awesome! Thank @U064X3EF3
Heroku is great, @roti
+1 heroku is pretty easy to get going and the free tier can take you pretty far
somewhere there was a discussion about where to put specs, and one of the suggestions was to stick them in their own namespace, so that the specs for program.widget
would be in program.widget.specs
. I’m trying to figure out how namespaced keywords would work in practice, but it seems to me that you need the specs to be in the same namespace or they won’t match up. Or am I missing something? Or maybe the idea is to put them in the same namespace but a different file?
the keyword used needs to match between definition and usage
the namespaces can be anything you find meaningful
@nickmbailey Not that it really matters but one of the reasons I appreciate Heroku is that they went out of their way to accommodate deploying Clojure fairly early on in its history
I think it was because they're users of Clojure and have always had Clojure advocates on the inside
@noisesmith What I mean is this kind of thing:
~$ clj
Clojure 1.9.0
user=> (in-ns 'spectest.spec)
#object[clojure.lang.Namespace 0x33308786 "spectest.spec"]
spectest.spec=> (clojure.core/require '[clojure.spec.alpha :as s])
nil
spectest.spec=> (s/def ::first-name clojure.core/string?)
:spectest.spec/first-name
spectest.spec=> (s/def ::person (s/keys :opt [::first-name]))
:spectest.spec/person
spectest.spec=> (in-ns 'spectest)
#object[clojure.lang.Namespace 0x5911e990 "spectest"]
spectest=> (clojure.core/require '[clojure.spec.alpha :as s])
nil
spectest=> (s/conform :spectest.spec/person {::first-name 42})
#:spectest{:first-name 42}
The spec didn’t really work because the first-name
key is defined in one ns but used in another. This isn’t a problem with :req-un
because it only matched up the name
of the keyword
that's just using aliases wrong
:: means “autoresolve in the context of the current namespace”
you’re using it in two different namespaces and expecting the same result
if you explicitly state the namespace, then you won't have any problems when it resolves to something you don't expect
(sorry it’s confusing that i called it spectest
. should be widget
vs. widget.spec
or something)
which, like I said, the keyword you use to define the spec and the one you use to check it need to match
right got it. the reason i was confused is because I could have sworn that someone was suggesting that by putting the specs in their own namespace, you could decide whether to load them or not. but that’s not really going to be possible if you want to use namespaced keywords
namespaced keywords do not belong to namespaces
the only thing that links them is ::
, which, see my earlier suggestion not to use it
I think the answer is that as a matter of taste I would want the keywords to be :foo/bar
rather than :foo.spec/bar
. so I should probably just change the spec and not use ::
there as you suggested (?)
Hey, I’m trying the following:
(POST "/:partner-id/antifraud-rules" []
:path-params [partner-id :- ::antifraud/partner_id]
:body-params [action :- ::antifraud/action
criteria :- ::antifraud/criteria]
:summary "Creates a new rule for given partner."
(try
; (println body)
(created "" {:rule (antifraud/add-rule-to-partner partner-id action {})})
(catch PSQLException e
(unprocessable-entity {:errors ["Invalid fields."]}))))
And my specs are:
(s/def ::action #{"allow" "deny"})
(s/def ::criteria (s/keys :opt-un [::email ::phonenumber ::document]))
And my error is:
{
"spec": "(spec-tools.core/spec {:spec (clojure.spec.alpha/keys :req-un [:$spec44286/action :$spec44286/criteria]), :type :map, :keys #{:criteria :action}, :keys/req #{:criteria :action}})",
"problems": [
{
"path": [],
"pred": "map?",
"val": null,
"via": [],
"in": []
}
],
"type": "compojure.api.exception/request-validation",
"coercion": "spec",
"value": null,
"in": [
"request",
"body-params"
]
}
What I’m doing wrong? 😞looks like there should be a map containing :criteria and :action and instead you got nil?
The point is: I’m sending a JSON body with the criteria and action as keys
what are you doing to allow the handler to use json?
I’m using the example from luminus:
(def antifraud-rules-routes
(api
{:swagger {:ui "/docs/external-antifraud-rules"
:spec "/antifraud-rules.json"
:data {:info {:version "1.0.0"
:title "Antifraud Rules Service"
:description "Create, update and remove rules from antifraud service."}}}}
(context "/v1/partners" []
:tags ["Configuration of antifraud."]
:coercion :spec
(POST "/:partner-id/antifraud-rules" []
:path-params [partner-id :- ::antifraud/partner_id]
:body-params [action :- ::antifraud/action
criteria :- ::antifraud/criteria]
:summary "Creates a new rule for given partner."
(try
; (println body)
(created "" {:rule (antifraud/add-rule-to-partner partner-id action {})})
(catch PSQLException e
(unprocessable-entity {:errors ["Invalid fields."]})))))))
usually the way you get json input is via a ring middleware, wrap-json-body iirc
if that middleware isn't being applied, that would be a simple reason that it wouldn't get any of your input
Oh I see now the problem
I’m missing the json middleware it seems
it probably isn't being added by default because you might not want it applied to everything indescriminately? anyway, it's easy to double check by applying it