pr-str also prints out trace messages - clojure

I am using pr-str to print EDN to string and communicate with the client side. Encountered very interesting behavior where pr-str also outputs println or clojure.tools.trace/trace messages mixed into the EDN string representation. This is the kind of strings pr-str outputs:
(TRACE from-ds {:key "asdasf", :weight 0, :tag "1"} ; trace message
{:key "asdasf", :weight 0, :tag "1"}) ; the actual edn that should be the sole output
I can't seem to reproduce this in REPL.
Why is this happening? How to work around it?

pr-str uses with-out-str, which captures any print output that happens while inside its block and turns it into a string which is returned.
with-out-str creates a thread-local binding of *out*. Because of this, the only way that you could be getting log output inside your output string is if the code inside your pr-str call was logging. This could be fixed by binding the value outside pr-str call and then calling pr-str on that value.
eg.
(let [the-value (generate-some-value) ; this prints something
value-string (pr-str the-value)] ; this doesn't have trace output
...)

Related

clojure - trouble destructing map inside macro

I'm a newbie in clojure, so please bear with me.
Writing a macro as so:
`(let [query# (:query-params ~'+compojure-api-request+)
options# (select-keys query# [:sort-by :from :to])])
First line of the let block destructures a query-params from http request - which produces this structure:
{sort-by billing-account/name, from 0, to 10, payment-due , payment-method , search }
And the trouble is with the second line - it returns an empty map when I use select-keys, however when I say for example (first query#) - the output looks like this: [sort-by billing-account/name]
Could anyone please explain why the select-keys does not work?
P.S. Tried (get query# :from) & (:from query#) - no luck there as well.
UPD
Keys were strings, not keywords - therefore using strings as keys works just fine.
By the way, you can also destructure string keys with :strs:
(let [m {"sort-by" "billing-account/name",
"from" "0",
"to" "10",
"payment-due" nil,
"payment-method", "search"}
{:strs [sort-by from to payment-due payment-method]} m]
(println sort-by from to payment-due payment-method))
;;=> billing-account/name 0 10 nil search
See https://clojure.org/guides/destructuring for a full description of the destructuring syntax.
I think you are confused by the differences between keywords, symbols and strings. In your comment you say that they're symbols, but in your edit you say they're strings.
You should read up on the difference:
in Clojure, why have Strings, Keywords AND Symbols?
Why does Clojure have "keywords" in addition to "symbols"?
The idiomatic thing is to usually prefer using keywords as map keys, although stuff that comes from the internet (json, http headers, etc) is sometimes all strings.
To answer your question directly, the keys passed to select-keys need to be equal (using the = function) to the ones in the map, so in this case they need to be the same type.
;; For example
(select-keys {'foo 1 'bar 2} ['foo]) ;=> {foo 1}
(select-keys {:foo 1 :bar 2} [:foo]) ;=> {:foo 1}
(select-keys {"foo" 1 "bar" 2} ["foo"]) ;=> {"foo" 1}
Also I question the need for this to be a macro, is there a reason that a plain function won't work?

Clojure: how to know if a function (test-vars) printed something to *out*?

I am looking for a way to determine if a function printed (using println or anything similar).
What I am trying to determine is if test-vars printed something or not.
The issue with this function is that it doesn't return anything, but only print things when errors got issues, but I want to know if it succeeded or not and the only way I see to know it is to check if it printed something or not.
Even better would be a way to "intercept" what is going to out and to put it in a variable.
After the comments from #lee and #leetwinski I tried the following:
(deftest test-1
(testing
(is (= 1 2))))
Then I tried to run that test using:
(let [printed (with-out-str (test-vars [#'test-1]))]
(print (str "Printed size: " (count printed))))
But here is what I got:
FAIL in (test-1) (form-init505699766276988020.clj:103)
expected: (= 1 2)
actual: (not (= 1 2))
Printed size: 0
nil
So, what test-vars outputs has been outputted anyway. Then printed was empty.
in addition to #Lee's answer: in general you could just rebind *out* to any other writer you want:
temporary binding:
user> (binding [*out* (java.io.StringWriter.)]
(println 101)
(str *out*))
"101\n"
is just an analogue to with-out-str
thread-local binding:
user> (set! *out* (java.io.StringWriter.))
#object[java.io.StringWriter 0x575e6773 ""]
user> (println 123)
nil
user> (str *out*)
"123\n"
here we rebind the *out*, for the current thread (and for all the threads, spawned from it, AFAIK).
You can use with-out-str which intercepts printed values and collects them into a string:
(let [printed (with-out-str (test-vars))]
...)

What's the purpose of the :printed keyword in this Clojure doto macro example?

I've been looking at this Clojure doto macro example from ClojureDocs, and I can't figure out what the purpose of the :printed keyword in the final println.
When I enter the example in a REPL, it prints out the HashMap as I would expect, just with a :printed displayed after the HashMap:
user=> (doto (java.util.HashMap.) (.put "a" 1) (.put "b" 2) (println :printed))
#<HashMap {b=2, a=1}> :printed
{"b" 2, "a" 1}
I figured println needed a placeholder so that it knows to wait for something coming from the doto macro. So I tried seeing what I'd get if I omitted :printed:
user=> (doto (java.util.HashMap.) (.put "a" 1) (.put "b" 2) (println))
#<HashMap {b=2, a=1}>
{"b" 2, "a" 1}
This one prints the same thing, but makes the HashMap without a :printed alongside it. Given this result, shouldn't the doto example give something like this:
#<HashMap {b=2, a=1}>
{"b" 2, "a" 1} :printed
What is the :printed keyword doing?
:printed simply adds " :printed" to the string printed by println.
It does not affect the hash-map.
(println "Bingo" :printed)
=> Bingo :printed

Printing and reading lists from a file in Clojure

I have a Clojure data structure of the form:
{:foo '("bar" "blat")}
and have tried writing them to a file using the various pr/prn/print. However, each time the structure is written as
{:foo ("bar" "blat")}
then when I try to read in it using load-file, I get an error such as:
java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IF
n (build-state.clj:79)
presumably as the list is being evaluated as a function call when it is read. Is there any way to write the structure out with the lists in their quoted form?
thanks,
Nick
The inverse of printing is usually reading, not loading.
user> (read-string "{:foo (\"bar\" \"blat\")}")
{:foo ("bar" "blat")}
If you really need to print loadable code, you need to quote it twice.
user> (pr-str '{:foo '("bar" "blat")})
"{:foo (quote (\"bar\" \"blat\"))}"
user> (load-string (pr-str '{:foo '("bar" "blat")}))
{:foo ("bar" "blat")}

Clojure: slurping structs from file fails with string attributes containing whitespaces

I have just started playing with Clojure and the first thing I thought I'd try is storing and retrieving a list of structs, like in Suart Halloway's example here.
My spit/slurp of a hash of structs works fine with, if I use struct instances without spaces in the attribute strings like the following:
(struct customer "Apple" "InfiniteLoop")
But if I use this:
(struct customer "Apple" "Infinite Loop 1")
I get an error:
Exception in thread "main" clojure.lang.LispReader$ReaderException: java.lang.ArrayIndexOutOfBoundsException: 7 (test-storing.clj:19)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2719)
at clojure.lang.Compiler$DefExpr.eval(Compiler.java:298)
at clojure.lang.Compiler.eval(Compiler.java:4537)
at clojure.lang.Compiler.load(Compiler.java:4857)
at clojure.lang.Compiler.loadFile(Compiler.java:4824)
at clojure.main$load_script__5833.invoke(main.clj:206)
at clojure.main$init_opt__5836.invoke(main.clj:211)
at clojure.main$initialize__5846.invoke(main.clj:239)
at clojure.main$null_opt__5868.invoke(main.clj:264)
at clojure.main$legacy_script__5883.invoke(main.clj:295)
at clojure.lang.Var.invoke(Var.java:346)
at clojure.main.legacy_script(main.java:34)
at clojure.lang.Script.main(Script.java:20)
Caused by: clojure.lang.LispReader$ReaderException: java.lang.ArrayIndexOutOfBoundsException: 7
at clojure.lang.LispReader.read(LispReader.java:180)
at clojure.core$read__4168.invoke(core.clj:2083)
at clojure.core$read__4168.invoke(core.clj:2081)
at clojure.core$read__4168.invoke(core.clj:2079)
at clojure.core$read__4168.invoke(core.clj:2077)
at chap_03$load_db__54.invoke(chap_03.clj:71)
at clojure.lang.AFn.applyToHelper(AFn.java:173)
at clojure.lang.AFn.applyTo(AFn.java:164)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:2714)
... 12 more
Caused by: java.lang.ArrayIndexOutOfBoundsException: 7
at clojure.lang.PersistentArrayMap$Seq.first(PersistentArrayMap.java:216)
at clojure.lang.APersistentMap.hashCode(APersistentMap.java:101)
at clojure.lang.Util.hash(Util.java:55)
at clojure.lang.PersistentHashMap.entryAt(PersistentHashMap.java:134)
at clojure.lang.PersistentHashMap.containsKey(PersistentHashMap.java:130)
at clojure.lang.APersistentSet.contains(APersistentSet.java:33)
at clojure.lang.PersistentHashSet.cons(PersistentHashSet.java:59)
at clojure.lang.PersistentHashSet.create(PersistentHashSet.java:34)
at clojure.lang.LispReader$SetReader.invoke(LispReader.java:974)
at clojure.lang.LispReader$DispatchReader.invoke(LispReader.java:540)
at clojure.lang.LispReader.read(LispReader.java:145)
... 20 more
Depending on the amount of the fields in the struct, I might also just get a part of the string as an attribute name instead of the error. For example :Loop 1
I use a store-function like this:
(defn store-customer-db [customer-db filename]
(spit filename (with-out-str (print customer-db))))
And a read-function like this:
(defn load-db [filename]
(with-in-str (slurp filename)(read)))
From the output file of spit I can see that the print doesn't give double quotes to the strings which seems to be a problem for slurp. What would be the correct solution for this?
My Clojure version is 1.0, and the contrib is a few weeks old snapshot.
print and println are meant for human-readable output. If you want to print something that's meant to be read in again later, use pr or prn.
user> (read-string (with-out-str (prn {"Apple" "Infinite Loop"})))
{"Apple" "Infinite Loop"}
Whereas:
user> (read-string (with-out-str (print {"Apple" "Infinite Loop"})))
java.lang.ArrayIndexOutOfBoundsException: 3 (NO_SOURCE_FILE:0)
It's trying to run this code:
(read-string "{Apple Infinite Loop}")
which has an odd number of keys/values. Note the lack of quotation marks around the individual hash keys/values. Even if this read works (i.e. if you coincidentally supply an even number of parameters), what it reads won't be a hash-map full of Strings, but rather Symbols. So you'll be getting back something other than what you output.
user> (map class (keys (read-string (with-out-str (print {"foo bar" "baz quux"})))))
(clojure.lang.Symbol clojure.lang.Symbol)
For, say:
(def hashed-hobbits {:bilbo "Takes after his Mother's family" :frodo "ring bearer"})
You only need:
(spit "hobbitses.txt" hashed-hobbits)
and to read it back:
(def there-and-back-again (read-string (slurp "hobbitses.txt")))
spit/slurp wraps it all in a string but using read-string on the slurp interprets the string back to clojure code/data. Works on trollish data structures too!