Skip to content

Commit

Permalink
Added functions for retrieving the actual namespace forms instead of …
Browse files Browse the repository at this point in the history
…just namespae symbols. This will be useful for speeding up 'lein help'. This commit should not change the behavior of any pre-existing public functions.
  • Loading branch information
DavidEGrayson committed Dec 20, 2013
1 parent fc7e418 commit 68491b2
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 10 deletions.
45 changes: 35 additions & 10 deletions src/bultitude/core.clj
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
(java.io File BufferedReader PushbackReader InputStreamReader) (java.io File BufferedReader PushbackReader InputStreamReader)
(clojure.lang DynamicClassLoader))) (clojure.lang DynamicClassLoader)))


(declare namespace-forms-in-dir
file->namespace-forms)

(defn- clj? [^File f] (defn- clj? [^File f]
(and (not (.isDirectory f)) (and (not (.isDirectory f))
(.endsWith (.getName f) ".clj"))) (.endsWith (.getName f) ".clj")))
Expand All @@ -28,7 +31,7 @@
(catch Exception _)) (catch Exception _))
(try (try
(str form) ;; force the read to read the whole form, throwing on error (str form) ;; force the read to read the whole form, throwing on error
(second form) form
(catch Exception _)) (catch Exception _))
(when-not (= ::done form) (when-not (= ::done form)
(recur rdr))))) (recur rdr)))))
Expand All @@ -39,26 +42,31 @@
(defn namespaces-in-dir (defn namespaces-in-dir
"Return a seq of all namespaces found in Clojure source files in dir." "Return a seq of all namespaces found in Clojure source files in dir."
[dir] [dir]
(map second (namespace-forms-in-dir dir)))

(defn namespace-forms-in-dir
"Return a seq of all namespace forms found in Clojure source files in dir."
[dir]
(for [^File f (file-seq (io/file dir)) (for [^File f (file-seq (io/file dir))
:when (and (clj? f) (.canRead f)) :when (and (clj? f) (.canRead f))
:let [ns-form (ns-form-for-file f)] :let [ns-form (ns-form-for-file f)]
:when ns-form] :when ns-form]
ns-form)) ns-form))


(defn- ns-in-jar-entry [^JarFile jarfile ^JarEntry entry] (defn- ns-form-in-jar-entry [^JarFile jarfile ^JarEntry entry]
(with-open [rdr (-> jarfile (with-open [rdr (-> jarfile
(.getInputStream entry) (.getInputStream entry)
InputStreamReader. InputStreamReader.
BufferedReader. BufferedReader.
PushbackReader.)] PushbackReader.)]
(read-ns-form rdr))) (read-ns-form rdr)))


