Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I format a map over several lines with pprint?

Tags:

clojure

pprint

pprint's docs are kind of a brick wall. If you pprint a map, it comes out on one line like so: {:a "b", :b "c", :d "e"}. Instead, I'd like to be pprinted like this, optionally with commas:

{:a "b"
 :b "c"
 :d "e"}

How would one do that with pprint?

like image 583
Rayne Avatar asked Oct 26 '10 02:10

Rayne


2 Answers

You can set the *print-right-margin* binding:

Clojure=> (binding [*print-right-margin* 7] (pprint {:a 1 :b 2 :c 3}))
{:a 1,
 :b 2,
 :c 3}

Not exactly what you're looking for, but it might be enough?

BTW, the best way to figure this out —or at least the approach I took— is to use

Clojure=> (use 'clojure.contrib.repl-utils)
Clojure=> (source pprint)
(defn pprint 
  "Pretty print object to the optional output writer. If the writer is not provided, 
print the object to the currently bound value of *out*."
  ([object] (pprint object *out*)) 
  ([object writer]
     (with-pretty-writer writer
       (binding [*print-pretty* true]
         (write-out object))
       (if (not (= 0 (.getColumn #^PrettyWriter *out*)))
         (.write *out* (int \newline))))))
nil

Hmmrmmm.. what does with-pretty-writer do to *out*?

Clojure=> (source clojure.contrib.pprint/with-pretty-writer)
(defmacro #^{:private true} with-pretty-writer [base-writer & body]
  `(let [new-writer# (not (pretty-writer? ~base-writer))]
     (binding [*out* (if new-writer#
                      (make-pretty-writer ~base-writer *print-right-margin* *print-miser-width*)
                      ~base-writer)]
       ~@body
       (if new-writer# (.flush *out*)))))
nil

Okay, so *print-right-margin* sounds promising...

Clojure=> (source clojure.contrib.pprint/make-pretty-writer)
(defn- make-pretty-writer 
  "Wrap base-writer in a PrettyWriter with the specified right-margin and miser-width"
  [base-writer right-margin miser-width]
  (PrettyWriter. base-writer right-margin miser-width))
nil

Also, this is pretty informative:

Clojure=> (doc *print-right-margin*)
-------------------------
clojure.contrib.pprint/*print-right-margin*
nil
  Pretty printing will try to avoid anything going beyond this column.
Set it to nil to have pprint let the line be arbitrarily long. This will ignore all 
non-mandatory newlines.
nil

Anyway —and perhaps you already knew even this— if you really want to customize the way that pprint works, you can proxy clojure.contrib.pprint.PrettyWriter and pass that down by binding it to *out*. The PrettyWriter class is pretty large and intimidating, so I'm not sure if this was what you originally meant by your "brick wall" comment.

like image 194
intuited Avatar answered Sep 19 '22 16:09

intuited


I don't think you can do that, you'll probably need to write your own, something like:

(defn pprint-map [m]
  (print "{")
  (doall (for [[k v] m] (println k v)))
  (print "}"))
like image 37
lazy1 Avatar answered Sep 20 '22 16:09

lazy1