Fork me on GitHub
#beginners
<
2022-01-31
>
Zoran Gasic06:01:35

In IntelliJ i want to have tests “auto runner” toggle button which when enabled, will execute tests automatically when I change a test or source file. But I don’t see it as you see on first screenshot. Second picture shows my IntelliJ test runner configuration. How can I see “auto runner” toggle button?

Old account10:01:16

Hello! How to split text by empty lines?

text1
text1

text2
Text2
So I would have 2 pieces. first:
text1
text1
and second:
text2
text2
Thanks in advance!

Mno10:01:56

I think it's just 2 newlines in a row, so:

(clojure.string/split text #"\n\n")
might work?

👍 2
pyry10:01:05

Might want to account for possible carriage returns as well, so perhaps something like #"\r?\n\r?\n" could be an improvement.

👍 2
Mno10:01:44

also clojure.string/split-lines might also be useful if you didn't know about it.

Mno10:01:30

you can use that with partition-by empty? or something would also work.

pyry10:01:01

Or if you'd rather think in terms of sequences of individual lines, something like

(->> text
     (clojure.string/split-lines)
     (partition-by clojure.string/blank?)
     (remove #(= % '(""))))
could do the trick. (edit: basically what Mno said :))

🎉 1
Mno10:01:45

I like your explanation better

Krishan V10:01:58

Hey everyone, I have a function which return a vector like this [#object[sun.nio.fs.UnixPath 0x51cb8962 "My-File"] I have this saved in an edn file with prn-str but when I attempt to read this edn, I run into an error No reader function for tag object user I do not understand readers well enough yet. Anybody knows how I should go about mapping this data-readers?

(edn/read-string (slurp "files.edn") {:readers {'object <>)}) 

noisesmith14:01:49

#object is used for many things that don't print readably, if you need to round-trip a path object it's better to give it a custom reader and custom writer. but do consider that it's probably more straightforward to write the string of the path, and then recreate it later

noisesmith14:01:20

data-readers expects a hash-map from the tag symbol to the function that creates the data type

noisesmith14:01:16

@U01V7GEU89J you got the argument order to read-string wrong - the opts come before the string to read

noisesmith14:01:11

working example:

(cmd)user=> (defn as-path [s] (java.nio.file.Paths/get s (into-array String [])))
#'user/as-path
(cmd)user=> (clojure.edn/read-string {:readers {'user/path user/as-path}} "#user/path \"foo\"")
#object[sun.nio.fs.UnixPath 0x37095ded "foo"]

noisesmith14:01:35

using print-method to create a custom writer so you can round trip:

(cmd)user=> (defmethod print-method java.nio.file.Path [p w] (.write w (str "#user/path \"" p "\"")))
#object[clojure.lang.MultiFn 0x73877e19 "clojure.lang.MultiFn@73877e19"]
(cmd)user=> (clojure.edn/read-string {:readers {'user/path user/as-path}} (pr-str (as-path "foo")))
#user/path "foo"

maverick10:01:01

I have comma-separated string "Hello,World,Three" and I want to replace this with comma separated values present in list of hash map like def maps [{:name "Hello" :value "1"} {:name "World" :value "2"} {:name"Three" :value "3"}] . Expected output 1,2,3 .

pyry11:01:13

So, to summarise: 1. Split on delimiter (here ,) 2. Look up each resulting item in maps and take the corresponding :value 3. Join results with delimiter

maverick11:01:51

Yes, correct.

pyry11:01:14

Note: step two above is easier if you can model your data structure (`maps`) differently: instead of vector of maps, can the data be modeled as a single map? (`{"Hello" "1", "World" "2", ...}`)

pyry11:01:51

Well, given the recipe above, can you come up with the parts required for the solution? 🙂

pyry11:01:23

You might wish to have a look at the clojure.string namespace.

maverick11:01:47

How can I do it using a loop ?

maverick11:01:06

Or something like this (->> maps )

pyry12:01:35

The process could look something like the following:

(->> (split text #",")
     (map lookup-value)
     (join ","))

pyry12:01:57

Where you'll have to do a bit of work for lookup-value and for split and join you might find something under clojure.string 🙂

maverick12:01:56

For lookup-value how should I pass the split string value

pyry12:01:16

Given the above, it should be a function from a comma-separated value of the input string (eg. "Hello") to the desired comma-separated output value (`"1"`).

maverick12:01:13

Yes I have written that function which will do compare on :name but the second parameter how should I pass that ?

maverick12:01:40

(map #(when (= (:name %) str) (:value %)) [{:name "Hello" :value "1"} {:name "World" :value "2"}])

maverick12:01:49

what should i pass in str ?

pyry12:01:25

I suggest you map over the result of splitting your input on ,, instead of mapping over your maps collection.

pyry12:01:17

That way the result (passed to join) will be in the order that you need it to be.

pyry12:01:02

And also the lookup-value will in that case be easier.

maverick12:01:15

Okay got it but how to perform that. I am not getting, can you share an example.

pyry12:01:29

(->> 
  (clojure.string/split input #",")
  (map lookup-value)
  (clojure.string/join ","))

pyry12:01:07

Where lookup-value could actually be a Clojure map (the persistent collection, not the function) if you modeled your data as (def lookup-value {"Hello" "1", "World" "2", "Three", "3"})`

maverick12:01:42

Ohh okay i need to flatten hash map then

pyry12:01:03

That would be the easiest course of action IMO.

pyry12:01:57

Otherwise, you'll need lookup-value to first find the correct element in maps and then get it's :value component.

pyry12:01:11

But generally if you're in control of how the data is structured, your best bet is to reshape the structure so that it's easy to work with.

maverick12:01:54

So how should I convert [{:name "Hello" :value "1"} {:name "World" :value "2"}] into one that you told. Is there any way to do it in clojure ?

pyry12:01:19

Is the data static? If it is, then just (def data {"Hello" "1", "World" "2"}) instead of (def data [{:name "Hello", :value "1"}, ...])

pyry12:01:15

If not, then there are various ways to iterate over the data, eg. the following:

(def lookup-value
  (->> 
    (for [{:keys [:name :value]} maps]
      [name value])
    (into {})))

maverick12:01:25

Okay got it. Thanks a lot @UCYS6T599

🎉 1
dorab17:01:42

Might also want to look at map-indexed.

thumbnail11:01:11

So I'm trying to add a field to the first item of my list, and the last map in a list,

[]                          => []
[{:id 1}]                   => [{:id 1, :hasPrevious false, :hasNext false}]
[{:id 1}, {:id 2}]          => [{:id 1, :hasPrevious false}, {:id 2, :hasNext false}]
[{:id 1}, {:id 2}, {:id 3}] => [{:id 1, :hasPrevious false} {:id 2} {:id 3, :hasNext false}]
The code I came up with so far is... not great 😅 (see 🧵)

thumbnail11:01:20

input is not lazy, and "usually" not big (<100 items)

pyry12:01:25

As input is finite (and smallish), you should be able to just count it. With that in mind, you should be able to do something like (map-indexed special-cases input). The implementation of special-cases could add the necessary metadata if it's given an index of 0 or (- (count input) 1).

thumbnail12:01:21

I've thought about map-indexed too; but i'm not sure it'll be much cleaner :thinking_face:. I'll give it a go in a sec

thumbnail12:01:46

In the meanwhile I spun the functions out; and instead of 1fn, i expose 2 as part of the API.

(defn add-has-previous [edges]
  (concat (when-let [x (first edges)]
            [(assoc x :hasPrevious false)])
          (rest edges)))

(defn add-has-next [edges]
  (concat (butlast edges)
          (when-let [x (last edges)]
            [(assoc x :hasNext false)])))

thumbnail12:01:59

Using an index with assoc-in also doesn't seem great;

(defn do-the-thing [input]
  (let [last-item (dec (count input))
        input' (assoc-in (vec input) [0 :hasPrevious] false)]
    (when (nat-int? last-item)
      (assoc-in input' [last-item :hasNext] false))))

thumbnail12:01:13

The map-indexed approach seems pretty clean actually 😮

(defn do-the-thing [input]
  (map-indexed (fn [idx item]
                 (assoc item
                   :hasNext     (not= idx (dec (count input)))
                   :hasPrevious (not (zero? idx))))
               input))

pyry12:01:53

How about this?

(map-indexed (fn [idx val]
                   (cond-> val
                           (= 0 idx)
                           (assoc :hasPrevious false)
                           (= (- (count items) 1) idx)
                           (assoc :hasNext false)))
                 items)
(edit: fixed threaded assoc usage)

thumbnail13:01:06

Yeah that's actually way less cumbersome. Thanks 🙂 !

pyry13:01:50

Welcome. To be honest, I might prefer your latest version over mine. But anyhow I think either version is quite a bit clearer than what we started out with. 🙂

clojure-spin 1
Patrix12:01:03

hmm I didn’t think I was a beginner but definitely feel like one right now. I’m looking at https://kit-clj.github.io and seeing the 2 lines to install it first one is: clojure -Ttools install com.github.seancorfield/clj-new '{:git/tag "v1.2.381"}' :as new This is what I get: Error building classpath. Unknown tool: tools I have the latest clojure cli tools , on macos 12 (1.10.3.1069). Just in case I’ve removed my ~/.clojure dir to have a fresh one generated. I’m sure I’m missing something obvious.. Could anyone point me in the right direction please?

practicalli-johnny14:01:57

The same command worked for me on the same version (on Ubuntu) Check the version using clojure -Sdescribe to check its using the version you think it should be using.

practicalli-johnny14:01:40

Alternatively, try adding an alias to the user level configuration, ~/.config/clojure/deps.edn or ~/.clojure/deps.edn This is an example from https://github.com/practicalli/clojure-deps-edn/

:project/new
  {:replace-deps {com.github.seancorfield/clj-new {:mvn/version "1.2.381"}}
   :exec-fn      clj-new/create
   :exec-args    {:template lib :name practicalli/playground}
   :main-opts    ["-m" "clj-new.create"]}
Then call the alias with the -T option (this is not the same as installing, this is just using the library as a tool)
clojure -T:project/new
Arguments will be key value pairs (but not in a map)

practicalli-johnny14:01:51

If you cannot get any tools to install, suggest asking in the #tools-deps channel for help.

Patrix23:01:38

thanks @U05254DQM, while that did help somewhat, I got some more errors after that.. Let me check with #tools-deps for further help

Patrix23:01:26

$ clojure -T:project/new create :template io.github.kit-clj :name pat/pat
Unqualified function can't be resolved: create
(that’s after it downloaded clj-new deps)

Patrix06:02:57

for anyone following here, the issue is due to macports not including tools.edn in its installed distribution of clojure. extracting tools.edn from an official tgz and copying it to /opt/local/lib/clojure/ (and keeping it in ~/.clojure/tools/ as well, but by default it will be copied there when using clojure -Ttools the first time), resolved it.. at least until the next time clojure gets updated.

dharrigan15:01:24

Is there a nice way to test if something is a collection, to return the first element, or if not a collection, just return the original var, i.e., (if (sequential? thang) (first thang) thang))?

Alex Miller (Clojure team)15:01:24

my strong recommendation would be to not do this and just always take one or the other

Alex Miller (Clojure team)15:01:26

but I don't know of a better way to write it

dharrigan16:01:21

Thank you, I'll see what I can do to change the code 🙂

Ben Sless16:01:57

With a protocol?

noisesmith17:01:56

code like this is often needed when acquiring data from a badly designed API, always convert once (at the point of acquisition).

noisesmith17:01:46

otherwise the test for single item vs. collection becomes contagious and spreads to all the code that ends up touching the data (the principled way to handle that is a protocol or multimethod, but it's much better to simply convert once at the boundary of your app)

noisesmith17:01:52

also, most of the time if an API provides data that is sometimes an X and sometimes a sequence of X, the right way to handle it is to turn the bare item into a one element vector

Dieter16:01:19

How to do java interop with nested interfaces? An example from a library does this: PlcReadRequest.Builder builder = plcConnection.readRequestBuilder(); how can you implement this in clojure?

noisesmith17:01:58

nested classes are not actually nested, in the vm (and therefore for clojure interop) Foo.Bar becomes a class called Foo$Bar. But you don't need to reference the nested class to translate the code in your example: (.readRequestBuilder plcConnection)

Dieter06:02:43

That works! Thanks a lot! I was completely stuck 😅

John Bradens18:01:57

Hi I'm trying the learn-clojurescript book lesson 5. It says to add

{:aliases
 {:new {:extra-deps {seancorfield/clj-new
                     {:mvn/version "1.1.243"}}
        :exec-fn clj-new/create
        :exec-args {}}}}
And then run
clj -X:new :template figwheel-main :name learn-cljs/weather :args '["+deps" "--reagent"]'
But then I get
WARNING: Specified aliases are undeclared: [:new]
No function found on command line or in :exec-fn
What do I do?

dpsutton18:01:19

can you post your full deps.edn file?

Josh Horwitz18:01:43

where are you adding it, in your ~/.clojure/deps.edn?

John Bradens19:01:02

Yes so this might be where I have it wrong. The book says to have a deps.edn file, and then it says to add the alias to a /.clojure/deps.edn, and I might have done that wrong. I'll show you what I have

John Bradens19:01:49

for deps.edn:

{:deps {org.clojure/clojurescript {:mvn/version "1.10.773"}}
 :paths ["src"]

 :aliases
 {:dev {:main-opts ["-m" "cljs.main"
                    "--compile" "my-cljs-project.core"
                    "--repl"]}}}
for /.clojure/deps.edn I just added a directory called .clojure in vscode, then added a file called deps.edn:
{:aliases
 {:new {:extra-deps {seancorfield/clj-new
                     {:mvn/version "1.1.243"}}
        :exec-fn clj-new/create
        :exec-args {}}}}

John Bradens19:01:10

It's all within the same project folder

John Bradens19:01:37

This is my file tree

dpsutton19:01:44

ah. You need that .clojure/deps.edn to be in your root directory, not just in a random directory

dpsutton19:01:13

~/.clojure/deps.edn vs ~/some/random/project/.clojure/deps.edn. It is your user’s own specified aliases and options

John Bradens19:01:14

Thanks @U11BV7MTK it works now!

👍 1
Lukas20:01:50

Hey guys, I hope you are doing well! I wrote a macro in which I use a transducer like this

(defmacro dbg []
   (let [xf (comp (filter odd?) (take 5))
         s [1 2 3 4 6 6 7 8 8 9 7]]
     `(transduce ~xf conj [] ~s)))
  
(dbg)
but when I try to evaluate (dbg) I get an Exception
1. Caused by java.lang.IllegalArgumentException
   No matching ctor found for class clojure.core$comp$fn__5825
Any help to resolve this is greatly appreciated :)

Lukas20:01:08

full error msg

2. Unhandled java.lang.ExceptionInInitializerError
   (No message)

NativeConstructorAccessorImpl.java:   -2  jdk.internal.reflect.NativeConstructorAccessorImpl/newInstance0
NativeConstructorAccessorImpl.java:   77  jdk.internal.reflect.NativeConstructorAccessorImpl/newInstance
DelegatingConstructorAccessorImpl.java:   45  jdk.internal.reflect.DelegatingConstructorAccessorImpl/newInstance
          Constructor.java:  499  java.lang.reflect.Constructor/newInstanceWithCaller
          Constructor.java:  480  java.lang.reflect.Constructor/newInstance
             Compiler.java: 5000  clojure.lang.Compiler$ObjExpr/eval
             Compiler.java: 7180  clojure.lang.Compiler/eval
             Compiler.java: 7136  clojure.lang.Compiler/eval
                  core.clj: 3202  clojure.core/eval
                  core.clj: 3198  clojure.core/eval
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn/fn
                  AFn.java:  152  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  core.clj:  667  clojure.core/apply
                  core.clj: 1977  clojure.core/with-bindings*
                  core.clj: 1977  clojure.core/with-bindings*
               RestFn.java:  425  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn
                  main.clj:  437  clojure.main/repl/read-eval-print/fn
                  main.clj:  437  clojure.main/repl/read-eval-print
                  main.clj:  458  clojure.main/repl/fn
                  main.clj:  458  clojure.main/repl
                  main.clj:  368  clojure.main/repl
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   84  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   56  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  152  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  218  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  217  nrepl.middleware.session/session-exec/main-loop
                  AFn.java:   22  clojure.lang.AFn/run
               Thread.java:  833  java.lang.Thread/run

1. Caused by java.lang.IllegalArgumentException
   No matching ctor found for class clojure.core$comp$fn__5825

            Reflector.java:  288  clojure.lang.Reflector/invokeConstructor
           LispReader.java: 1317  clojure.lang.LispReader$EvalReader/invoke
           LispReader.java:  853  clojure.lang.LispReader$DispatchReader/invoke
           LispReader.java:  285  clojure.lang.LispReader/read
           LispReader.java:  216  clojure.lang.LispReader/read
           LispReader.java:  205  clojure.lang.LispReader/read
                   RT.java: 1879  clojure.lang.RT/readString
                   RT.java: 1874  clojure.lang.RT/readString
                      REPL:  260  lhrb.words.solver/eval152134873
NativeConstructorAccessorImpl.java:   -2  jdk.internal.reflect.NativeConstructorAccessorImpl/newInstance0
NativeConstructorAccessorImpl.java:   77  jdk.internal.reflect.NativeConstructorAccessorImpl/newInstance
DelegatingConstructorAccessorImpl.java:   45  jdk.internal.reflect.DelegatingConstructorAccessorImpl/newInstance
          Constructor.java:  499  java.lang.reflect.Constructor/newInstanceWithCaller
          Constructor.java:  480  java.lang.reflect.Constructor/newInstance
             Compiler.java: 5000  clojure.lang.Compiler$ObjExpr/eval
             Compiler.java: 7180  clojure.lang.Compiler/eval
             Compiler.java: 7136  clojure.lang.Compiler/eval
                  core.clj: 3202  clojure.core/eval
                  core.clj: 3198  clojure.core/eval
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn/fn
                  AFn.java:  152  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  core.clj:  667  clojure.core/apply
                  core.clj: 1977  clojure.core/with-bindings*
                  core.clj: 1977  clojure.core/with-bindings*
               RestFn.java:  425  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn
                  main.clj:  437  clojure.main/repl/read-eval-print/fn
                  main.clj:  437  clojure.main/repl/read-eval-print
                  main.clj:  458  clojure.main/repl/fn
                  main.clj:  458  clojure.main/repl
                  main.clj:  368  clojure.main/repl
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   84  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   56  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  152  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  218  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  217  nrepl.middleware.session/session-exec/main-loop
                  AFn.java:   22  clojure.lang.AFn/run
               Thread.java:  833  java.lang.Thread/run

noisesmith00:02:35

the issue here is that a macro needs to serialize data into the form it generates, and some arbitrary objects (including this transducer) don't round trip cleanly

noisesmith00:02:52

you've already solved it by quoting the construction of the transducer of course

Lukas20:01:58

okay sry to bother you just figured:

(defmacro dbg []
   (let [xf '(comp (filter odd?) (take 5))
         s [1 2 3 4 6 6 7 8 8 9 7]]
     `(transduce ~xf conj [] ~s)))
does the trick 🙈