Fork me on GitHub
#clojure
<
2021-07-13
>
anisoptera02:07:54

Is there an easy way I can make a separate lib that gets built as part of a consumer project? Right now I just stuck it in its own namespace but still in the same project

anisoptera02:07:11

Or is that a more complex build system question

seancorfield02:07:56

@anisoptera What do you mean by "lib that gets built"?

seancorfield02:07:20

Clojure can consume projects in source form so what "build" are you asking about?

anisoptera02:07:19

Hmm okay so if I just make a symlink to another project src dir or use a sub module

anisoptera02:07:38

I’m just thinking of like, a shared lib between two projects

didibus02:07:13

Yes that's easy to do

didibus02:07:26

Are you using lein or deps?

didibus02:07:53

Ok, with lein it's a bit harder, but still doable

anisoptera03:07:57

Ahhh thanks!

didibus03:07:55

With deps it's much easier though, because you can just define another folder as a dependency directly using: https://clojure.org/guides/deps_and_cli#_using_local_libraries Where you can just define the dependency as: {:deps {time-lib/time-lib {:local/root "../time-lib"}}}

seancorfield02:07:02

I'm not sure what you're asking. Can you provide a bit more background?

anisoptera03:07:44

I have project A, “drone”, and it references project B, “web3”, and can import things from the web3 namespace

anisoptera03:07:21

And I currently just have project b in project a’s src folder with its own namespace directories

seancorfield03:07:43

With lein, you could do lein install and refer to it as a dependency. Or you could use lein checkouts perhaps.

anisoptera03:07:44

But at some point I want to move it out of project A so a different project can share the code

anisoptera03:07:11

Cool, that gives me some places to start :)

seancorfield03:07:45

(and as @didibus noted in the thread -- this is much easier with the Clojure CLI and deps.edn but it is possible with lein and various plugins)

eskos05:07:15

@anisoptera check out https://github.com/amperity/lein-monolith it’s sort of like Maven multi module projects, and does enable to do stuff like you described.

hiredman05:07:34

Deeply amusing because I was working with technomancy on a clojure codebase that was built using a maven multi module build while he was writing lein, and then came into work one day to find our boss had ripped out all of the maven multi module bits and turned it into one single lein build in a single commit because the multi module stuff was such a pain

eskos08:07:45

It’s almost as if trying to circumvent artifact publishing process to eg. private Artifactory instance would be difficult on purpose… 🙂

zendevil09:07:29

has anyone deployed a jar inside nginx in docker? How does one do it?

delaguardo09:07:35

you mean the same container? nginx + your application?

zendevil09:07:08

[docker-container [nginx [ jar-app]]]

delaguardo09:07:45

so you want nginx to run your application?

delaguardo09:07:58

nginx is a proxy server, not sure I ever saw it used as an application server

eskos11:07:36

Yeah, that is not nginx’s task.

eskos11:07:58

It depends more on your full deployment environment how you want to orchestrate/load balance/reverse proxy things.

jumar13:07:56

We use nginx to serve some static content but other requests are just routed to a standalone jar running an embedded http server

emccue13:07:13

(jetty is a solid choice for that)

eskos13:07:58

Yeah, whatever your httpring server of choice uses will be fine. Jetty, Netty, Undertow, something's underneath, just lean on that.

zendevil13:07:12

Yeah I’m using aleph which I believe is built on netty

noisesmith14:07:15

there is a version of nginx that can host clojure inside it, but outside of weird performance optimization (that you probably don't need) it's just a curiousity

rutledgepaulv20:07:16

i used nginx clojure in production to stream and cache files from a private s3 bucket with custom authorization checks and auditing implemented in clojure 😆

Jim Newton09:07:40

question about clojure.test, during my test there is a failure outside of an assertion. How do I get a debuggable/clickable stack trace? what I see is a stack trace printed into the repl. I'm calling the test using (clojure.test/test-vars [#'clojure-rte.rte-test/t-circular-dfa-rte-flow])

