Fork me on GitHub
#clojure
<
2019-12-12
>
ag01:12:09

What’s the elegant way of doing something like:

(or 
  (get m :foo)
  (get m :bar)
  (get m :zap))
I see it often, and although it’s clear that way, I don’t like it (for some reason)

dpsutton01:12:45

(some-fn :foo :bar :zap)

ag01:12:21

ah… right… thanks Dan. Maybe I should’ve said “I don’t like it (for some-fn reason)“. 🙂

dpsutton01:12:57

I always forget about that one :)

ag01:12:49

yeah, it’s tricky because it’s kind of opposite of every-pred but the name is not similar

💯 4
dpsutton01:12:18

yeah i had to apropos it today because i couldn't recall it 🙂

andy.fingerhut01:12:37

The Clojure cheat sheet puts them in the same group with each other, so if you remember one, you can find the other: https://clojure.org/api/cheatsheet

👍 4
ag02:12:46

Meh, who needs a cheatsheet when there are awesome people right here 🙂

Lyn Headley03:12:46

I'm working on a library to be called from both clojure and clojurescript. I'd like to write unit tests in .cljc files and have them work in both clojure and clojurescript, though I expect I'd invoke them differently (via different repls or test runners). Are there examples of others doing this I can study?

andy.fingerhut09:12:11

The latest core.rrb-vector library is almost ready to do this, as soon as the primary author agrees they are willing to require Clojure 1.7.0 and later, when clic files were introduced. It has several test files that are nearly identical to each other for clj and cljs, and ready to be merged into common clic files with only a small use of reader conditionals in a few places. It also has a debug.clj and debug.cljs file nearly identical similarly ready to be merged into a common clic file. It has a deps.edn file that can run tests for each clj or cljs from the command line, and a Leiningen project.clj file that can run tests for either clj or cljs. https://github.com/clojure/core.rrb-vector Note that this was my first project I worked on using cljs at all, so I don't claim it is necessarily the best way to do things here.

andy.fingerhut09:12:19

The README of that project gives several commands you can use to run the included tests.

mauricio.szabo13:12:11

It also have a CI script (.travis.yml) to run tests on both Clojure and ClojureScript

Balaji Sivaramgari03:12:07

08:58:24.138 INFO: ------------------------------------------------------------------------ 08:58:24.138 ERROR: Error during SonarQube Scanner execution org.sonar.api.utils.command.CommandException: http://java.io.IOException: Cannot run program "lein": CreateProcess error=2, The system cannot find the file specified at org.sonar.api.utils.command.CommandExecutor.execute(CommandExecutor.java:102) at org.sonar.plugins.clojure.sensors.CommandRunner.run(CommandRunner.java:36) at org.sonar.plugins.clojure.sensors.CommandRunner.run(CommandRunner.java:50) at org.sonar.plugins.clojure.sensors.eastwood.EastwoodSensor.execute(EastwoodSensor.java:47) at org.sonar.scanner.sensor.AbstractSensorWrapper.analyse(AbstractSensorWrapper.java:48) at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:85) at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:62) at org.sonar.scanner.scan.ModuleScanContainer.doAfterStart(ModuleScanContainer.java:82) at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136) at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122) at org.sonar.scanner.scan.ProjectScanContainer.scan(ProjectScanContainer.java:387) at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:383) at org.sonar.scanner.scan.ProjectScanContainer.doAfterStart(ProjectScanContainer.java:346) at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136) at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122) at org.sonar.scanner.bootstrap.GlobalContainer.doAfterStart(GlobalContainer.java:141) at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:136) at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:122) at org.sonar.batch.bootstrapper.Batch.doExecute(Batch.java:72) at org.sonar.batch.bootstrapper.Batch.execute(Batch.java:66) at org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher.execute(BatchIsolatedLauncher.java:46) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) at org.sonarsource.scanner.api.internal.IsolatedLauncherProxy.invoke(IsolatedLauncherProxy.java:60) at com.sun.proxy.$Proxy0.execute(Unknown Source) at org.sonarsource.scanner.api.EmbeddedScanner.doExecute(EmbeddedScanner.java:189) at org.sonarsource.scanner.api.EmbeddedScanner.execute(EmbeddedScanner.java:138) at org.sonarsource.scanner.cli.Main.execute(Main.java:112) at org.sonarsource.scanner.cli.Main.execute(Main.java:75) at org.sonarsource.scanner.cli.Main.main(Main.java:61) Caused by: http://java.io.IOException: Cannot run program "lein": CreateProcess error=2, The system cannot find the file specified at java.base/java.lang.ProcessBuilder.start(Unknown Source) at java.base/java.lang.ProcessBuilder.start(Unknown Source) at org.sonar.api.utils.command.CommandExecutor.execute(CommandExecutor.java:74) ... 31 more Caused by: http://java.io.IOException: CreateProcess error=2, The system cannot find the file specified Even the lein is added to the PATH variable. $ which lein /c/Users/XXXXXX/lein

