zcaudate
zcaudate

Reputation: 14258

is there a way to read all the forms in a clojure file?

If I use

(-> "<file>.clj" 
    (slurp) 
    (read-string))

That will only read the first form in the file (typically the ns declaration). Is there a way to retrieve a list of forms from the file?

I'd prefer if no external libraries are used.

Upvotes: 8

Views: 1031

Answers (2)

noisesmith
noisesmith

Reputation: 20194

This function opens a stream for Clojure to read from, and eagerly reads all forms from that stream until read throws an exception (this happens if there is a parse error, or there are no more forms to read).

(import '[java.io PushbackReader])
(require '[clojure.java.io :as io])

(defn read-all
  [file]
  (let [rdr (-> file io/file io/reader PushbackReader.)]
    (loop [forms []]
      (let [form (try (read rdr) (catch Exception e nil))]
        (if form
          (recur (conj forms form))
          forms)))))

Upvotes: 14

Arthur Ulfeldt
Arthur Ulfeldt

Reputation: 91577

stick a [ and ] onto the start and end of the string to make the whole file into a single vector form:

user> (clojure.pprint/pprint 
         (read-string (str "[" (slurp "/home/arthur/hello/project.clj") "]")))
[(defproject
  hello
  "0.1.0-SNAPSHOT"
  :description
  "FIXME: write description"
  :url
  "http://example.com/FIXME"
  :license
 {:name "Eclipse Public License",
  :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies
  [[org.clojure/clojure "1.5.1"] [clj-time "0.6.0"]]
  :source-paths
  ["dev"])] 
nil

```

Upvotes: 6

Related Questions