p-himik09:07:16

> debuggable You'd have to attach a debugger first and use a breakpoint - either at a specific location if you know it, or triggered by a specific exception. > clickable That depends on your development environment. E.g. in Cursive stack traces printed with .printStackTrace are clickable.

Jim Newton09:07:41

the stack trace printed by clojure.test.do-report doesn't seem to be clickable in cider

Jim Newton10:07:25

I think it would be if clojure.test would re-throw the error (depending on some configuration variable of course)

Ed10:07:41

cider instruments clojure.test to make it "clickable"

Jim Newton10:07:36

what do I have to do to make it clickable in cider? I'm calling the test function simply from the cider repl

Ed10:07:04

(ns integration.test-test
  (:require [clojure.test :refer [deftest]]))

(deftest something
  (throw (Exception. "test")))
for me, that lets me navigate into the exception

Ed10:07:32

I think that it just needs to get thrown back up to cider's test runner

Ed10:07:26

how are you running the tests?

Jim Newton10:07:46

I'm calling it directly from the repl inside cider

Jim Newton10:07:03

I just found a menu item Cider Interactions -> Test -> Run Test

Jim Newton10:07:13

which will run 1 test, and let me navigate the failure.

Ed10:07:43

yeah ... I tend to hit C-c C-t C-n to run all the tests in a namespace

Ed10:07:25

but there are a bunch of shortcuts to get cider to run your tests, which will use cider's test reporting mechanism

✔️ 2
Jim Newton09:07:04

When I look at the code in clojure.test I see this.

(defn test-var
  "If v has a function in its :test metadata, calls that function,
  with *testing-vars* bound to (conj *testing-vars* v)."
  {:dynamic true, :added "1.1"}
  [v]
  (when-let [t (:test (meta v))]
    (binding [*testing-vars* (conj *testing-vars* v)]
      (do-report {:type :begin-test-var, :var v})
      (inc-report-counter :test)
      (try (t)
           (catch Throwable e
             (do-report {:type :error, :message "Uncaught exception, not in assertion."
                      :expected nil, :actual e})))
      (do-report {:type :end-test-var, :var v}))))
Which looks like the test is always run within a try/catch, with no facility for re-throwing the exception.

Jim Newton13:07:31

question about clojure.test. I don't see in the doctoring of the is macro whether the msg argument is promised to NOT BE evaluated in case the test passes.

Jim Newton13:07:02

oops, that wan't a question: sorry. is the msg argument guaranteed to not be evaluated if the test passes?

p-himik13:07:38

Judging by the implementation, there are cases where msg is evaluated if the test passes.

Jim Newton14:07:04

is there a clever way to evoke a side effect only if the test fails?

Kyle Ferriter14:07:30

is returns a boolean and if-not only evaluates its branches when needed

Kyle Ferriter14:07:44

you could create a macro wrapper around these replicating is but ensuring the msg arg isn't evaluated unless the test fails

noisesmith14:07:32

if you only need one branch, I think or is clearer: (or (is ....) (some side effect))

dpsutton14:07:49

I think the or above is pretty clean. If you need some more firepower you can make your own do-report that does something on failures. Since collecting these failures is a side effect of the actual testing suite

noisesmith14:07:36

oh right, clojure.test has that tooling

alexmiller13:07:56

if you don't see a guarantee then you probably shouldn't assume a guarantee

😭 2
noisesmith14:07:34

is has a return value to indicate success, putting side effects in the place of the message string is just weird

☝️ 2
2
noisesmith16:07:21

funny discovery today: if I put a future in a hash map and that future has failed, pprint omits the key/value pair entirely, and prints the message of the exception, then the rest of the map afterward

noisesmith16:07:55

oh - printing the rest was accidental, it seems there's some threading race with the printing

noisesmith16:07:00

full output in a thread here to avoid spamming

noisesmith16:07:29

what pprint does:

org.noisesmith.expecting=> (def bad-calculations {:a (future (/ 1 0)) :b (future (+ "hello" "world")) :c 42})
#'org.noisesmith.expecting/bad-calculations
org.noisesmith.expecting=> (pprint bad-calculations)
Execution error (ArithmeticException) at org.noisesmith.expecting/fn (a2ad38d8de6e530d571a2f0e206a3214c8d6fac1c305fe67d8ab4bf380e724df-init.clj:1).
Divide by zero
{:a

noisesmith16:07:42

the raw value:

org.noisesmith.expecting=> bad-calculations
{:a #object[clojure.core$future_call$reify__8454 0x447aea69 {:status :failed, :val #error {
 :cause "Divide by zero"
 :via
 [{:type java.util.concurrent.ExecutionException
   :message "java.lang.ArithmeticException: Divide by zero"
   :at [java.util.concurrent.FutureTask report "FutureTask.java" 122]}
  {:type java.lang.ArithmeticException
   :message "Divide by zero"
   :at [clojure.lang.Numbers divide "Numbers.java" 188]}]
 :trace
 [[clojure.lang.Numbers divide "Numbers.java" 188]
  [clojure.lang.Numbers divide "Numbers.java" 3901]
  [org.noisesmith.expecting$fn__1769 invokeStatic "a2ad38d8de6e530d571a2f0e206a3214c8d6fac1c305fe67d8ab4bf380e724df-init.clj" 1]
  [org.noisesmith.expecting$fn__1769 invoke "a2ad38d8de6e530d571a2f0e206a3214c8d6fac1c305fe67d8ab4bf380e724df-init.clj" 1]
  [clojure.core$binding_conveyor_fn$fn__5754 invoke "core.clj" 2030]
  [clojure.lang.AFn call "AFn.java" 18]
  [java.util.concurrent.FutureTask run "FutureTask.java" 264]
  [java.util.concurrent.ThreadPoolExecutor runWorker "ThreadPoolExecutor.java" 1128]
  [java.util.concurrent.ThreadPoolExecutor$Worker run "ThreadPoolExecutor.java" 628]
  [java.lang.Thread run "Thread.java" 829]]}}], :b #object[clojure.core$future_call$reify__8454 0x43d12484 {:status :failed, :val #error {
 :cause "class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')"
 :via
 [{:type java.util.concurrent.ExecutionException
   :message "java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')"
   :at [java.util.concurrent.FutureTask report "FutureTask.java" 122]}
  {:type java.lang.ClassCastException
   :message "class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')"
   :at [clojure.lang.Numbers add "Numbers.java" 153]}]
 :trace
 [[clojure.lang.Numbers add "Numbers.java" 153]
  [org.noisesmith.expecting$fn__1771 invokeStatic "a2ad38d8de6e530d571a2f0e206a3214c8d6fac1c305fe67d8ab4bf380e724df-init.clj" 1]
  [org.noisesmith.expecting$fn__1771 invoke "a2ad38d8de6e530d571a2f0e206a3214c8d6fac1c305fe67d8ab4bf380e724df-init.clj" 1]
  [clojure.core$binding_conveyor_fn$fn__5754 invoke "core.clj" 2030]
  [clojure.lang.AFn call "AFn.java" 18]
  [java.util.concurrent.FutureTask run "FutureTask.java" 264]
  [java.util.concurrent.ThreadPoolExecutor runWorker "ThreadPoolExecutor.java" 1128]
  [java.util.concurrent.ThreadPoolExecutor$Worker run "ThreadPoolExecutor.java" 628]
  [java.lang.Thread run "Thread.java" 829]]}}], :c 42}

noisesmith16:07:10

note that it's all data, pprint is being "helpful" in a way that obscures data now that we have good exception printing in core

noisesmith16:07:20

though the newlines in the exception printer act slightly odd when inline inside a map

noisesmith16:07:03

anyway, the behavior of pprint hides data in this case

noisesmith16:07:56

would customizing or fixing this be a question of adding / changing a print-dup implementation?

hiredman16:07:18

pprint doesn't always fliush

noisesmith16:07:37

yeah that output definitely looks like failure to flush (for starters)

noisesmith16:07:47

yeah, even when a future is not in a failed state the pprint output is worse than the default IMHO

Nazral17:07:00

Hi, I have a question regarding java interop. I'm trying to see how to use imgui from Clojure using https://github.com/SpaiR/imgui-java/blob/master/example/src/main/java/Main.java#L28, and I am really not sure how to reproduce the super.initImGui in Clojure, or how to call a class https://github.com/SpaiR/imgui-java/blob/master/example/src/main/java/Main.java#L96. Should there be some intermediate java work to make writing bindings for it more palatable?

phronmophobic18:07:22

@UGH9KH1DF, just curious why you're trying ImGui over some of the other options like seesaw, cljfx, skija, and quil. I've been working on my own desktop UI clojure lib and am interested in knowing what potential users are looking for.

Nazral18:07:08

Well, it looks very complete (e.g. I need to do lots of graphs & tables and it's all built in) and friends told me about it, but I haven't done lots of comparison with what's available I admit

👍 2
Nazral18:07:59

isn't quil mostly for procedural art?

phronmophobic18:07:31

that's quil's most popular use case, but it can be used for other stuff. I wasn't sure what you were building

phronmophobic18:07:53

ImGui is pretty neat

Nazral18:07:26

it looks like it, and I hope I'll manage to write bindings for it, but I'm not off to a good start 😄

noisesmith19:07:59

nb. this shouldn't be an issue for a GUI lib (they don't usually thread their UI code) but proxy-super is not thread safe

Nazral01:07:10

not ideal. There is another java bindings to imgui, maybe I'll have best luck with it

zendevil17:07:27

I tried but am unable to connect two repls simultaneously in atom chlorine. Is there no way around this?

mauricio.szabo19:07:58

Hi, Chlorine author here. Indeed, there's no way. What you may be able to do is have a script to disconnect from one REPL, and connect to the other.

mauricio.szabo19:07:21

The only trouble I see is that you won't explicitly have a command to disconnect the REPL, but you also can handle something with:

// Disconnect if something exists
atom.commands.dispatch(atom.views.getView(atom.workspace.getActiveTextEditor()), 'chlorine:disconnect')
setTimeout(() => {
  //connect to a new REPL
}, 200) // a time to allow REPL disconnection

zendevil08:07:59

and what’s the best way to have a cljs + clj repl workflow on vscode?

zendevil18:07:29

just need to run two separate instances of atom

seancorfield18:07:34

@ps There's a #chlorine-clover channel where the author might be able to help you.

Santiago18:07:56

I’m using Tailwind CSS for a project using only server-side rendering i.e. only clojure, no clojurescript nor JS. Setting the reasons to do this aside, I’m thinking about the best way to add classes programatically in this scenario. Example let’s say we have this function that returns some hiccup

(defn cool-element
  []
  [:div.bg-yellow-500 {:id "cool-element"}
    [:h1 "I'm an element."]])
How would you change this fn to accept & classes and add them to :div ? Maybe this is not the best notation for this use case? :thinking_face: I thought about simply manipulating strings, concatenating and turning into keyword

potetm18:07:02

@UFPEDL1LY Hiccup accepts any properties that HTML accepts. So you can do [:div {:id "cool-element, :class "bg-yellow-500"}] . The whole dot-separated, keyword class thing is just a shorthand.

Santiago05:07:18

@U05476190 is this particular to reagent? It doesn’t work for me with pure hiccup. I am not using clojurescript at all.

pithyless08:07:32

I didn't realize this was reagent specific. [0] I guess you'd have to write a helper function to do something similar:

[:div {:class (classes ["a-class" (when active? "active") "b-class"])}]
[0] https://github.com/reagent-project/reagent/blob/c214466bbcf099eafdfe28ff7cb91f99670a8433/src/reagent/impl/util.cljs#L126