Balaji Sivaramgari03:12:39

This is the setup I am trying in local windows machine. and we are trying to run the sonarqube code analysis for clojure projects

Balaji Sivaramgari03:12:12

:jvm-opts ["-Xmx15g" "-server"] is the memory settings in my project.clj file

kulminaator08:12:40

I have opted into keeping the lein script in my repos, as it installs itself on the go if needed. Doing the same with gradle wrapper for java projects.

kulminaator08:12:00

Lein bash script is pretty tiny. It fits.

kulminaator08:12:10

And i actually want to write code and make products/services work, not spend my life configuring and tracing issues of various build agents & platforms 🙂

borkdude08:12:39

are nested syntax-quotes a feature or undefined territory?

(println
 `(+ 1 2 3 `(+ 1 2 3)))

sogaiu14:12:05

fwiw, they appear in "joy of clojure" and other places. coincidentally, trying to wrap my head around reading them :)

borkdude14:12:16

@UG1C3AD5Z I mean nested without an intermediate unquote

sogaiu14:12:43

i haven't found that to be too common, but that does appear in the aforementioned book.

sogaiu14:12:06

would like to hear opinions of more experienced people ofc 🙂

borkdude14:12:11

I guess I'll have to support that in babashka too then 😉

sogaiu14:12:26

ha ha ha fwiw, i haven't thoroughly digested the book -- the place i saw it was in 8.1.1 in a side bar. not so sure there are that many real-world uses for such things.

borkdude08:12:13

Someone mentioned this code in #clj-kondo:

