Fork me on GitHub
#beginners
<
2020-10-01
>
AudA00:10:39

Is it possible to access RuntimeMXBean, more specifically http://Is%20it%20possible%20to%20access%20RuntimeMXBean,%20more%20specifically%20(getUptime())[https://docs.oracle.com/javase/7/docs/api/java/lang/management/RuntimeMXBean.html#getUptime()] ? In my namespace, do I need to require something to access ManagementFactory?

alexmiller00:10:18

you'll need to import the class, and yes should be no problem to do

AudA09:10:55

I’ve been getting by with the core library… this is a whole new world! Thanks!

alexmiller00:10:42

user=> (import java.lang.management.ManagementFactory)
java.lang.management.ManagementFactory
user=> (.getUptime (ManagementFactory/getRuntimeMXBean))
75162

Clark Urzo03:10:23

Any way to automatically reload assets on file save when using deps.edn?

seancorfield05:10:58

@signup867 I would advise against any sort of automated file reloader and just develop a really good, tight REPL-focused workflow where you evaluate every change as you make it. Watch Stu Halloway's talks on REPL-Driven Development and Running With Scissors; watch Eric Normand's excellent online course about REPL-Driven Development.

seancorfield05:10:36

I have been doing Clojure in production for a decade now and I don't use watchers or auto-loading: I just eval every change I make, often without even saving files, I run tests from my editor, I develop into a live, running server process all the time, with my REPL active for days, sometimes even weeks.

Jim Newton07:10:49

where in the clojure doc is the explanation of the full syntax of argument lists. I know about stand-alone &, but recently I've seen &env and &something-else which I can't remember.

Jim Newton07:10:04

I thought this might be in the documentation for fn, but I didn't find it there

Jim Newton08:10:57

yes, are those variables, or are they syntax for the lambda list of a macro?

Jim Newton08:10:25

however the page you reference doesn't seem to show any examples or other information about how to use those special variables.

alexmiller12:10:24

they are "magic" args available in any defmacro (in reality, defmacro actually generates a function that takes arity + 2 to pass these). the &env tells you the local bindings in scope when the form is expanded and &form is the actual form being expanded.

alexmiller12:10:18

