Track which keys and indices of a deep data structures are accessed.
; require the namespace
(require '[eu.esuomi.code.coll-tracker :as tracker])
; define some data
(def data {:simple 1
:nested {:value 2
:deeply {:final-value 3}}
:another 4
:sequences [#{:awesome :cool}
#{:hot :lit}
[6 7]]})
; you need an atom for tracking
(def tracker (atom #{}))
(def tracked (tracker/tracked data tracker))
; use the tracked data structure
(println (get tracked :simple)
(some-> tracked :nested :value)
(get-in tracked [:nested :deeply :final-value])
((juxt first second) (-> tracked :sequences (nth 2))))
; => 1 2 3 [6 7]
; see which paths were accessed
(println (sort @tracker))
; => ([:nested] [:sequences] [:simple] [:nested :deeply] [:nested :value] [:sequences 2] [:nested :deeply :final-value])
; Note! Accessing the original data does not impact the tracker
(println (get data :another)
(-> data :sequences (nth 1) second)
(get-in data [:nested :value]))
; => 4 :lit 2
; reprint to see that nothing changed
(println (sort @tracker))
; => ([:nested] [:sequences] [:simple] [:nested :deeply] [:nested :value] [:sequences 2] [:nested :deeply :final-value])The wrapper supports Clojure's ILookup, Indexed and Seqable interfaces meaning maps,
vectors, lists, sets are all supported.
In case of sets a special key is used to indicate access:
(def colored (atom #{}))
(def paints (tracker/tracked {:colors #{{:name :red :value "#bb515d"}
{:name :green :value "#00ff80"}
{:name :blue :value "#0c5daa"}}}
colored))
(println (-> paints :colors first :value))
; => "#<hex value>"
@colored
; => #{[:colors] [:colors :*]}The tracked data structure decorates printing with a #tracked:
(println paints)
; => #tracked {:colors #{{:name :blue, :value #0c5daa} {:name :green, :value #00ff80} {:name :red, :value #bb515d}}}The paths are useful, but a trie-like map is more readable to see what was used. Utility function is provided for this purpose:
(clojure.pprint/pprint (tracker/paths->map @tracker))
; => {:sequences {2 nil},
; :nested {:value nil, :deeply {:final-value nil}},
; :simple nil}OpenAI's ChatGPT with GPT-4.1 model was used to create parts of this library. As such the license is chosen as a very permissive one as I cannot claim ownership of a product of an amalgamation of all those who became before me.
All assets and code are under the CC0 LICENSE and in the public domain unless specified otherwise.