Custom edn readers for dummies

Custom edn readers for dummies

Here follows a silly example to show you how easy it is to extend edn using your own custom reader tags.

We will need...

  • A reader tag: we will use #demo/reverse (note: tags always needs a prefix, demo in this case)
  • A function that will understand what we want to achieve with our custom tag
  • To tell the edn reader about our custom tag

What do we want to achieve?

For our demo, we want to reverse some of the collections in our .edn file. I get that you will never use this, but it makes understanding the process easy.

;; data.edn
{:a "a"
 :b [1 2 3 4 5]
 :c #demo/reverse ["e" "d" "c" "b" "a"]}

;; becomes
{:a "a"
 :b [1 2 3 4 5]
 :c '("a" "b" "c" "d" "e")}

Let's build the reader

Our reader will simply check if the value it receives is a collection, and if it is, it will reverse that collection.

(defn reverse-reader [coll]
  (assert (coll? coll) "you can only reverse collections")
  (reverse coll))

Then we link our reader tag with our reader function.

 (def custom-readers {'demo/reverse reverse-reader})

Finally we read some custom edn

(def some-edn "{:a 1
                :b [1 2 3 4 5]
                :c #demo/reverse [5 4 3 2 1]}")

(def result-data
  (clojure.edn/read-string {:readers custom-readers} some-edn))

(prn (:c result-data)) ; => '(1 2 3 4 5)

It's that easy!

For some real world examples have a look at how dyn-edn and integrant use custom reader tags.