This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-06-17
Channels
- # announcements (4)
- # babashka (22)
- # beginners (50)
- # biff (2)
- # calva (4)
- # cider (18)
- # clj-kondo (12)
- # cljs-dev (3)
- # clojars (2)
- # clojure (66)
- # clojure-austin (1)
- # clojure-belgium (11)
- # clojure-europe (90)
- # clojure-hungary (5)
- # clojure-norway (6)
- # clojure-switzerland (1)
- # clojure-uk (4)
- # clojurescript (19)
- # datascript (2)
- # datomic (41)
- # fulcro (4)
- # gratitude (2)
- # helix (20)
- # jackdaw (2)
- # jobs (9)
- # jobs-discuss (38)
- # kaocha (1)
- # minecraft (8)
- # off-topic (11)
- # polylith (21)
- # rdf (2)
- # remote-jobs (1)
- # sci (1)
- # shadow-cljs (12)
- # specter (7)
- # tools-deps (16)
how can I tell clj
to load a specific namespace by default?
I want to do something like clj -?:api
, which should pop me into a REPL where the src/api.clj file has been loaded
Loading is possible, changing into that namespace is not. To load namespace, Create a file that defines a user namespace, e.g. dev/user.clj and add the API namespace as a require. As long as the REPL process is started with dev directory on the class path, API namespace will be loaded when REPL starts. This will not put the REPL into the api namespace (only Leiningen does that) More details here https://practical.li/clojure/clojure-cli/projects/configure-repl-startup.html
I have a situation where the presence of :a
in a map m
needs to be handled one way, but if there's a :b
then that needs to be handled another way.
I came up with:
(condp #(%1 %2) m
:a :>> handle-a
:b :>> handle-b)
I like this, except for the #(%1 %2)
which isn't very readable. I was hoping to just use get
, but the arguments are in the wrong order for that to work. Of course I can use (fn [k m] (k m))
, but that is overly verbose.
Any ideas?I would keep it simple
(cond
(contains? m :a)
(handle-a m)
(contains? m :b)
(handle-b m))
Using cond
it would actually look like this:
(cond
(contains? m :a)
(handle-a (m :a))
(contains? m :b)
(handle-b (m :b)))
I don't like the repeated map accessing there.you can do something like this, but it all seems very premature optimization
(if-let [a (:a m)]
(handle-a a)
(if-let [b (:b m)]
(handle-b b)))
Oh no performance is not the issue. Neither is the typing, unless the amount of clauses would increase a lot.
I don't dislike the cond
solution necessarily, it's just that I feel the condp
was almost perfect (if get
could be used) and hoped someone had some way of flipping the arguments or something 🙂
Thanks though!
Btw contains?
is better because that allows you to detect the case when :a
is in the map but is nil
whereas you won't notice it when using get
(unless you use the default value arg)
Yes, that's a good point
Alternatively you can use find
+`val`
(if-let [ma (find m :a)]
(handle-a (val ma))
(if-let [mb (find m :b)]
(handle-b (val mb))))
(with-open
[in (io/input-stream (str "/home/benj/repos/clojure/currency-data-to-s3/" "test.csv"))
boas (java.io.ByteArrayOutputStream.)
gos (java.util.zip.GZIPOutputStream. boas)]
(io/copy in gos)
(spit "lul.gz" boas)
)
jo what am I doing wrong? My goal is to read a text file, gzip in memory and upload thatComparing the version with and without boas it seems only the first dozen bytes get written
(with-open [in (io/input-stream "/tmp/xx.csv")
out (io/output-stream "/tmp/lul.gz")
gos (java.util.zip.GZIPOutputStream. out)]
(io/copy in gos))
(with-open [in (io/input-stream "/tmp/xx.csv")
boas (java.io.ByteArrayOutputStream.)
gos (java.util.zip.GZIPOutputStream. boas)]
(io/copy in gos)
(spit "/tmp/lul.gz" boas))
Seems there's some flushing that needs to happen, if you close the gzipoutputstream you get more data, but somehow it's not valid
(let [boas (java.io.ByteArrayOutputStream.)]
(with-open [in (io/input-stream "/tmp/xx.csv")
gos (java.util.zip.GZIPOutputStream. boas)]
(io/copy in gos))
(spit "/tmp/lul.gz" (.toString boas)))
Does it work if you try translating this example directly to Clojure? https://www.geeksforgeeks.org/gzipoutputstream-class-in-java/
(let [file "/tmp/xx.csv"
fis (io/input-stream file)
gzip-file "/tmp/lul.gz"
fos (io/output-stream gzip-file)
gzip-out (java.util.zip.GZIPOutputStream. fos)]
(io/copy fis gzip-out)
(.close fis)
(.close fos)
(.close gzip-out)
)
hm, still something is wrong.
This version writes 10bytes(with-open [in (io/input-stream "/tmp/xx.csv")
out (io/output-stream "/tmp/lul.gz")
gos (java.util.zip.GZIPOutputStream. out)]
(io/copy in gos))
this is the only version I know that worksGZipOutputStream needs "to do some work" to properly wrap the resulting gzip file, which is done only when the stream is closed (`.close` is called). So the "gos" needs to be closed before you can write the generated content to a file somewhere. This worked for me
(with-open [baos (java.io.ByteArrayOutputStream.)]
(with-open
[in (io/input-stream (str "/home/benj/repos/clojure/currency-data-to-s3/" "test.csv"))
gos (java.util.zip.GZIPOutputStream. baos)]
(io/copy in gos)
)
(spit "lul.gz" (.toByteArray baos))
)
@U03KDUXD9PB do you still have the version that worked?
(with-open [baos (java.io.ByteArrayOutputStream.)]
(with-open
[in (io/input-stream (.getBytes "fo"))
gos (java.util.zip.GZIPOutputStream. baos)]
(io/copy in gos))
(spit "/tmp/lul.gz" (.toByteArray baos)))
tried this and it doesn't work on my end@UK0810AQ2 yea that works for when writing a file, but I initially wanted to upload the gzip bytes directly
@U02CV2P4J6S
The problem is with spit
. Depending on the bytes generated, it believes the data is over when there are still bytes remaining on the stream.
This worked with several files of mine:
(with-open [baos (java.io.ByteArrayOutputStream.)
fos (io/output-stream "/home/boschi/temp/lul.gz")]
(with-open
[in (io/input-stream "/home/boschi/temp/template.html")
gos (java.util.zip.GZIPOutputStream. baos)]
(io/copy in gos))
(io/copy (java.io.ByteArrayInputStream. (.toByteArray baos))
fos))
just fixing a mistake in my code: there is no need to create an inputstream with the byte array.... just write the byte-array to the outputstream....
(with-open [baos (java.io.ByteArrayOutputStream.)
fos (io/output-stream "/home/boschi/temp/lul.gz")]
(with-open
[in (io/input-stream "/home/boschi/temp/template.html")
gos (java.util.zip.GZIPOutputStream. baos)]
(io/copy in gos))
(.write fos (.toByteArray baos)))
Oh well, passing or
as a param for a function seems not to work 🙈 (which is I think a very obvious thing one would do from time to time)
Can't take value of a macro: #'clojure.core/or
why do you want to pass it as an argument?
(update-in m [...] or default-value)
to make sure a value is set in a map without additional ifthe important difference is that or
does not evaluate all it's arguments (conditional evaluation). This is one of the reasons to have a macro.
How would you do (update m :k #(or "value I want to have set, if :k has no value"))
with fnil
?
(update {:k 10} :k (fnil (constantly "there was a k") "default"))
{:k "there was a k"}
if you can catch (and handle) an exceptional event. for instance: retrying, logging, passing an event along in a more useful way such as catching and returning an http response with the proper error code
in general, it's best to minimize explicit try/catch to high level code and not try to do this at 10 places in the stack
may I suggest the new parse-double
function added to clojure.core in 1.11?
it will return null
in the case of an invalid double string, so probably you'll want (or (parse-double n) -1)
or maybe you want -1.0
- seems a little weird to parse to either a double or long -1