What is the "Correct" way to write an EDN file in Clojure as of August 2013?

15.1k views Asked by At

I would like to write out an EDN data file from Clojure as tagged literals. Although the clojure.edn API contains read and read-string, there are no writers. I'm familiar with the issue reported here. Based on that, it's my understanding that the pr and pr-str functions are what are meant to be used today.

I wanted to check with the StackOverflow community to see if something like the following would be considered the "correct" way to write out an EDN file:

(spit "friends.edn" (apply str 
  (interpose "\n\n"
             [(pr-str (symbol "#address-book/person") {:name "Janet Wood"})
              (pr-str (symbol "#address-book/person") {:name "Jack Tripper"})
              (pr-str (symbol "#address-book/person") {:name "Chrissy Snow"})])))

If you are using EDN in production, how do you write out an EDN file? Similar to the above? Are there any issues I need to look out for?

Update

The Clojure Cookbook entry, "Emitting Records as EDN Values" contains a more thorough explanation of this issue and ways to handle it that result in valid EDN tags.

1

There are 1 answers

1
Arthur Ulfeldt On BEST ANSWER

you should not need to generate the tags manually. If you use any of the clojure type definition mechanisms they will be created by the printer. defrecord is particularly convenient for this.

(ns address-book)
(defrecord person [name])

(def people [(person. "Janet Wood")
             (person. "Jack Tripper")
             (person. "Chrissy Snow")])

address-book> (pr-str people)
"[#address_book.person{:name \"Janet Wood\"} 
  #address_book.person{:name \"Jack Tripper\"} 
  #address_book.person{:name \"Chrissy Snow\"}]"

if you want them formatted more nicely you can combine with-out-str and clojure.pprint/pprint. Using Clojure types to create the tags also gives you reading of those tags for free.

address-book> (read-string (pr-str people))
[#address_book.person{:name "Janet Wood"} 
 #address_book.person{:name "Jack Tripper"} 
 #address_book.person{:name "Chrissy Snow"}]

address-book> (def read-people (read-string (pr-str people)))
#'address-book/read-people

address-book> (type (first read-people))
address_book.person

The only downside I see is that you lose some control over the way the tags look if you have -'s in your namespace because java classes can't contain these so they get converted to underscores.