I’ve got a piece of code to implement a ref of a map of atoms containing maps
> (def a (example.DynaRec.)
> (dosync (assoc! a 3 {:id 3 :contents "stuff"} 4 {:id 4}))
;;=> #[DynaRec@1a659078: {4 [<Atom@118eb00c: {:id 4}] 3 [Atom@242110fc: {:id 3 :contents "stuff"}]]
I want to make change the way this is displayed in the repl so that it only outputs
> a
;;=> ({:id 3 :contents "stuff"}
;; {:id 4})
how can this be done? The code is shown below:
(ns example.dyna-rec
(:gen-class
:name example.DynaRec
:prefix "-"
:init init
:state state
:extends clojure.lang.AFn
:implements [clojure.lang.IDeref
clojure.lang.Seqable
clojure.lang.ILookup
clojure.lang.ITransientMap]))
(defn- $ [this] (:data (.state this)))
(defn- valid?
([e]
(valid? e []))
([this e]
(every? #(contains? e %) (:required (.state this)))))
(defn -deref [this] @($ this))
(defn -valAt
([this k] ((-deref this) k nil))
([this k nv]
(if-let [vatom ((-deref this) k nv)]
@vatom)))
(defn -invoke
([this k] (-valAt this k))
([this k nv] -valAt this k nv))
(defn -seq [this] (seq (-deref this)))
(defn -count [this] (count (-deref this)))
(defn -without [this obj]
(alter ($ this) dissoc obj))
(defn -assoc
([this obj] (-assoc this (:id obj) obj))
([this k v]
{:pre [(valid? this v)
(= k (:id v))]}
(alter ($ this) assoc k (atom v))
this))
(defn -conj [this obj]
(-assoc this obj))
(defn -persistent [this]
(-deref this))
(defn -init []
[[] {:required #{:id}
:data (ref {})}])
To extend the classic java model (which clojure embraces) you can implement your own
.toStringwhich produces the correct strings, and then tell the REPL how to print this new class properlystart by adding a super basic
toStringto dyna-rec.clj:this can be called like this:
then improve the printer to match your desired output:
and test it:
This still does not print correctly at the REPL, so we need to extend the multimethod used by the printer (print-method) which is used by the REPL to know about your new class:
this produces what you seek: