This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-01-24
Channels
- # announcements (3)
- # aws (5)
- # babashka (10)
- # beginners (61)
- # calva (22)
- # clara (9)
- # clj-kondo (8)
- # cljdoc (8)
- # cljsrn (15)
- # clojure (44)
- # clojure-australia (2)
- # clojure-europe (31)
- # clojure-hungary (20)
- # clojure-nl (5)
- # clojure-uk (3)
- # core-logic (2)
- # cursive (2)
- # data-science (2)
- # datalevin (4)
- # datascript (6)
- # datomic (17)
- # defnpodcast (1)
- # figwheel-main (1)
- # fulcro (18)
- # graalvm (2)
- # introduce-yourself (2)
- # jobs (1)
- # jobs-discuss (59)
- # lsp (44)
- # music (1)
- # nrepl (2)
- # off-topic (26)
- # pedestal (2)
- # re-frame (12)
- # reagent (27)
- # releases (1)
- # remote-jobs (4)
- # rewrite-clj (2)
- # sci (12)
- # shadow-cljs (12)
- # sql (10)
- # uncomplicate (6)
- # vim (12)
- # xtdb (2)
Anybody have any strong opinions about the “best” library for manipulating URIs/URLs? I need something that will easily add query parameters, handling coding transparently, break things apart, etc. I’d like something that’s a bit more useful than java.net.URL or http://java.net.URI. Exploding Fish seems interesting (https://github.com/wtetzner/exploding-fish). Anybody have any strong opinions about it or others that you particularly like/hate?
I've found lambdaisland/uri
useful for my (rather simple) needs. I like the fact that it works on Clojure and Clojurescript.
Not quite connected, but please don't use java.net.URL
s in Clojure. In Clojure you want everything to just be inert data and easy to use, but the hash function of java.net.URL
depends on DNS servers and actually makes network calls, so if you have one as a map key it could behave incredibly unexpectedly and very slowly.
always prefer URIs if you can.