(defn example
  [name]
  `(defmacro ~name [& args#]
     `(foo ~(keyword '~name) ~@args#)))

kulminaator08:12:51

if stuff gets scary then people tend to bring out pitchforks ... and this is getting slightly scary yes 😄

valerauko13:12:11

is there any not-too-hacky way to use an existing third-party clojurescript library (in my case com.taoensso/sente) from a client-side (webpacked) javascript (vuejs) project?

borkdude14:12:14

@vale you can compile the project using a small JS interface to advanced JS

borkdude14:12:21

and then use that from JS

valerauko14:12:01

i'll look at that, thanks!

Vincent Cantin11:12:40

The channels #announcements and #news-and-articles are a better place for posting links like this one.

erwinrooijakkers12:12:55

Thanks for next time!

amalantony14:12:02

Hello, I'm trying to get a simple redirect middleware to work with compojure-api, while my middleware indeed seems to be getting called, the redirect isn't working. Any ideas? Here's what my code looks like:

(defn redirect [handler]
  (fn [req]
    (let [uri (:uri req)
          fixed-req (assoc req :uri "")]
      (handler fixed-req))))

(def app
  (api
   {:swagger
    {:ui "/"
     :spec "/swagger.json"
     :data {:info {:title "Dice-api"
                   :description "Compojure Api example"}
            :tags [{:name "api", :description "some apis"}]}}}

   (context "/api" []
     :tags ["api"]
     :middleware [redirect]

     (GET "/roll/:n/:s" []
       :path-params [n :- s/Int
                     s :- s/Int]
       :return Result
       :summary "Rolls :n dice of sides :s"
       (ok (roll-dice n s)))
     (POST "/roll" []
       :body-params [num :- s/Int
                     sides :- s/Int]
       :return Result
       :summary "Given a correct request body with keys :num and :sides, returns result of roll"
       (ok (roll-dice num sides))))

   (undocumented
    (route/resources "/")
    (route/not-found "404 Not Found"))))

ikitommi15:12:43

@amalantony to always redirect, you could:

(defn redirect [handler]
  (fn [req]
    (see-other "")))

amalantony15:12:22

@U055NJ5CC That actually works for redirection. Thanks.

Luke Schubert15:12:18

is there a clean way to modify multiple items at the bottom of a deeply nested series of hash-maps and sequences?

Luke Schubert15:12:32

without a bunch of nested maps/updates

p-himik15:12:30

If you do that often, consider using https://github.com/redplanetlabs/specter

Aleks Abla15:12:05

Hi everyone, running into a weird compiling error. Getting the following message: Syntax error compiling at (report_logic.clj:1:1). Unable to resolve symbol: ​ in this context

ethanc15:12:03

Is there a Zero width space in there?

Aleks Abla15:12:04

it happens when I am trying to evaluate my entire project.

Aleks Abla15:12:32

yes that seems to be the case

ethanc15:12:09

yeah, seems if i add a zero width space i get the same error. I would assume simply removing it/them it would solve the issue

ethanc15:12:56

My guess as to why it fails is because java doesn’t treat Zero width spaces as ‘whitespace’, and it seems that Clojure uses java’s definition of whitespace while reading files. https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LispReader.java#L130-L132

Aleks Abla16:12:37

yea, i am just a little confused as to where the error comes from... there is no whitespace as far as i can tell

valerauko16:12:25

it definitely seems to be there in the message you pasted. you can check by highlighting and moving the cursor with the arrow keys

ethanc16:12:46

Each of the empty lines in the snippet seem to contain a zero width space

p-himik16:12:18

@ablazevix hexdump -C or something like that is your friend.

Aleks Abla16:12:51

awesome thanks guys, i'll try some things

Aleks Abla16:12:15

@p-himik hexdump -C is my friend... but y'all are my best friends lol

❤️ 8
valerauko16:12:23

you can try search-replace \u200B (the zero-width space)

p-himik16:12:35

People are temporary, CLI tools are eternal.

8
ghadi16:12:50

that's dark

Aleks Abla16:12:44

removed the spaces and that seemed to have fixed it.. all tests passed

👍 4
evocatus17:12:23

can you help me with walkable library? I managed to get a "floor-plan" that is created correctly (though i'm not sure, at least it doesn't cause an exception). I wrote a simple query:

(def my-query [{(:person/all {:limit 5}) [:person/name :person/surname]}])
When I try to print it I get
[{nil [:person/name :person/surname]}]
What should I do to get a query string to pas it to jdbc/query? Or does it work other way? I suppose there should be some function for that in walkable library but there is nothing about executing queries in it's docs

p-himik17:12:17

my-query is a vector of one map. That one map's key is (:person/all {:limit 5}). Since you're using parenthesis and are not quoting anything, it because a call of function :person/all on map {:limit 5}. The map doesn't have that key, so the result is nil, which you see when you print my-query.

p-himik17:12:54

This particular error has nothing to do with the walkable library itself. Alas, I cannot answer your other question about turning this vector into a string.

p-himik17:12:41

But the answer to that question is probably here, in the documentation: https://walkable.gitlab.io/emitter.html

seancorfield17:12:13

There's a #walkable channel if you need assistance with it @UEQDV142J

evocatus17:12:59

Thanks a lot 🙂

g7s17:12:04

I have values in my program that are sorted-map-by with a custom comparator. Up until now I used a reader tag to read back those values in EDN but now I want to read/write in transit. All those values have a :type metadata (say :foo). Providing a write handler with {:foo foo-write-handler} seems that it doesn’t work and I can understand why. My question is what is the preferrable approach if one wants to read/write in transit a value that has type metadata?

Alex Miller (Clojure team)17:12:41

"doesn't work" == what ?

g7s17:12:46

Yes I read that. By doesn’t work means that in the handlers map

{:handlers {clojure.lang.PersistentTreeSet sorted-set-write-handler}}

g7s17:12:24

I cannot provide as a key the :type metadata of the value

Alex Miller (Clojure team)17:12:25

transit-clj is built on transit-java, and relies on concrete classes, not metadata (as Java doesn't have it)

g7s17:12:47

I know and I understand why. My question remains though, how should I approach this?

g7s17:12:11

Should I wrap the value in a class or something?

Alex Miller (Clojure team)17:12:41

use clojure.lang.PersistentTreeMap ?

g7s17:12:52

hmm yeah you are right I can use that and emit a custom tag if the value has my :type metadata so as to use the custom comparator to construct the value

g7s17:12:58

because t/write-handler accepts a function that given the value returns the tag to write for that value

deas19:12:46

Quick question: What's the tool of choice for namespace dependency graph visualization?

andy.fingerhut19:12:06

I don't know which is best supported or featureful/working, but these exist: https://github.com/walmartlabs/vizdeps. https://cljdoc.org/d/lein-hiera/lein-hiera/1.1.0/doc/readme

👍 4
deas19:12:35

Quick try with lein hiera: java.lang.IllegalArgumentException: "Unparsable namespace form:" ["parinfer-codemirror"] 💥 😉

Aleks Abla20:12:03

can anyone recommend a way to get a value out of a hash-map? I tried (vals #{:shoes}) but i believe vals only works on maps

frozenlock20:12:47

Value out of a set or a hash-map?

Aleks Abla20:12:27

sorry, I meant hash-set #{:shoes}

frozenlock20:12:26

Could you provide a slightly more detailed example? Are you trying to convert a set into a list/vector?

Aleks Abla20:12:42

I have a map in which there is a KV pair :interests {#:shoes} :interests {#:clothes} :interests {#:watches}

Aleks Abla20:12:39

im slurping out interests, and the values are coming out as {#:shoes} {#:clothes}

Aleks Abla20:12:56

instead would like to have them come out as strings

Aleks Abla20:12:24

was thinking of doing that with mapping vals but that won't work I think

jumpnbrownweasel20:12:28

You could just call seq on the set.

jumpnbrownweasel20:12:03

But the set itself is a collection, so you can pass it to map.

frozenlock20:12:33

(map name #{:shoes :pants})
=> ("shoes" "pants")

Aleks Abla20:12:09

right on, thanks gentleman

Aleks Abla20:12:32

newbie question -- how often do you use seq?

Alex Miller (Clojure team)20:12:01

all sequence function seq their input, so generally you don't need to use it that often

seancorfield20:12:03

I mostly only use it for checking whether some collection or sequence is non-empty...

Aleks Abla20:12:37

good to know! thanks again folks

seancorfield20:12:41

I just searched our codebase for calls to seq (90K lines of Clojure) and there are maybe half a dozen places where we call seq outside of a conditional context (`if`, when, etc) -- and those half dozen are all in really old code and seem to be unnecessary so they could be removed... indicative of days when we were still very new to Clojure!

🙏 4
💯 4
enn21:12:11

Is it possible in Java (and thus Clojure), from a Java program running in a TTY, to run a subprocess with access to that same TTY (or some kind of pseudo-terminal to the same effect, so that the user can interact with that subprocess as though it were running in the same TTY)?

enn21:12:55

The closest I've gotten is using ProcessBuilder.inheritIO, but that just redirects stderr, stdout, and stdin, without giving real terminal access to the subprocess (vim, for example, will warn that "Output is not to a terminal" and "Input is not from a terminal" and will not be usable).

andy.fingerhut21:12:47

I don't know, but you may get better results than the following maybe-useful page, which I found using Google with search terms: java subprocess inherit tty https://jonisalonen.com/2012/runtime-exec-with-unix-console-programs/

enn21:12:26

yes, ProcessBuilder.inheritIO which I mentioned is just a shorthand for that. It might work for simple tools like less (the example on that page), but it is not sufficient for curses-type tools which need to control the cursor, determine window size, etc.

bfabry21:12:30

I don't think java has access to the tty out of the box does it?

bfabry21:12:40

that would seem very hard to be platform independent

bfabry21:12:20

yeah all the examples I'm finding rely on a natively compiled curses or similar

enn21:12:46

It looks like the only way to do this is a kludge using bash, which I'm trying now: https://stackoverflow.com/questions/29733038/running-interactive-shell-program-in-java

noisesmith22:12:53

I wonder if that kluge is possible without bash, since you can pass a file for the child to use for io - or maybe bash does something "magic" for /dev/tty

noisesmith22:12:09

this successfully runs vi with full tty from OSX:

justin.smith@C02RW05WFVH6: ~$ clojure vilaunch.clj 
0

;; viluanch.clj
(def vi-ret
  (let [vi-command (ProcessBuilder. ["/usr/bin/vi"])
        tty (.File. "/dev/tty")]
    (doto vi-command
      (.redirectError tty)
      (.redirectOutput tty)
      (.redirectInput tty))
    (-> vi-command
        (.start)
        (.waitFor))))

(prn vi-ret)

noisesmith22:12:27

running that file gives you a normal vi session, then prints the return value of the vi process before exiting

noisesmith22:12:14

I was skeptical, but that code also works inside a repl that uses readline via clj!

noisesmith22:12:08

hmm, for me (OSX, http://terminal.app, clojure cli tool) this works too:

(-> (ProcessBuilder. ["/usr/bin/vi"])
    (.inheritIO)
    (.start)
    (.waitFor))

enn14:12:38

hmm. that second one didn't work for me with vim. I didn't try with plain vi, though. The first approach looks interesting, I will try that as well.

noisesmith18:12:56

note that the waitFor is mandatory - vi and the repl both become unusable without the waitFor, as they take turns stealing input and neither gets coherent input

favila22:12:11

Is there a way to get :extra-deps to resolve using :default-deps ? Usecase is I want to have an eastwood alias across many modules, but I don’t want to repeat the eastwood version

seancorfield22:12:06

@favila You want :override-deps for that, not :default-deps

seancorfield22:12:37

Then you can say :extra-deps {some.group/artifact {}}

seancorfield22:12:45

(which is what we do at work)

seancorfield22:12:57

I don't think :default-deps really works...?

favila23:12:23

:override-deps will “pin” even transient versions, right?

favila23:12:43

i.e. versions not explicitly required via a deps.edn, but required via a transitive dependency

favila23:12:43

:default-deps works for :deps if the coordinate is nil

favila23:12:39

{:deps {foo nil} :aliases {:defaults {:default-deps {foo {:mvn/version "1.2.3"}}}}

favila23:12:51

but not for extra-deps it seems

favila23:12:35

😕 I take that back, it seems to work fine

favila23:12:41

not sure what I was doing wrong

seancorfield23:12:33

My reading of what Alex has said about :default-deps is that they really aren't fully fleshed out so I've avoided them. In answer to your question about transitive deps, yes, :override-deps will pin those too (we rely on that a lot).

noisesmith22:12:09

this successfully runs vi with full tty from OSX:

justin.smith@C02RW05WFVH6: ~$ clojure vilaunch.clj 
0

;; viluanch.clj
(def vi-ret
  (let [vi-command (ProcessBuilder. ["/usr/bin/vi"])
        tty (.File. "/dev/tty")]
    (doto vi-command
      (.redirectError tty)
      (.redirectOutput tty)
      (.redirectInput tty))
    (-> vi-command
        (.start)
        (.waitFor))))

(prn vi-ret)

niveauverleih22:12:08

I need help with the following. I am composing transducers. The input data is a vector of tuples of three things: an integer, a string and a map. The first couple of transducers in the composition reshape only the maps and leave the integers and the strings unchanged. Only the last transducer combines all the data. I managed to do this, but I wonder if there is a better way. If the composition were a defn, I would use let to put the unused string and integer aside; alas transducer compositions are defs.

didibus22:12:02

Are you re-using this transducer chain on a lot of different datasets? Otherwise just make a function out of it.

niveauverleih07:12:19

I use it in an core.async pipeline to process REST API json responses. The different transducers do the following: extract body from the http response, parse json, extract some data from the json (several steps), combine the extracted data with the parameters I used initially for the API call. I prefer the transducers over functions because of the performance gain (no intermediate sequences between calculations) and the ease of use with the pipeline function I run the whole thing in a loop over hundreds of API calls. The responses all have the same structure.

noisesmith23:12:24

@nick.romer what specifically would a defn do here that a def wouldn't be able to?

niveauverleih07:12:16

As far as I understand (noob,first heard about clojure 2 months ago) def allows to compose transducers using comp, while defn doesn't. Inversely, defn has access to the data being transformed (the function arguments), while def doesn't. Only the individual transducers being chained together do have access.

p-himik08:12:46

What do you mean by "defn has access to the data"? defn is just a syntactic sugar for (def (fn ...)).

niveauverleih08:12:51

I should have said fn. A function has arguments. A composition of transducers doesn't.

p-himik08:12:12

If you're worrying that you have all these transform-third-map functions lying around not being very generic, just extract transform-map functions from them and wrap them in something like (fn [[x y m]] [x y (transform-map m)]) (assuming that you're fine working only with vectors).

p-himik08:12:16

Strictly speaking, a composition of transducers has arguments - it's a reducing function. But I probably see what you mean. And how would having the arguments help you?

p-himik08:12:34

Maybe it would be easier for us to understand what you want if there was a concrete example.

niveauverleih08:12:28

I actually did what you proposed above. What bothers me is that I have to let the non-map values trickle down the chain of transducers. I'd rather put them somewhere temporarily and fetch them when I need them. Is it possible to have 2 parallel chains of transducers and to join them at some point?

p-himik08:12:38

> I'd rather put them somewhere temporarily and fetch them when I need them You need transducers only to do half of the job. Just do exactly as you have yourself told - extract the not relevant values under some name, run the transducers chain over the stripped down data, join the result back with the extracted values.

p-himik08:12:19

If you have all sorts of different extractions, mappings, and joins throughout your projects, you can find https://github.com/redplanetlabs/specter useful.

niveauverleih08:12:55

You understood my problem correctly. I guess I'll have to let go of the pipeline function and put / retrieve my data on / from the channels with <! And >! . I didn't know about specter. I'll look into it. Thank you very much!

niveauverleih07:12:19

I use it in an core.async pipeline to process REST API json responses. The different transducers do the following: extract body from the http response, parse json, extract some data from the json (several steps), combine the extracted data with the parameters I used initially for the API call. I prefer the transducers over functions because of the performance gain (no intermediate sequences between calculations) and the ease of use with the pipeline function I run the whole thing in a loop over hundreds of API calls. The responses all have the same structure.

niveauverleih07:12:16

As far as I understand (noob,first heard about clojure 2 months ago) def allows to compose transducers using comp, while defn doesn't. Inversely, defn has access to the data being transformed (the function arguments), while def doesn't. Only the individual transducers being chained together do have access.