Is there a way to pretty print EDN with custom tags included, without libraries like fipp? I'm using flatland ordered maps and I want the #ordered/map tags to be included but when I use pprint/pprint it doesn't print the tags
maybe print with normal EDN and then re-format it with e.g. cljfmt?
Yeah maybe. I was just wondering if there's anythign built-in.
You can certainly use the built-in pprint in a way that prints ordered maps with the printer supplied by the flatland library and prints everything else in a pretty way:
(pp/write {:some {:nested [:map (ordered-map :a 1 :b 2 :c 3)]}}
:dispatch (fn [obj]
(if (instance? flatland.ordered.map.OrderedMap obj)
(print-method obj *out*)
(pp/simple-dispatch obj))))
Or, if you want to make the change global, just (defmethod pp/simple-dispatch ...).
However, if you want to also pretty-print flatland maps, you have to do more work.I just realized that I'm not interested in the tags at all š I just want to get the keys in order and edamame can help with that.
My use-case: I have some large JSON files that are annoying to edit. I want to parse the JSON files and convert them to EDN files. Then I'll edit the EDN files and convert them back to JSON and I want to preserve the order all the time. So I can parse JSON with clj-yaml, write it to EDN file with pprint, then I can parse the EDN file with https://github.com/borkdude/edamame?tab=readme-ov-file#preserve-order-of-map-and-set-keys and write back to JSON file.
I just commented about that clj-YAML trick in an issue in cheshire. Weāre you reading that or sheer coincidence?
sheer coincidence š
Iām trying to follow the directions of chatgpt, and I supsect itās leading me in the wrong direction.
I would like to use clj from the command line to exec code in a file in the same directory.
I have a deps.edn file and a file name dteqt.clj (which contains a ns definition for dteqt) and also contains a definition a function -main.
When I call the following command line:
clj -M -cp /Users/jnewton/Documents/courses -m dteqt
I get the error
Execution error (FileNotFoundException) at java.io.FileInputStream/open0 (FileInputStream.java:-2).
-cp (No such file or directory)
has chatgpt lead me astray?man clj give the following:
-Scp CP
Do NOT compute or cache classpath, use this one instead@gunnar, i think iād like to add . to the class path, not replace the classpath with .
But you don't need and should not use a custom CLI-specified classpath if you have deps.edn.
That file should already be specifying everything you need.
If you clj -h | grep main, you'll see that you can indeed use the -m option to specify the namespace. But the classpath will come from whatever is in deps.edn.
If you need a different classpath, just put it under an alias and specify that alias under -M. You can also move the whole -m dteqt thing under that alias, so in the end it can be something like clj -M:dteqt.
Check out https://clojure.org/reference/clojure_cli#use_main, especially the last paragraph.
I donāt really understand. is this correct? the -m says to call -main, right? what does -M do?
-M[aliases] Use concatenated aliases to modify classpath or supply main opts
I saw that, but I donāt know what āconcatenated aliasesā are
-M allows using aliases from deps.edn. It can be used without aliases at all, in which case it can be omitted. But such usage is considered deprecated so even if you don't need any aliases, -m and some other flags ask you to also use -M for consistency.
"Concatenated aliases" are just a string of alias names, concatenated.
So if you have aliases :a, :b, and :c, the "concatenated aliases" in this case means :a:b:c.
Some examples in the docs are here: https://clojure.org/reference/clojure_cli#options
ok, whatās an alias?
for me an alias is a short form of another longer command.
It's kinda like that, just structured and with abilities to override things: https://clojure.org/reference/clojure_cli#aliases
so when I take out the -cp foolishness. and I use the command line
clj -M -m dteqt a b c
Hereās the error which chatgpt was trying to fix.
Execution error (FileNotFoundException) at clojure.main/main (main.java:40).
Could not locate dteqt__init.class, dteqt.clj or dteqt.cljc on classpath.
Full report at:
/var/folders/c1/sqxjhjm15gdcyr49z7r4k1mr0000gn/T/clojure-1362372849798786874.edn
make: *** [all] Error 1For the vast majority of cases, deps.edn and clj are enough, when used properly.
Most of the time, there's no need for make or shell scripts, precisely because of aliases.
>
Could not locate dteqt__init.class, dteqt.clj or dteqt.cljc on classpath.
>
This is pretty self-explanatory. If you have dteqt.clj or something else mentioned in the error, it's not on the classpath. If you put it in ., I'd definitely suggest moving it under some nested directory and adding that to deps.edn under the :paths key (by default it's ["src" "classes"], IIRC).And if you still want for it to be in ., just specify :extra-paths ["."] under some alias. Or :replace-paths (same as just :paths).
if I remove the -main function and just top-level its content, then I can run the script as follows.
clj -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.11.1"} org.clojure/data.json {:mvn/version "2.4.0"}}}' -M dteqt.clj
However, it doesnāt seem to work with any of the advice from above nor from chatgpt. I think thereās something subtle wrong. but at least I can proceed with this ugly workaround ⦠it is being called from a Makefile anyway.But what doesn't work? What are the symptoms?
My workaround is just to put a top-level call
(apply -main *command-line-args*)
in the file, and then call as Iāve mentioned above.
However, every attempt to use the -m flag gives me the familiar error. despite efforts to add :extra-paths. maybe its my java version or something bizzzzare like that.
Execution error (FileNotFoundException) at clojure.main/main (main.java:40).
Could not locate dteqt__init.class, dteqt.clj or dteqt.cljc on classpath.Should be nothing bizarre. What's in your deps.edn (the relevant parts, at least) and how exactly do you try to run the function from the CLI when it fails with that message?
Here is the content of the deps.edn file.
{:deps {org.clojure/clojure {:mvn/version "1.11.1"}
org.clojure/data.json {:mvn/version "2.4.0"}}
}I tried to add the extra paths like this
{:deps {org.clojure/clojure {:mvn/version "1.11.1"}
org.clojure/data.json {:mvn/version "2.4.0"}}
:extra-paths ["."]
}:extra-paths is only for aliases, not for the top-level...
$ mkdir clj-cli-test
$ cd clj-cli-test
$ echo '{:aliases {:dteqt {:extra-paths ["."] :main-opts ["-m" "dteqt"]}}}' > deps.edn
$ echo '(ns dteqt) (defn -main [& args] (println "main called with" args))' > dteqt.clj
$ clj -M:dteqt
main called with nil
$ clj -M:dteqt hello there
main called with (hello there)I think that this thread has shown that the advice you've gotten from chatgpt has been unhelpful at many different points. I do not recommend using the tool for learning new things, as it often makes small errors that can hinder understanding. Generally, chatgpt is more useful on subjects that you already know well because you can spot the errors. Instead, I recommend looking through the guides on http://clojure.org, and asking questions here or in #beginners
@suskeyhose i didnāt imagine that calling a script from the command-line should be so fraught with pitfalls.
It shouldn't be, and it isn't really. ChatGPT simply shits the bed inexcusably here, for some reason.
as an aside. I am somewhat dyslexic ⦠iām pretty sure that at some point i probably typed detqt rather than dteqt. apparently if you give clj an alias that does not exist, it silently ignores and does something different. for example. clj -M:detqt seems to go into interactive clojure repl. while clj -Mdteqt does what I want.
Note that : should still be there, so it should be -M:dteqt.
Regarding a missing alias - no idea why it was done that way, perhaps it's just the default behavior of how maps work when you look up a key that doesn't exist. No error is thrown.
But maybe there's a deeper meaning and a deliberate decision behind not throwing anything.
It possible your issue is because classpath are really gnarly. You have to explicitly have a path to all subdirectory or there are some weird glob patterns you can use when you manually provide it using the command argument.