I want to be able to send commands to and set the config options of my running (web) app from the command line (without having to enter a REPL). Is the best way to do this to use curl to send JSON POST requests and add a JSON handler? Or is there another way?
If the config options you want to set are rather large then JSON or any other human-writable and machine-readable format that can easily represent your data would be a good fit.
If options are small and plain key-value pairs, then you can get by with query parameters, like in ?a=1&b=2
.
Another way would be to have a separate config file and make the server re-read it when it receives some signal, usually SIGHUP
(although it doesn't have to be a POSIX signal - it can be a request to some URL).
I actually use the latter already. I have hawk watch my config file for changes. I guess sending commands through babashka/curl
is the best option then.
Wait, initially you mentioned CLI but now you mention babashka/curl
. If you gonna write your own tool to communicate to your own server then it doesn't have to be JSON - it can be any serializable format. And if you need to be able to change the config only from the machine where the server is running, then you can do it via programmable REPL - it would simply call the right function with the new config and exit, without you having to type anything.
Agreed. But I might want to run the program on a different server and communicate with it remotely.
Actually, my comment above is not entirely correct - REPL can be accessible from anywhere, not just the same server. But doing so is definitely more dangerous than exposing only the config endpoint. Although the latter is still dangerous by itself, of course, so all the necessary precautions must be taken.
I actually try to use CSRF tokens but I can't get them to work: https://clojurians.slack.com/archives/C053AK3F9/p1643011299188500 when sending POST requests with curl.
I'm trying to call Java's Path.of
class method, which has a single-arity version (takes a URI) and a variable-arity version (takes strings). I know with variable arity you're supposed to use into-array
, but (Path/of (into-array ["path" "parts"]))
errors saying it can't cast java.lang.String
to java.net.URI
, so presumably Clojure is thinking it should call the single-arity form because there's only a single argument on the Clojure side. How do I get around that?
For testing purposes, we will use a dynamic var, bind an atom, and then test some code that will produce side effects. Things like emails, snowplow events, etc. Wondering about what is best to put in the (def ^:dynamic emails-sent nil)
bit of code.
But in the test file, is it better to have some reify’d atom that will warn “you need a binding” type of thing rather than nil? And if so, is the following the best way to accomplish that?
(reify
clojure.lang.IAtom
(swap [_ f] (throw (ex-info "test instance. must add binding" {})))
(swap [_ f a] (throw (ex-info "test instance. must add binding" {})))
(swap [_ f a b] (throw (ex-info "test instance. must add binding" {})))
(swap [_ f a b c] (throw (ex-info "test instance. must add binding" {})))
(compareAndSet [_ old new] (throw (ex-info "test instance. must add binding" {})))
(reset [_ v] (throw (ex-info "test instance. must add binding" {})))
clojure.lang.IAtom2
(swapVals [_ f] (throw (ex-info "test instance. must add binding" {})))
(swapVals [_ f a] (throw (ex-info "test instance. must add binding" {})))
(swapVals [_ f a b] (throw (ex-info "test instance. must add binding" {})))
(swapVals [_ f a b c] (throw (ex-info "test instance. must add binding" {})))
(resetVals [_ v] (throw (ex-info "test instance. must add binding" {}))))
Using declare
would at least give you an exception about the var being unbound. That’s what I normally go with
(declare foo)
(assoc foo :bar true)
;;=> class clojure.lang.Var$Unbound cannot be cast to class clojure.lang.Associative
It's better in the general case because most functions will throw with the unbound var where they might accept nil. But if you care about the error message, I think you'd need to mock out all the methods as in your example.
Hey! I have a question on macros: consider this calls that happen in normal code (using the quil
library):
(q/defsketch sketch-01-001-0002
:title "sketch-01-001-0002"
:settings #(q/smooth 2)
:setup setup
:size [(:width sketch) (:height sketch)]
:key-pressed #(case (q/key-as-keyword)
:s (q/save-frame "art/sketch-01-001-0002-####.tiff")
:r (setup)
nil))
Now, I want to write this macro that wraps it:
(defmacro ssketch [name & instructions]
`(q/defsketch ~name
:title (str ~name)
:settings #(q/smooth 2)
:setup (do [email protected])
:size [(:width sketch) (:height sketch)]
:key-pressed #(case (q/key-as-keyword)
:s (q/save-frame "art/sketch-01-001-0002-####.tiff")
:r (do [email protected])
nil)))
I'll continue with the question in-thread!Now, when I call macroexpand-1
(macroexpand-1 '(ssketch 'sketch-01-001-0002
(q/color-mode :hsb 360 100 100 1.0)
(q/background 200 50 50 1)
(dotimes [_ 50] (draw-circle))))
I get:
(quil.core/defsketch
'sketch-01-001-0002
:title
(clojure.core/str 'sketch-01-001-0002)
:settings
(fn* [] (quil.core/smooth 2))
:setup
(do
(q/color-mode :hsb 360 100 100 1.0)
(q/background 200 50 50 1)
(dotimes [_ 50] (draw-circle)))
:size
[(:width sketch-01-001-0002/sketch) (:height sketch-01-001-0002/sketch)]
:key-pressed
(fn*
[]
(clojure.core/case
(quil.core/key-as-keyword)
:s
(quil.core/save-frame "art/sketch-01-001-0002-####.tiff")
:r
(do
(q/color-mode :hsb 360 100 100 1.0)
(q/background 200 50 50 1)
(dotimes [_ 50] (draw-circle)))
nil)))
And you can see that the first argument of defsketch
, 'skettch-01-001-0002
is quoted. I would like that not to be quoted. How can I do that?
Thank you! But I can't call it like this:
(ssketch sketch-01-001-0002
(q/color-mode :hsb 360 100 100 1.0)
(q/background 200 50 50 1)
(dotimes [_ 50] (draw-circle)))
At a glance I think you need to quote it in your str call
(str ‘~name)
Sorry for wonky quote symbol on phone
I’m confused why you think you can call
(q/defsketch sketch-01-001-0002 ...)
but you must quote the name to your own macro
(ssketch 'sketch-01-001-0002 ...)
`
@U11BV7MTK I bet the str call is throwing with “symbol not found” or something
Ok I solved the problem I was having: quil was expecting a function in the :setup
key, so I should have written :setup (fn [] (do [email protected]))
in:
(defmacro ssketch [name & instructions]
`(q/defsketch ~name
:title (str '~name)
:settings #(q/smooth 2)
:setup (fn [] (do [email protected]))
:size [(:width sketch) (:height sketch)]
:key-pressed #(case (q/key-as-keyword)
:s (q/save-frame "art/sketch-01-001-0002-####.tiff")
:r (do [email protected])
nil)))
And the other error is that I thought I had to quote the symbol I was passing to defmacro
. I worried that there was no meaning in an unquoted version. But I guess defmacro
is taking as parameter the raw syntax, so that's not necessary!Thanks @U017QJZ9M7W and @U11BV7MTK 🙏
you should probably prefer ~(str name)
Although I guess it doesn't much matter here
general question: when I create a namespace and :require
something in it, if the required file evaluated instantly (I suspect this is the case but would like some confirmation and a pointer to where this is discussed)
when a namespace is loaded, any required namespaces that are not yet loaded are loaded at that point
just as a general thing, when a Clojure namespace is loaded, top level forms are read and evaluated top-down just like they would be if you typed them in at the repl
the ns macro expands a series of calls but relevant here, a call to require
which initiates a load if the namespace is not yet loaded (tracked in *loaded-libs*
dynamic var)