Fork me on GitHub
#beginners
<
2021-11-03
>
Apple00:11:14

try adding this line to your .emacs (setq cider-repl-use-pretty-printing t)

Imdad Ahmed10:11:57

This seems to only work with (setq cider-show-error-buffer 'only-in-repl) for errors

orpheus01:11:54

Is there a way to remove the namespace prefix from all the keys in a map? I’d like to json-stringify a map and send it over the wire w/o the ns

seancorfield02:11:36

@titanroark If you just call name on those keys, you'll get strings without the namespace prefix.

seancorfield02:11:03

There are a few walk-related functions in the Clojure library that can make that easier if it's a nested map. Or just use org.clojure/data.json (or Cheshire or jsonista) to turn it into actual JSON, which should all lose the namespace prefix, or can be configured to do so.

orpheus02:11:46

Ah.. I was using cheshire. Maybe I missed a config

orpheus02:11:47

I’m actually using your jdbc-next library. I saw up above someone ask a similar question and a response that toggled the namespaces on or off, but I was looking for something more general, thus this question.

orpheus02:11:26

When I did (name (:table/uuid_field) map) it threw an error saying a uuid type can’t be converted to a name

orpheus02:11:09

clojure.data.json worked nicely though, thank you

seancorfield02:11:55

(name (:table/uuid_field) map) -- that first tries to "call" the keyword :table/uuid_field with no arguments, hence the error: (:table/uuid_field) is a function call. (reduce-kv (fn [m k v] (assoc m (name k) v)) {} the-map) would apply name to each key in the-map. In Clojure 1.11 (Alpha 2), you could just say (update-keys the-map name)

seancorfield02:11:06

data.json is a nice library because it's "fast enough" for nearly all uses and has absolutely no dependencies. Both Cheshire and jsonista bring in Jackson libraries (Java JSON stuff) that are notorious for causing conflicts with other libraries that also do JSON using (a different version) of Jackson.

orpheus02:11:13

Ah yes, I typed the function call out wrong in slack. And that update-keys fn sounds really nice. Thanks for the reduce-kv tip, the data.json library did the trick well for me, so I won’t need to manually map. And good to know about the library differences, Cheshire starts off with saying its faster so I just went with that

seancorfield02:11:38

Yeah, it used to be. data.json has had some major speedups lately. It's not always the fastest - jsonista usually is - but it is certainly fast enough and we switched from Cheshire to data.json at work for all our production usage recently (to avoid Jackson). I blogged about at http://corfield.org

🖤 1
seancorfield02:11:06

dev=> (require '[clojure.data.json :as json])
nil
dev=> (json/write-str {:foo/bar 1 :bar/quux "two"})
"{\"bar\":1,\"quux\":\"two\"}"
with the Contrib lib.

🙌 1
zendevil07:11:47

Hi I have the following reitit endpoint in my server:

["/organizations/:id/users/:uid"
     {:put {:summary ""
            :parameters {:role string?}
            :responses {200 {:body map?}
                        500 {:body string?}}
            :handler foo}}]
And I make the request using http-xhrio in reframe like so:
{:http-xhrio {:method          :put
                            :uri             (str "/organizations/" (get user "organization-id") "/users/" (get user "id"))
                            :params          {:role role}
                            :format          (ajax/json-request-format)
                            :response-format (ajax/json-response-format {:keywords true?})
                            :on-success      [:block-editing/handle-success]
                            :on-failure      [:block-editing/handle-error]}
But I get the following error:
xhrio.js:645 PUT  404 (Not Found)
Any ideas why?

ikitommi08:11:32

1. do you have any prefix in the routes, e.g. ["/api" …]? 2. does foo return non-nil?

zendevil08:11:25

@U055NJ5CC I had forgotten “/api” but it still gives the same error:

PUT  400 (Bad Request)

zendevil08:11:49

no actually it gives bad request instead of not found

zendevil08:11:08

not sure why

dharrigan08:11:27

It may be worth while to put onto github or summat an example that fails, a fully working example

dharrigan08:11:02

You can, for example, use my one as a basis.

dharrigan08:11:23

(also, I think this may be better served in the #reitit channel?)

Apple12:11:05

dump user and make sure organization-id and id are not nil

Benjamin11:11:31

In core.async is there an opposite to "onto-chan" that returns a collection of the items in a channel? Is there a better alternative?

Benjamin11:11:43

(a/<!! (a/reduce conj [] <tickets))
doing this now

oly12:11:21

I am writing out some data into an edn file I can see in the file its tagged like this :created #time/instant "2021-10-23T19:25:46.574852Z", how ever when I read it back in using slurp and read-string I get this :created (. java.time.Instant parse "2021-10-21T11:54:31.831771Z") this is causing my code to fail when I call things like tick/year I get an IExtraction error I would have expected the read edn to match the initial tag of #time/instant so bit baffled as to whats happening, any one able to point me in the right direction ?

oly12:11:15

never mind combination of things using the wrong read-string, and then needing to add my own reader for the tag

🦆 1
Nikhil Warke12:11:16

How do you pass arguments in double dot notation ((.. fs -promises readFile) "db.edn") or (.. fs -promises readFile "db.edn") P.S. - doesn't work with either of them This worked - (.readFile (.-promises fs) "db.edn")

Colin P. Hill13:11:26

it works just like ->, if you're familiar with that macro

Colin P. Hill13:11:20

The .. equivalent of the solution you found is

(.. fs
  -promises
  (readFile "db.edn"))

1
Benjamin16:11:36

(get-in m  [:a :b])
  (-> m :a :b)
which is better?

Ben Sless16:11:15

Performance, the latter, the rest is a matter of philosophy and taste

dharrigan16:11:27

imho, a matter of preference, although with the get-in variant, you can have a default value if not found.

alexmiller17:11:03

you could have that with -> too, if "not found" is at a specific loc (-> m :a (:b :whoops)) :)

dharrigan17:11:28

Did not know that 🙂 Thank you!

Mno16:11:57

I've seen get-in used more often, but I think it's very preference/context dependant.

dharrigan16:11:01

(I use both variants)

dpsutton16:11:07

i’ve seen a good argument (i think from zach tellman) that you should always prefer to use the functions that most concretely represent the type. I need to go look it up. But i thought it was a useful guideline

hiredman17:11:20

get-in is more dynamic, e.g. the list of keys does not need to be a compile time constant

hiredman17:11:08

get-in also works for other kinds of keys

hiredman17:11:22

-> is likely going to be faster (constant fixed set of keys, for certain things keyword look up calls turn into field accesses), but maybe not by enough to care about, -> allows for more complicated processes because you can stick random functions in there

alexmiller17:11:44

-> is I think definitely faster right now (but that may not always be the case in the future)

dpsutton17:11:16

that is surprising to me. i would have guessed get-in would be faster, kinda specialized to key value lookup

hiredman17:11:01

I mean, -> expands into a fixed set of function calls, get-in is a loop over the contents of a vector

hiredman17:11:00

by fixed I mean statically known at compile time

alexmiller17:11:06

user=> (dotimes [_ 10] (time (dotimes [_ 100000] (-> m :a :b))))
"Elapsed time: 5.769764 msecs"
"Elapsed time: 2.083059 msecs"
"Elapsed time: 2.065704 msecs"
"Elapsed time: 2.026249 msecs"
"Elapsed time: 1.989106 msecs"
"Elapsed time: 1.969671 msecs"
"Elapsed time: 1.446167 msecs"
"Elapsed time: 1.416666 msecs"
"Elapsed time: 1.408738 msecs"
"Elapsed time: 1.409222 msecs"
nil
user=> (dotimes [_ 10] (time (dotimes [_ 100000] (get-in m [:a :b]))))
"Elapsed time: 21.282209 msecs"
"Elapsed time: 15.645264 msecs"
"Elapsed time: 13.058268 msecs"
"Elapsed time: 12.87428 msecs"
"Elapsed time: 7.01354 msecs"
"Elapsed time: 6.806815 msecs"
"Elapsed time: 6.66232 msecs"
"Elapsed time: 6.803173 msecs"
"Elapsed time: 18.48002 msecs"
"Elapsed time: 5.500962 msecs"
nil

👍 2
alexmiller17:11:16

easy to test

dpsutton17:11:55

good points. makes sense

alexmiller17:11:03

in opposition to the argument above, I think there is actually an argument to rely on as few assumptions about type as possible

dpsutton17:11:46

that’s a really good point. I wish i could find where he made that argument so I could see the reasons and if he qualified it in any way

hiredman17:11:56

page 52 of elements of clojure

hiredman17:11:16

"use the narrowest possible data accessor"

hiredman17:11:28

the argument seems to be about communicating intent

dpsutton17:11:03

yes it is guides for keeping the shape of data in the readers head as i remembered it. addressed by other means as well but still a decent idea to me

hiredman17:11:22

the counter argument is write the code as generically as possible so you have to care about the exact shape as little as possible

alexmiller17:11:50

I favor the latter :)

alexmiller17:11:33

there are plenty of times in Clojure where you can change the implementation between a map or a function, or between a vector or a list or a seq or even a set, without changing the caller. that's an amazing option to have.

👍 2
West17:11:06

Damn, you beat me to it

alexmiller17:11:11

lookup is more generic than maps

hiredman17:11:28

lambda the ultimate

alexmiller17:11:01

but as I said, get-in could be, and should be, faster than it is so don't carry this performance comparison as absolute

alexmiller17:11:19

I use both -> and get-in in these cases and choose primarily on which one is easier to understand in the context of the code

catjam 1
alexmiller17:11:23

the perf argument is weak, unless you're in a very hot path here (like the page router of your web app)

alexmiller17:11:04

and even in that case, hotspot in a new jvm might make the above a wash

alexmiller17:11:05

in fact, that was java 8 above, here's java 17

user=> (dotimes [_ 10] (time (dotimes [_ 100000] (-> m :a :b))))
"Elapsed time: 11.085806 msecs"
"Elapsed time: 5.569733 msecs"
"Elapsed time: 5.167711 msecs"
"Elapsed time: 5.269218 msecs"
"Elapsed time: 5.093628 msecs"
"Elapsed time: 5.052448 msecs"
"Elapsed time: 5.143588 msecs"
"Elapsed time: 2.802478 msecs"
"Elapsed time: 1.395313 msecs"
"Elapsed time: 1.411534 msecs"
nil
user=> (dotimes [_ 10] (time (dotimes [_ 100000] (get-in m [:a :b]))))
"Elapsed time: 21.824148 msecs"
"Elapsed time: 17.589059 msecs"
"Elapsed time: 13.940786 msecs"
"Elapsed time: 13.9655 msecs"
"Elapsed time: 3.989803 msecs"
"Elapsed time: 4.947388 msecs"
"Elapsed time: 4.247937 msecs"
"Elapsed time: 3.350112 msecs"
"Elapsed time: 4.805961 msecs"
"Elapsed time: 6.8933 msecs"

😮 1
Benjamin17:11:48

(defn has-keys? [m keys]
  (apply = (map count [keys (select-keys m keys)])))
is this a good solution to check if a map have contains all of some given keys?

hiredman17:11:33

use every and contains?

1
Benjamin17:11:05

ah I was missing every? thanks

hiredman17:11:46

that has-keys? is terrible

hiredman17:11:20

even something using reduce and contains? would be preferable

Benjamin17:11:48

is there something like apply or [coll-of-key

Benjamin17:11:04

(every?
   m
   the-keys)
I figured out this solves has-keys? if I'm not mistaken. Well I guess it doesn't handle nil or false values if the use case is to check contain? but it isn't my case so yea

AT12:11:57

I'm using the following to check if a map contains all the keys, does it help?

(defn keys-check [m & ks]
  (every? #(contains? m %) ks))

;;---------TESTING FNS----------
(deftest keys-check-test
  (testing "Basic test cases"
    (let [x {:a 1 :b 1 :c 2}

          y [{:a 1 :b 1 :c 2}
             {:a 1 :b 1 :c 2 :d 5}]]

      (is (true? (keys-check x :a)))
      (is (true? (keys-check x :a :b)))
      (is (true? (keys-check x :a :b :c)))
      (is (false? (keys-check x :d)))
      (is (false? (keys-check x :a :d)))
      (is (false? (keys-check x :a :b :c :d)))
      (is (every? true? (map #(keys-check % :a :b :c) y)))
      (is (false? (every? true? (map #(keys-check % :a :b :c :d) y))))
      (is (every? false? (map #(keys-check % :a :b :c :e) y))))))

George Silva17:11:19

Hello friends! I'm trying something here: I have a project that I'm starting off with clojure and I'll be deploying it on aws batch. This means this is going to be shipper as an docker image. For testing I would like to run tests and, some things, in docker. Also I don't want to miss on Calva. The tricky part is about environment variables. I configured environ and I have correctly set up the profiles, so locally, calva works just fine. However, for docker/docker-cmpose I'm using .env as a way of configuring the environment variables for the image. Is there a lean way of writing this only once and having access to the best of both worlds? Or should I just open up the REPL server in docker and allow calva to connect to it?

hiredman19:11:36

I think this is a common antipattern with clojure and docker. Don't dev inside docker, dev as normal, build an uberjar, package uberjar inside a docket contianer, done

George Silva15:11:50

Yea thanks! I'll follow that route for now!

Shmarobes19:11:24

Hi. I've decided to start thoroughly studying the clojure standard library. Thus I'm looking for advice on how to approach it. Which resources did you use/are you using for this purpose? I'm thinking I should just read clojure-docs, source code and usage examples for every core function. Do you think there is a better way? Any resources that are worth noting? I came across "Clojure the essential reference", but wasn't able to find a free copy anywhere, so it's not really an option for me.

Mno21:11:46

I learned it by utility by just googling generic questions like "how do I remove various keys from a map?" whenever I ran into a problem, until I got a hang of the ones I commonly use. also https://clojuredocs.org/clojure.core is your friend.

tws22:11:05

i went through clojure cheatsheet and (source foo) on all of it.

1
👍 1
Shmarobes08:11:09

@U1Z392WMQ Yep, that's what I'm probably going to do.