(defn- namespaces-in-jar [^File jar] (defn- namespace-forms-in-jar [^File jar]
(try (try
(let [jarfile (JarFile. jar)] (let [jarfile (JarFile. jar)]
(for [entry (enumeration-seq (.entries jarfile)) (for [entry (enumeration-seq (.entries jarfile))
:when (clj-jar-entry? entry) :when (clj-jar-entry? entry)
:let [ns-form (ns-in-jar-entry jarfile entry)] :let [ns-form (ns-form-in-jar-entry jarfile entry)]
:when ns-form] :when ns-form]
ns-form)) ns-form))
(catch ZipException e (catch ZipException e
Expand Down Expand Up @@ -91,31 +99,48 @@
reducing the namespace search space. For large directories on the classpath, reducing the namespace search space. For large directories on the classpath,
passing a `prefix` can provide significant efficiency gains." passing a `prefix` can provide significant efficiency gains."
[^String prefix ^File f] [^String prefix ^File f]
(map second (file->namespace-forms prefix f)))

(defn file->namespace-forms
"Map a classpath file to the namespace forms it contains. `prefix` allows for
reducing the namespace search space. For large directories on the classpath,
passing a `prefix` can provide significant efficiency gains."
[^String prefix ^File f]
(cond (cond
(.isDirectory f) (namespaces-in-dir (.isDirectory f) (namespace-forms-in-dir
(if prefix (if prefix
(io/file f (-> prefix (io/file f (-> prefix
(.replaceAll "\\." "/") (.replaceAll "\\." "/")
(.replaceAll "-" "_"))) (.replaceAll "-" "_")))
f)) f))
(jar? f) (let [ns-list (namespaces-in-jar f)] (jar? f) (let [ns-list (namespace-forms-in-jar f)]
(if prefix (if prefix
(filter #(and % (.startsWith (name %) prefix)) ns-list) (filter #(and (second %) (.startsWith (name (second %)) prefix)) ns-list)
ns-list)))) ns-list))))


(defn namespaces-on-classpath
"Return symbols of all namespaces matching the given prefix both on disk and (defn namespace-forms-on-classpath
"Returs the namespaces forms matching the given prefix both on disk and
inside jar files. If :prefix is passed, only return namespaces that begin with inside jar files. If :prefix is passed, only return namespaces that begin with
this prefix. If :classpath is passed, it should be a seq of File objects or a this prefix. If :classpath is passed, it should be a seq of File objects or a
classpath string. If it is not passed, default to java.class.path and the classpath string. If it is not passed, default to java.class.path and the
current classloader, assuming it is a dynamic classloader." current classloader, assuming it is a dynamic classloader."
[& {:keys [prefix classpath] :or {classpath (classpath-files)}}] [& {:keys [prefix classpath] :or {classpath (classpath-files)}}]
(mapcat (mapcat
(partial file->namespaces prefix) (partial file->namespace-forms prefix)
(->> classpath (->> classpath
classpath->collection classpath->collection
classpath->files))) classpath->files)))


(defn namespaces-on-classpath
"Return symbols of all namespaces matching the given prefix both on disk and
inside jar files. If :prefix is passed, only return namespaces that begin with
this prefix. If :classpath is passed, it should be a seq of File objects or a
classpath string. If it is not passed, default to java.class.path and the
current classloader, assuming it is a dynamic classloader."
[& args]
(map second (apply namespace-forms-on-classpath args)))

(defn path-for (defn path-for
"Transform a namespace into a .clj file path relative to classpath root." "Transform a namespace into a .clj file path relative to classpath root."
[namespace] [namespace]
Expand Down
23 changes: 23 additions & 0 deletions test/bultitude/core_test.clj
Original file line number Original file line Diff line number Diff line change
@@ -1,7 +1,24 @@
(ns bultitude.core-test (ns bultitude.core-test
(:require [clojure.java.io :as io])
(:use clojure.test (:use clojure.test
bultitude.core)) bultitude.core))


(deftest namespaces-in-dir-test
(testing namespaces-in-dir
(is (= '(bulti-tude.test) (namespaces-in-dir "test/bulti_tude")))))

(deftest namespaces-forms-in-dir-test
(testing namespace-forms-in-dir
(is (= '((ns bulti-tude.test)) (namespace-forms-in-dir "test/bulti_tude")))))

(deftest file->namespaces-test
(testing "on a directory with a clj in it"
(is (= '(bulti-tude.test) (file->namespaces nil (io/file "test/bulti_tude"))))))

(deftest file->namespace-forms-test
(testing "on a directory with a clj in it"
(is (= '((ns bulti-tude.test)) (file->namespace-forms nil (io/file "test/bulti_tude"))))))

(deftest namespaces-on-classpath-test (deftest namespaces-on-classpath-test
(testing "find clojure.core" (testing "find clojure.core"
(is (seq (filter (is (seq (filter
Expand All @@ -23,6 +40,12 @@
#{'bulti-tude.test} #{'bulti-tude.test}
(set (namespaces-on-classpath :prefix "bulti-tude")))))) (set (namespaces-on-classpath :prefix "bulti-tude"))))))


(deftest namespace-forms-on-classpath-test
(testing namespace-forms-on-classpath
(is (every?
#(= 'ns (first %))
(namespace-forms-on-classpath)))))

(defn test-doc-from-ns-form-helper (defn test-doc-from-ns-form-helper
[docstring ns-form] [docstring ns-form]
(eval ns-form) (eval ns-form)
Expand Down

0 comments on commit 68491b2

Please sign in to comment.