This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-07
Channels
- # announcements (1)
- # babashka (77)
- # beginners (219)
- # chlorine-clover (6)
- # cider (52)
- # clj-kondo (14)
- # cljdoc (5)
- # clojure (173)
- # clojure-europe (49)
- # clojure-finland (1)
- # clojure-germany (2)
- # clojure-italy (1)
- # clojure-nl (39)
- # clojure-sweden (4)
- # clojure-uk (51)
- # clojurescript (25)
- # code-reviews (9)
- # conjure (25)
- # data-science (2)
- # figwheel-main (6)
- # fulcro (74)
- # graalvm (1)
- # graphql (11)
- # jobs-discuss (17)
- # keechma (4)
- # lein-figwheel (4)
- # leiningen (1)
- # luminus (10)
- # malli (14)
- # mid-cities-meetup (2)
- # off-topic (28)
- # re-frame (5)
- # reagent (76)
- # reitit (30)
- # ring (7)
- # ring-swagger (1)
- # shadow-cljs (163)
- # spacemacs (11)
- # specter (2)
- # sql (43)
- # tools-deps (13)
- # vim (6)
- # yada (1)
Is there a built-in function to de-namespace a map? If I have #entity{id: 1 name: "hey"} I just want {:id 1 :name "hey"}
Can you just build a map without namespace? Or this namespaced map is already built?
But I don't necessarily know what keys I'll be getting, I just want the non-namespaced versions
Let me check it out
(into {} (map (fn [[k v]] [(keyword (name k)) v])) m)
(keyword (name :my.ns/foo))
-> :foo
(There isn't a built-in function to do it that I know of, but you can do it with a short combination of core functions.)
You can use clojure.walk
to do that as well
https://clojuredocs.org/clojure.walk/postwalk
There is an example
;;example of removing namespaces from all keys in a nested data structure
(def thing {:page/tags [{:tag/category "lslsls"}]})
(postwalk #(if(keyword? %)(keyword (name %)) %) thing)
{:tags [{:category "lslsls"}]}
It is good to be sure that you are not receiving a map with multiple different qualifiers for the same 'base name' of keyword, e.g. using a function like the above if you received {:foo/id 1, :bar/id 2}
would end up with one of those two key/value pairs in the result, not both, and it would not be easily predictable which one it was, unless you wrote explicit code to "pick the winner".
Yes! Or if you need just some keywords, can use a destruct and map only what you want
You’re 1. throwing away information, 2. introducing odd edge-cases (e.g. what @andy.fingerhut said), 3. adding runtime overhead, for what gain?
If you’re trying to hook two already-written systems together, I would find it preferable to manually map keys somewhere. There’s no reason to assume that every key will line up in both systems anyways.
@datran Why do you want to de-namespace the maps? Why not just use them as-is?
Ok, thanks for the questions. The reason I wanted to de-namespace was because the ns qualifier wasn't surviving the network boundary when I was encoding them to json. But @seancorfield and @potetm, you make good points! So I changed my encoding to transit and edn works perfectly out of the box, and now I don't have to worry about hinky de-namespacing functions
Keep in mind though that not-found
and falsy are two different things, i.e. (get {} :a 42)
and (get {:a nil} :a 42)
will give you different results whereas (or (get {:a nil} :a) 42)
and (or (get {} :a) 42)
will give you the same result.
In general, get
is a function, and all Clojure function calls first evaluate the values of their arguments, then call the function. If something is a macro, then it is up to how the macro is defined if/when/how-many-times things are evaluated.
In this particular case, it might have been nice if get/get-in were macros. I struggle to think of a benefit of having not-found
evaluated eagerly. Unless you’re hacking it to side-effect on it.
In most cases I have seen, the not-found
parameter value supplied in the call is a keyword, or a new JVM object created just for the purpose (sometimes called a 'sentinel value'), because that is guaranteed to be different than any other JVM object on the system, and thus never equal to anything that you might possibly find in the collection.
Most things in Clojure are immutable values, so most parameters are not evaluated for the purpose of achieving side effects.
I’m getting something from cache (an atom), or otherwise fetching it and inserting it into the cache (as well as returning it). Semantically, it could be get
, but it makes no sense to do so, of course.
> Most things in Clojure are immutable values, so most parameters are not evaluated for the purpose of achieving side effects.
Indeed, which is why it’s a shame that get
isn’t lazy wrt not-found
.
Does anyone know if there are tools to create docs or readme's from spec
?
Hi. In a proxy
, can I delegate to the super method of the same name?
(defn ws-listener
[_request _response ws-map]
(proxy [WebSocketAdapter] []
(onWebSocketConnect [^Session ws-session]
(.onWebSocketConnect this) ;; <<< This does not work
(when-let [f (:on-connect ws-map)]
(f ws-session)))))
Found the answer by peeking at ring-jetty9-adapter: https://github.com/sunng87/ring-jetty9-adapter/blob/master/src/ring/adapter/jetty9/websocket.clj
Need to use proxy-super
!
In production, however, I get the error Syntax error macroexpanding at (metadata.clj:13:1). remote: Execution error (ExceptionInfo) at tech.jna.base/do-load-library (base.clj:158). remote: Failed to load library
When importing: [libpython-clj.require :refer [require-python]] [tech.v2.datatype :as dtype]
Hey I’m having trouble deploying my application to Docker. I’m suspecting some code I’ve written
(defn load-schema
[]
(-> (io/resource "schema.edn")
slurp
edn/read-string
(util/attach-resolvers (resolver-map))
schema/compile))
Compiling si-be.handler
Syntax error compiling deftype* at (flatland/ordered/set.clj:19:1).
Exception in thread "main" Syntax error compiling deftype* at (flatland/ordered/set.clj:19:1). This is the error I’m getting
FROM clojure
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY project.clj /usr/src/app
RUN mkdir -p /usr/src/app/resources
COPY resources/schema.edn /usr/src/app/resources
RUN lein deps
COPY . /usr/src/app
RUN mv "$(lein with-profile prod uberjar | sed -n 's/^Created \(.*standalone\.jar\)/\1/p')" app-standalone.jar
EXPOSE 8080
CMD java -jar app-standalone.jarDockerfile
#!/bin/sh
docker kill si-be-container
docker rm si-be-container
docker build -t si-be ~/Developer/spesielt-interessert/si-be
docker run -p 8080:8080 --name si-be-container -d si-be```
Deploy script@peder.august what version of flatland ordered are you using?
also - is that the full error output?
@noisesmith It’s a dependency of lacinia (graphql). I’m pretty sure it has something to do with the schema or something? error looks like this
Step 9/11 : RUN mv "$(lein with-profile prod uberjar | sed -n 's/^Created \(.*standalone\.jar\)/\1/p')" app-standalone.jar
---> Running in f18b213a4483
Compiling si-be.handler
Syntax error compiling deftype* at (flatland/ordered/set.clj:19:1).
Exception in thread "main" Syntax error compiling deftype* at (flatland/ordered/set.clj:19:1).
at clojure.lang.Compiler.analyzeSeq(Compiler.java:7114)
... (alot of output)
at clojure.main.main(main.java:37)
Caused by: java.lang.IllegalArgumentException: Must hint overloaded method: toArray
at clojure.lang.Compiler$NewInstanceMethod.parse(Compiler.java:8496)
at clojure.lang.Compiler$NewInstanceExpr.build(Compiler.java:8058)
at clojure.lang.Compiler$NewInstanceExpr$DeftypeParser.parse(Compiler.java:7934)
at clojure.lang.Compiler.analyzeSeq(Compiler.java:7106)
... 165 more
Compilation failed: Subprocess failed
Uberjar aborting because jar failed: Compilation failed: Subprocess failed
mv: cannot stat '': No such file or directory
The command '/bin/sh -c mv "$(lein with-profile prod uberjar | sed -n 's/^Created \(.*standalone\.jar\)/\1/p')" app-standalone.jar' returned a non-zero code: 1
Unable to find image 'si-be:latest' locally
But it works when I do
lein run
But I’m just using the dockerimage of clojure?
right, your local version of java is different from what is used in the docker image
hmmm, ok, how do I check the java version in docker? and how do I change it?
thank you btw
you should check to make sure your dependencies are up to date, newer versions of java mad some changes to reflection which newer versions of clojure needed updating to handle
I got a reply from someone saying to change my lacinia version, since it had some issues
It worked changing my version of lacinia
This looks like a documented issue with flatland.ordered when upgrading to JDK 11: https://www.deps.co/blog/how-to-upgrade-clojure-projects-to-use-java-11/
yeah, this is a known issue (I think actually introduced in Java 10) where compiled code against java.util.Collection is now ambiguous due to the introduction of a new default method. Java's typing is sufficient to avoid the ambiguity, but requires a type hint in Clojure to do so. (non-AOT'ed code won't see this issue)
I've always thought that timbre logs exception's stacktrace when the exception is passed as the first arg - however, it's not working now:
(try (throw (RuntimeException. "boom"))
(catch Exception e #_(.printStackTrace e) (log/error e "ah")))
Anyone knows what's going on?
(the .printStackTrace
thing works properly)Hi all, hoping to get some help with Java interop, trying to make a proper HashMap:
// Java Example found
Map<String, Object> args = new HashMap<>();
args.put("pid", "current");
args.put("profileName", "Time Profiler");
args.put("timeout", 6000*1000);
driver.executeScript("mobile: startPerfRecord", args);
;; What I have so far
(.executeScript driver
"mobile: deepLink"
(doto (java.util.HashMap. )
(.put "url" "")
(.put "package" "org.telegram.messenger")))
Clojure Error:
Unhandled java.lang.ClassCastException
Cannot cast java.util.HashMap to [Ljava.lang.Object;
I suspect I'm not building the Map<String, Object> args = new HashMap<>();
correctly. My java skills aren't great, so not exactly sure what that's doing and haven't found any similar examples in Clojure. Do I need to add type hinting somewhere?@slack1620 clojure maps are already implement java.util.Map
(.executeScript driver
"mobile:deepLink"
{:url ""
:package "org.telegram.messenger"})
Unhandled java.lang.ClassCastException
Cannot cast clojure.lang.PersistentArrayMap to [Ljava.lang.Object;
can you link to the Java doc of the method you're trying to call upon the driver
class?
definition
public void executeCommand (final String command, final Map <String, Object> args) {
this.driver.executeScript (command, args);
}
dammit @seancorfield i'm trying to use science
ok, here's the docs for that methods: https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/remote/RemoteWebDriver.html#executeScript-java.lang.String-java.lang.Object...- It's inherited by this https://javadoc.io/doc/io.appium/java-client/latest/io/appium/java_client/AppiumDriver.html
public java.lang.Object executeScript(java.lang.String script,
java.lang.Object... args)
so the X...
varargs in Java translates at the calling convention level to an array of X
https://clojure.org/reference/java_interop#_arrays I don't see anything there ^ about varargs specifically
@slack1620 would certainly be worth a pull request here https://github.com/clojure/clojure-site/blob/master/content/reference/java_interop.adoc
Still trying to follow.. So we only have one arg for our java.lang.Object... args
. Is the hashmap Object the item for the array?
(into-array Object {:url ""
:package "org.telegram.messenger"})
I think you suggest the strings.
(into-array Object ["url" ""
"package" "org.telegram.messenger"])
(.executeScript driver "command" (into-array Object ["url" ""
"package" "org.telegram.messenger"]))
I got it to work. Turns out it does need an array of HashMap
since it will be converted to json object. Thanks for the help. Very subtle with the java.lang.Object... args
(.executeScript driver
"mobile:deepLink"
(object-array [(doto (java.util.HashMap.)
(.put "url" "")
(.put "package" "org.telegram.messenger"))]))
you still shouldn't don't need to use interop there - {"url" "
should work
clojure hash-maps are Map instances as ghadi mentioned
I see, yes the (doto java.util.HashMap. )
is not needed but the (object-array [{"url "..."}])
is still needed since it's definition has variadic arguments.
right
Hi guys! I'm parsing command line arguments using https://github.com/clojure/tools.cli. It seems whenever it finds a comma inside a parameter value it splits it, and put in a separate arguments key. Any way to avoid this?
lein run --addressComplement "Cambridge, MA"
(println parse-opts args cli-options))
{:options {:addressComplement "Cambridge,}, :arguments [MA"], :summary...}
thanks!
the weird thing is if I put "Cambridge,MA"
with no spaces it works fine
but "Cambridge, MA"
causes the unexpected behavior
Maybe it's the spaces that are causing the split?
It seems so! I'm looking for a way to avoid the split
it's weird that it also captures the ""
yeah 😕
if you use prn
rather than println
you'll get the kind of printing the repl would do instead of the default which does weird things to strings
It seems Clojure tools cli is not aware of double quotes either.
I have a server with long standing TCP client connections, and really like being able to update functions in the REPL without having to reconnect a test client. I’ve found you can pass a var to a callback which allows that var to be set to something else via the REPL and things work great. That said, making every callback and var and then having to call var-get
seems like a pain. Is there a better solution here?
you can just call vars
you don't need var-get for that
user=> (map #'str [:a :b :c])
(":a" ":b" ":c")
vars implement IFn, and when called just call the thing they hold
huh, I had no idea. I thought I had tried that yesterday but apparently I didn’t do it right.
I guess that makes things easy then, I just have to remember to pass vars for all callbacks.
It seems Clojure tools cli is not aware of double quotes either.
run --addressComplement "MyAddress"
(prn (parse-opts args cli-options))
{:options {:addressComplement "\"MyAddress\""}
But quotes are important for command line arguments that include spaces on it
I think the issue is you aren't seeing the grouping / parsing that a shell would do - as if you were executing this without sh
or not, I dunno, but basically, you will not get the results you would get just by running your code if you run your code from lein run
you might try something like
java -cp `lein classpath` clojure.main -m your.main your arguments here
Good hypothesis, I gave it a try here
however it seems the arguments arrive correctly
(defn -main [& args]
(println args)
(--addressComplement "My, Address")
with prn
("--addressComplement" "\"My," "Address\"")
so the issue seems with clojure tools CLI
{:options {:addressComplement "\"My,"}, :arguments ["Address\""]
the println is hiding the error, prn exposes it
are you using a shell that doesn't use " for grouping?
("--addressComplement" "\"My," "Address\"")
seems right to me, isnt it?
lein run is like a hack, it is a covience thing that got added, but it is full of corner cases is not a good way to actual run your clojure programs
sorry, I missed it
whats the problem with that?
I see
it split into two string
gotcha
Yeah, bye bye lein run
thanks!
~ % clojure -e '(prn *command-line-args*) (System/exit 0)' -- --addressComplement "My, Address"
("--addressComplement" "My, Address")
~ %
from the shell it works nicely
thanks again @noisesmith and @hiredman
@ricardo.ekm just a hunch - what if you used lein trampoline run
instead of lein run
- this starts your process in the same jvm instead of forwarding args to the other vm
I suspect the re-invocation of the the next vm is where the args get mangled
it yields the same problem 😕
Just use the clojure
CLI instead 🙂
BTW how do I set an option as required in clojure tools cli?
the docs talk about it, but I haven't figured out how to do it (I think an example is missing)
Instead of throwing errors, parse-opts collects error messages into a vector and returns them to the caller. Unknown options, missing required arguments, validation errors, and exceptions thrown during :parse-fn are all added to the errors vector.
By default, the error message when a required argument is omitted is:
Missing required argument for ...
Hmmm, how do I set an argument as required?
alternatively, just having a long form of "--port PORT" specifies that it requires an argument
thanks!
Hmmm, how do I set an argument as required?