This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-02-19
Channels
- # babashka (7)
- # beginners (29)
- # biff (10)
- # cherry (6)
- # cider (23)
- # clj-kondo (9)
- # clojure (54)
- # clojure-europe (27)
- # clojure-nl (2)
- # clojure-norway (10)
- # clojure-uk (5)
- # datomic (14)
- # deps-new (1)
- # events (7)
- # figwheel-main (3)
- # hyperfiddle (9)
- # lsp (4)
- # malli (12)
- # off-topic (8)
- # other-languages (2)
- # releases (3)
- # shadow-cljs (104)
- # specter (1)
- # tools-deps (12)
I'd like to use the function browse-url
from clojure.java.browse
to browse a file on my local file system.
How can I convert a file name to a url which will work on *nix and also on windows?
Normally the file name has been created by a call to
.
Here is some similar code in Scala, but it seems to use a different java library.
for {path_to_file <- str_to_png(gv, title)}
locally {
import java.awt.Desktop
import java.net.URI
if (Desktop.isDesktopSupported) {
// See:
Desktop.getDesktop.browse(java.nio.file.Paths.get(path_to_file).toUri)
}
}
If I simply try to use (browse-url "file:///path/name/to/file.svg")
it tries to start an application called LaTeXiT
rather than opening in the browser
when I look at the code for browse-url
I see it calls the function open-url-in-browser
whose code is the following, which looks a lot like the Scala code I posted above.
(defn- open-url-in-browser
"Opens url (a string) in the default system web browser. May not
work on all platforms. Returns url on success, nil if not
supported."
[url]
(try
(when (clojure.lang.Reflector/invokeStaticMethod "java.awt.Desktop"
"isDesktopSupported" (to-array nil))
(-> (clojure.lang.Reflector/invokeStaticMethod "java.awt.Desktop"
"getDesktop" (to-array nil))
(.browse (URI. url)))
url)
(catch ClassNotFoundException e
nil)))
maybe I should call open-url-in-browser
directly rather than going through browse-url
?
when I try to do that, I see that the function is private
1. Unhandled java.lang.IllegalAccessError
open-url-in-browser is not public
core.clj: 4250 clojure.core/refer
core.clj: 4218 clojure.core/refer
RestFn.java: 139 clojure.lang.RestFn/applyTo
core.clj: 669 clojure.core/apply
browse
uses the underlying platform to 'launch' the path provided. I think the result is that, at this point in the timeline of OSes, that'll generally open the path in whatever application it's associated with.
you can call "private" function by using its fully qualified name: (#'clojure.java.browse/open-url-in-browser url)
How would you convert a hex string to its decimal representation? "0x2d3f4304d303d49fe26a"
-> 213673465822491589993066
https://docs.oracle.com/javase/8/docs/api/java/lang/Long.html#parseLong-java.lang.String-int-
https://docs.oracle.com/javase/8/docs/api/java/math/BigInteger.html#BigInteger-java.lang.String-int-
(BigInteger. "2d3f4304d303d49fe26a" 16)) ; 213673465822491589993066
Thanks, @U0NCTKEV8. Is that about as good as I can get? I have to strip out the leading 0x
from the string myself?It depends, as good as for what? The leading 0x indicates what follows is a hex number, and which is useful for people and general parsers, but if you already know it is a hex number it is not needed
The general constructor from a string that doesn't take a radix may work with the 0x, but it will also parse non-hex numbers which you may not want
There are no raw strings in clojure. You can put a newline in a regular string tho, if that’s what you want.
Is there a better construct for conditionally assoc'ing values into a map?
(cond-> {}
true (assoc :foo 1)
false (assoc :bar 2)
true (assoc :baz 3)))
How about this?
(into {}
(->> [[true [:foo 1]]
[false [:bar 2]]
[true [:baz 3]]]
(filter first)
(map second)))
For me, there's no better construct than yours @UPWHQK562. IMO @U0552GV2X32’s approach is less clear, but that may depend on your familiarity with cond->
. If you want to create a macro to reduce the repetition of assoc
you could do something like this:
(defmacro assoc-some-> [expr & clauses]
(let [steps (mapcat (fn [[t k v]]
`(~t (assoc ~k ~v)))
(partition 3 clauses))]
`(cond-> ~expr ~@steps)))
(assoc-some-> {}
true :foo 1
false :bar 2
true :baz 3)
;; => {:foo 1, :baz 3}
but I'd recommend against it. It breaks the first rule of macro club: don't write macros. It's just more syntax for everyone reading your code to know, and it's not worth saving the space. Maybe fun to play with though 🙂I'd agree that mine is less readable for explicit lists, but it will handle the case where the list is unknown before runtime, if that's what you're working with. I should have been clearer about that. E.g like this
(into {}
(->> some-list
(filter first)
(map second)))
Ah yup, fair point. I'd probably transduce those intermediate colls away, but agree the approach is good for runtime:
(into {} (keep (fn [[b kv]] (when b kv))) some-list)
Thanks for the replies! I'm aware of the transducer options but I think cond->
stands out as the easiest (in terms of reading) solution.
Just as alternative, I often use merge
, but I think cond->
is probably still preferable:
(merge
{:default "options"}
(when foo?
{:foo 42})
(when bar?
{:bar 43}))
I like that option too. That's quite legible, but I haven't seen it used anywhere so the familiarity of cond->
tips the scales IMO.
assoc
is just a function, so I copied and modified its source as follows, to preserve the semantics of assoc
. It appears to work.
(defn assoc-when
([m pred k v]
(if pred (clojure.lang.RT/assoc m k v) m))
([m pred k v & kvs]
(let [ret (if pred (clojure.lang.RT/assoc m k v) m)]
(if kvs
(if (nnext kvs)
(recur ret (first kvs) (second kvs) (nth kvs 2) (nthnext kvs 3))
(throw (IllegalArgumentException.
"assoc-when expects modulo-three number of arguments after map/vector, found another number")))
ret))))
user=> (assoc-when {} true :foo 1)
{:foo 1}
user=> (assoc-when {} false :foo 1)
{}
user=> (assoc-when {} false :foo 1 true :bar)
Execution error (IllegalArgumentException) at user/assoc-when (REPL:1).
assoc-when expects modulo-three number of arguments after map/vector, found another number
user=> (assoc-when {} false :foo 1 true :bar 2)
{:bar 2}
user=> (assoc-when {} true :foo 1 false :bar 2 true :baz 3)
{:foo 1, :baz 3}
user=> (assoc-when {} true :foo 1 true :bar 2 true :baz 3)
{:foo 1, :bar 2, :baz 3}
user=> (assoc-when [] true 0 1 true 1 2 true 2 3)
[1 2 3]
Thank you for adding on, @UK0810AQ2 and @U051MHSEK.
I like that assoc-when
fn. My main purpose here is to conditionally build up a map. I suppose with this fn I could drop the cond->
(which, although not very esoteric, is still somewhat less familiar) and replace it with a simple ->
.
Okay, based on the shape of your code, I assumed you were going for a general "assoc-when" concept. It seems like you need to consider one set of pred, key, value at a time? In which case, this will suffice.
(defn maybe-assoc
[m [pred k v]]
(if pred (assoc m k v) m))
And now you can...
(reduce maybe-assoc {} [[true :foo 1], [false :bar 2], ...])