user=> (defmacro lookie [x] (println "&form" &form) (println "&env" &env) x)
#'user/lookie
user=> (let [a 100] (lookie 10))
&form (lookie 10)
&env {a #object[clojure.lang.Compiler$LocalBinding 0x749f539e [email protected]]}

alexmiller12:10:29

notice that the vals of the &env map are actually Compiler$LocalBinding objects out of the internals of the compiler

Jim Newton13:10:37

@U064X3EF3 Do I recall seeing the &env in the argument list of the macro somewhere? or is it only useful in the body of the macro?

alexmiller13:10:15

only in the body (it is actually passed as an arg to the macro but that's not visible to you as a macro writer)

Jim Newton13:10:37

Is there more syntax for the lambda list other than just variable names followed by & and a single trailing variable name?

Jim Newton13:10:15

as I recall there is something about default values. right?

alexmiller13:10:57

you can use any destructuring syntax in the arg list

Jim Newton13:10:06

does destructuring have any default value syntax?

alexmiller13:10:22

it does for maps, with :or

Jim Newton13:10:35

ahhhh.. Where is the documentation for that?

alexmiller13:10:50

(defmacro foo [{:keys [a b] :or {a 1 b 2}}] ... )

alexmiller13:10:43

or if you're using kw-arg style passing, you can destructure the variable arg seq: (defmacro foo [& {:keys [a b] :or {a 1 b 2}] ...)

Jim Newton13:10:55

that's only for macros or also for normal functions?

Jim Newton13:10:26

I notice (fn [x & rest :as all] ...) triggers an error, but (fn [[x & rest :as all]] ...)`` does not

alexmiller13:10:08

the :as is not supported in the fn args

Jim Newton13:10:38

but it apparently is within the [[]] of a fn args

alexmiller13:10:48

the fn is the exception here, can't say I know the reason why off the top of my head

alexmiller13:10:01

every place else that has sequential destructuring does support it

alexmiller13:10:01

not sure if that's just a historical quirk or if there's actually a reason for it

Jim Newton13:10:25

I'm writing a function what wants to provide arglists with the same syntax as fn. To implement this distinction will be tricky.

Jim Newton13:10:52

as its a recursive function. It'll have to know whether it is the top level recursion or not. guess not so tricky, but good do know.

Jim Newton13:10:21

In common lisp, destructuring is only allowed in macro lambda lists, not in normal functions. So that's a feature of clojure that I really appreciate.

Jim Newton07:10:11

yes, are those variables, or are they syntax for the lambda list of a macro?

Daniel Stephens11:10:17

Hi all, trying to work out the best way to install a deps.edn project into my local maven. Currently my process seems like a huge hack but I haven't been able to find much on the process. • generate the pom from the deps.edn with clj -Spom • manually edit the pom, updating the version, group and artifact ids. • run mvn install Seems a bit round-about and I'm hoping I'm missing something obvious.

Daniel Stephens11:10:13

A couple of more specific questions: • Is there some dep that will do this for me, I found uberdeps and depstar but they both still seem to expect a pom.xml to exist, so at that point I might as well use mvn I suppose. • Is there a way to get the pom generated by clj -Spom to fill out the version, group + artifact id, based on something I can write into the deps.edn itself

Daniel Stephens16:10:43

cheeky bump just in case 😬

Daniel Stephens16:10:20

ahh, I have found what I needed! https://clojure.org/reference/deps_and_cli#_local_maven_install had been misread the end of this thinking it still required a pom file

Daniel Stephens17:10:26

I take it back, I can build a jar seemingly quite easily, but the mvn-install thing seems to corrupt it

Daniel Stephens17:10:34

ahhh, what I didn't realise is that clj -Spom doesn't override the existing version/group/artifact ids, so I only have to set them once! All sorted

Day Bobby13:10:26

hi everyone, I have a namespaced map that I need to split into 2 separate maps for customer and address . I know I can destructure, however the address namespace has about a dozen things in it so Im wondering is there a quick way to extract keys from the same namespace.

{:customer/id 1 :customer/name "" :address/street "..." :address/city "..."}

alexmiller13:10:33

(let [{:customer/keys [id name] :address/keys [street city]} your-map] ...)

Day Bobby13:10:30

yes, I know I could do this. However, this gives me id name street city that I have to use to construct my new maps customer & address. I have many keys in the address namespace and would have to type them out twice (once to destructure and once to build new map). Is there a way to group them by namespace automatically from the map so I can save me some typing? Thank you!

alexmiller13:10:08

don't think so - might depend a bit on what you're doing in between the destructuring and re-building

Day Bobby14:10:46

I'm just trying to transform the result of a sql query to this form (expected by a lacinia graphql resolver)

{:id "" :name "" :address {:street "" :city ""}}

teodorlu08:10:29

If so, do you just want to filter on key namespace?

(defn filter-key-ns [m key-ns]
    (->> m
         (filter (fn [[k v]]
                   (= key-ns (namespace k))))
         (into {})))

(let [data {:customer/id 1 :customer/name "Alice"
            :address/street "Jane Street" :address/city "New York"}]
  (filter-key-ns data "customer"))
;; => #:customer{:id 1, :name "Alice"}

teodorlu08:10:58

(defn filter-key-ns-2 [m key-ns]
    (->> m
         (filter (fn [[k v]]
                   (= key-ns (namespace k))))
         (map (fn [[k v]]
                [(keyword (name k)) v]))
         (into {})))

(let [data {:customer/id 1 :customer/name "Alice"
            :address/street "Jane Street" :address/city "New York"}]
  (merge (filter-key-ns-2 data "customer")
         {:address (filter-key-ns-2 data "address")}))
;; => {:id 1, :name "Alice", :address {:street "Jane Street", :city "New York"}}

Day Bobby10:10:56

yes this is what i wanted. thank you!

teodorlu13:10:57

Glad it helped!

Chris K14:10:04

What are some easy and simple options for GUI programming with Clojure. I was looking at seesaw, but it says it is compatible with 1.5, and doesn't mention any of the newer Clojure versions so I am not sure if it will work. If not, any recommendations?

manutter5114:10:37

Check out CLJFX (and the #cljfx channel)

alexmiller14:10:36

seesaw should work just fine with newer Clojure (and Java) versions

alexmiller14:10:19

javafx (cljfx) is probably the more popular option these days though

WWeeks14:10:41

I am an experienced network engineer that wants to learn Clojure as my first language, What website should I use to learn to code in Clojure?

vncz14:10:02

I still think that the Rich Hickey's video "Clojure for Java Programmers" is the best video to start with. All the other resources I consulted before that one just failed.

practicalli14:10:06

I recommend using the websites that make sense to you most, everyone learns differently. I publish a free book and run a video series via YouTube. https://practicalli.github.io/ I do recommend using http://4Clojure.com to practice using the Clojure core functions. Keeping motivation is important when learning, so building something you find useful in Clojure will help.

manutter5114:10:21

Also http://purelyfunctional.tv if you like video tutorials

WWeeks14:10:32

Thank you. I will give those 3 websites a try for a few hours.

J Crick15:10:23

I just ran into this syntax in Hiccup (in reagent):

[:> ImportedReactComponent ]
I haven't seen this before, and, I couldn't find anything online in the Hiccup docs about it. Can someone point me to some documentation that discusses it?

J Crick15:10:01

No need! I just found it in the reagent docs. I was looking in the wrong place 🙂

Vahe15:10:38

Hi all, how Unauthorizedaccessexception can be thrown in clojure? thanks

ach clj17:10:07

Is there a way to escape commas from a string (csv)? Related but the answers are quite old: https://stackoverflow.com/questions/16215169/clojure-csv-with-escaped-comma

alexmiller17:10:14

you shouldn't escape commas - you should quote the entry. the higher-voted answer there has a link to the "spec" (as much as it is), which is what the org.clojure/data.csv library follows (the only Clojure csv parser I use regularly)

alexmiller17:10:58

$ clj -Sdeps '{:deps {org.clojure/data.csv {:mvn/version "1.0.0"}}}'
Clojure 1.10.1
user=> (require '[clojure.data.csv :as csv])
nil
user=> (csv/read-csv "\"a,b\",c")
(["a,b" "c"])

ach clj17:10:27

Got it. Will try that. I'm trying to follow the guide at https://andersmurphy.com/2019/01/06/clojure-sending-emails-with-sendgrid.html However, if the data is like:

[{:id 1, :t_id "1311350232249065472", :text "6b/ Substack: \"We've just been growing fairly consistently, and gradually the how-do-we-keep-up anxiety got bigger and bigger until there wasn't time left in the day to worry about whether we had product-market fit.\" – @cjgbest", :created_at "2020-10-01T12:17:34.611062000-00:00"}]
The resultant csv creates new column for every comma word between the commas (2nd row)

hiredman17:10:02

yep, use a real csv library

ach clj17:10:41

Yup, checking it out.

alexmiller18:10:05

Re the \" before We've - I would usually expect that to be escaped with a double quote instead ""We've

alexmiller18:10:32

and from a glance at the data.csv code that's what it's expecting too

alexmiller18:10:50

but csv is notoriously non-standardized

ach clj18:10:54

Hmm, the data from the db itself has \"

[{:id 1, :t_id "1311350232249065472", :text "6b/ Substack: \"We've just been growing fairly consistently, and gradually the how-do-we-keep-up anxiety got bigger and bigger until there wasn't time left in the day to worry about whether we had product-market fit.\" – @cjgbest", :created_at "2020-10-01T12:17:34.611062000-00:00"}]
How should I go about turning this into a valid csv structure/string?

alexmiller18:10:40

yeah, you have to deal with the data you have

alexmiller19:10:01

if I had to go out on a limb, I suspect you're not going to see that \" other than this case, so you could str/replace that with "", have no idea how often that would go wrong but might be a useful hack

ach clj19:10:27

I'll try that.

hiredman19:10:34

How did you write that csv?

hiredman19:10:17

I would say the code generating that csv is not correctly escaping quotes, so if you are generating the csv you should fix that code

ach clj20:10:32

The data stored in the db is as <the screenshot>. When reading that data using Toucan, I get the vector of maps as shared before: It looks like the following in the REPL:

[{:id 1, :t_id "1311350232249065472", :text "6b/ Substack: \"We've just been growing fairly consistently, and gradually the how-do-we-keep-up anxiety got bigger and bigger until there wasn't time left in the day to worry about whether we had product-market fit.\" – @cjgbest", :created_at "2020-10-01T12:17:34.611062000-00:00"}]
Notice the \" is already present there. Now, I need help with converting that to CSV.

ach clj20:10:52

cc:// @U064X3EF3

hiredman20:10:19

you are confusing yourself

hiredman20:10:37

the \" is escaping the " for reading in clojure

hiredman20:10:54

it is not present, what is present is a single "

hiredman20:10:40

user=> (def data [{:id 1, :t_id "1311350232249065472", :text "6b/ Substack: \"We've just been growing fairly consistently, and gradually the how-do-we-keep-up anxiety got bigger and bigger until there wasn't time left in the day to worry about whether we had product-market fit.\" – @cjgbest", :created_at "2020-10-01T12:17:34.611062000-00:00"}])
#'user/data
user=> (let [baos (java.io.ByteArrayOutputStream.) w (java.io.OutputStreamWriter. baos)] (write-csv w [[(:text (first data))]]) (.flush w) (String. (.toByteArray baos)))
"\"6b/ Substack: \"\"We've just been growing fairly consistently, and gradually the how-do-we-keep-up anxiety got bigger and bigger until there wasn't time left in the day to worry about whether we had product-market fit.\"\" – @cjgbest\"\n"
user=> (read-csv (let [baos (java.io.ByteArrayOutputStream.) w (java.io.OutputStreamWriter. baos)] (write-csv w [[(:text (first data))]]) (.flush w) (String. (.toByteArray baos))))
(["6b/ Substack: \"We've just been growing fairly consistently, and gradually the how-do-we-keep-up anxiety got bigger and bigger until there wasn't time left in the day to worry about whether we had product-market fit.\" – @cjgbest"])
user=>

hiredman20:10:22

you can see when correctly encoded the " is a double " (which is not what you have) which is why read-csv throws an error

hiredman20:10:29

if you want to print something without escaping for reading you can use println

hiredman20:10:33

user=> (def s "\"")
#'user/s
user=> s
"\""
user=> (println s)
"
nil
user=>

ach clj20:10:20

Hmm, understood the quotes issue. Thank you.

ach clj20:10:02

> if I had to go out on a limb, I suspect you're not going to see that \" other than this case, so you could str/replace that with "", have no idea how often that would go wrong but might be a useful hack The replacing hack also worked btw. Modified the escape-csv-value function to test and it does work.

(defn escape-csv-value [value]
   (-> (str/replace value #"\"" "")
      (as-> rdt (str "\"" rdt "\""))))

alexmiller19:10:51

it sounds like that's data from someone else

alexmiller19:10:03

hell is other people's data right?

hiredman19:10:44

The linked to blog post includes code for naively creating csvs without any escaping

hiredman19:10:55

Which is why I suggested data.csv

hiredman19:10:20

But you will need to generate the csv using data.csv, not the obviously incorrect code in that blog post

ryan echternacht19:10:17

Is there a pithy or builtin way to assign a key to a map if that key isn't already set? specifically when using the thread operators?

ryan echternacht19:10:44

I have

(-> map
    (assoc :key (get map key default-value))
But was curious if there is something better

ghadi19:10:57

(merge defaults-map your-map)

dpsutton19:10:58

(-> {} (update :key (fnil identity "new-value")))

dpsutton19:10:22

merge is better if its top level. good call

ryan echternacht19:10:27

ooo @dpsutton, that might be it too

ryan echternacht19:10:39

I guess merge could work too. it is top level Merge doesn't seem to work well in threading, or am I missing something?

dpsutton19:10:55

then that is preferable imo

ryan echternacht19:10:01

for the merge while using the thread operator, wouldn't I need to do something like

(-> map
    (#(merge defaults-map %))
Or am I wrong?

seancorfield20:10:54

(->> map
     (merge defaults-map))

seancorfield20:10:54

Or if you have a whole pipeline of -> stuff but want a merge of defaults somewhere in the middle:

(-> stuff
    (do-things)
    (->> (merge defaults-map))
    (do-more :things))

seancorfield20:10:31

(but, in general, it's considered somewhat bad practice to mix -> and ->> in a pipeline -- it generally indicates you're trying to do too much at once and potentially mixing data types, since sequence functions take the sequence last but collection and "object" functions take that argument first)

ryan echternacht19:10:12

or are you thinking of just doing the merge after all of the threading is complete?

ghadi20:10:05

you should not contort things just for the threading macro

ghadi20:10:31

Usually I add my defaults upfront, then thread my operations subsequently

dpsutton20:10:51

(-> (merge map defaults) ...)

ryan echternacht20:10:34

That makes sense. I have an map (from a db) that's getting a bunch of transformations applied. At the end, some validation logic runs over it. and this key needs to exist, either using what was already there or add in the default value if not. and the whole block is already threaded

ryan echternacht20:10:24

so I was hoping to slip in a 1-liner in the threading without changing too much more. thanks for the help!

Jeff Evans20:10:36

I heard somewhere (can’t remember if it was a podcast, or article, or something else) about a daily problem/challenge to solve in Clojure. Does this ring a bell for anyone?

seancorfield20:10:15

The closest I can think of is http://www.4clojure.com/

Jeff Evans20:10:23

yes! this is exactly what I was trying to recall. thanks

practicalli20:10:24

There a few good coding challenges websites https://practicalli.github.io/clojure/coding-challenges/ 4clojure is excellent for learning the core functions in Clojure, it sometimes challenges you to rewrite them (at least in part)

Jeff Evans21:10:15

ha, that is great. forcing me to rewrite my code such that it really does fir exactly into the blank is a challenge unto itself