bultitude-master/0000700000175000017500000000000012077411267013275 5ustar daigodaigobultitude-master/README.markdown0000664000175000017500000000521112064520102015772 0ustar daigodaigo# Bultitude [![Build Status](https://secure.travis-ci.org/Raynes/bultitude.png)](http://travis-ci.org/Raynes/bultitude) Bultitude is a library for finding namespaces on the classpath. ## Usage ```clojure user=> (require '[bultitude.core :as b]) nil user=> (take 10 (b/namespaces-on-classpath)) (bultitude.core-test bultitude.core clojure.data clojure.string clojure.test clojure.xml clojure.inspector clojure.repl clojure.set clojure.test.junit) user=> (b/namespaces-on-classpath :prefix "bultitude") (bultitude.core-test bultitude.core) user=> (b/namespaces-on-classpath :prefix "bultitude" :classpath "src") (bultitude.core) user=> (b/namespaces-on-classpath :prefix "bultitude" :classpath "src:test") (bultitude.core bultitude.core-test) ``` Value for :classpath can either be a String containing paths (using the underlying operating system's path separator), or a collection of `File` objects. ## The Name I don't know. You'd have to ask [Phil](https://github.com/technomancy) about that one. ## History This library is a library similar to `clojure.tools.namespace`. It is designed to find namespaces on the classpath. This one was ripped from Leiningen's core because we decided it should be publically available to everyone. This library was originally devised in Leiningen because Leiningen had a few specific needs that `clojure.tools.namespace` did not provide. Furthermore, the library's author seems to be ignoring some issues with the library (having declined a filed issue about it so far) that makes the library explode when ran across a namespace with a namespace form that the reader cannot read. We ran into this problem because lein-newnew has mustache templates with `.clj` extensions and namespace forms with mustache syntax inside of them, and it would break any project that was using tools.namespace. If you have this kind of problem, you can use this library instead. Furthermore, this library has a few useful features like being able to provide your own classpath as a string and for only looking for namespaces matching a certain prefix. Note that regarding the above, the author of tools.namespace did eventually fix the issue. This library is still necessary and maintained because: * Leiningen uses it internally * There have been some fairly complex classpath contributions that people rely on * This is not a contrib project so you can contribute without a CA or a Jira patch parade * I don't have a lot of confidence in tools.namespace after the issue reported above was declined to be fixed for several months for no good reason New features have been added to tools.namespace recently, and when I get some time I'll see about porting them over. bultitude-master/.gitignore0000664000175000017500000000011412064520102015256 0ustar daigodaigopom.xml *jar /lib/ /classes/ .lein-deps-sum .lein-failures pom.xml* target/ bultitude-master/.travis.yml0000664000175000017500000000006412064520102015403 0ustar daigodaigolanguage: clojure lein: lein2 script: lein2 test-allbultitude-master/test/0000700000175000017500000000000012077411267014254 5ustar daigodaigobultitude-master/test/bultitude/0000700000175000017500000000000012077411267016255 5ustar daigodaigobultitude-master/test/bultitude/core_test.clj0000664000175000017500000000143712064520102020740 0ustar daigodaigo(ns bultitude.core-test (:use clojure.test bultitude.core)) (deftest namespaces-on-classpath-test (testing "find clojure.core" (is (seq (filter #(= 'clojure.core %) (namespaces-on-classpath))))) (testing "prefix" (is (seq (filter #(= 'clojure.core %) (namespaces-on-classpath :prefix "clojure.core")))) (is (every? #(.startsWith (name %) "clojure.core") (namespaces-on-classpath :prefix "clojure.core")))) (testing "directory" (is (= #{'bultitude.core 'bultitude.core-test} (set (namespaces-on-classpath :prefix "bultitude"))))) (testing "dash handling in prefixes" (is (= #{'bulti-tude.test} (set (namespaces-on-classpath :prefix "bulti-tude")))))) bultitude-master/test/bultitude/invalid.clj0000664000175000017500000000034112064520102020370 0ustar daigodaigo;; This is an invalid clojure file, and is used to check bultitude has no ;; problems with malformed source, which may be on the classpath for use ;; as templates, etc ({{somthing}}) (ns bultitude.{{some node}}) (def x 1) bultitude-master/test/bulti_tude/0000700000175000017500000000000012077411267016414 5ustar daigodaigobultitude-master/test/bulti_tude/test.clj0000664000175000017500000000002512064520102020057 0ustar daigodaigo(ns bulti-tude.test) bultitude-master/project.clj0000664000175000017500000000075012064520102015434 0ustar daigodaigo(defproject bultitude "0.2.0" :min-lein-version "2.0.0" :description "A library for find Clojure namespaces on the classpath." :url "https://github.com/Raynes/bultitude" :dependencies [[org.clojure/clojure "1.4.0"] [dynapath "0.2.0"]] :aliases {"test-all" ["with-profile" "dev,default:dev,1.3,default:dev,1.2,default" "test"]} :profiles {:1.3 {:dependencies [[org.clojure/clojure "1.3.0"]]} :1.2 {:dependencies [[org.clojure/clojure "1.2.1"]]}}) bultitude-master/src/0000700000175000017500000000000012077411267014064 5ustar daigodaigobultitude-master/src/bultitude/0000700000175000017500000000000012077411267016065 5ustar daigodaigobultitude-master/src/bultitude/core.clj0000664000175000017500000001010712064520102017503 0ustar daigodaigo(ns bultitude.core (:require [clojure.java.io :as io] [clojure.string :as string] [dynapath.util :as dp]) (:import (java.util.jar JarFile) (java.util.zip ZipException) (java.io File BufferedReader PushbackReader InputStreamReader) (clojure.lang DynamicClassLoader))) (defn- clj? [f] ;; Needs to work on JarEntries and Files, the former of which has no .isFile (and (not (.isDirectory f)) (.endsWith (.getName f) ".clj"))) (defn- jar? [f] (and (.isFile f) (.endsWith (.getName f) ".jar"))) (defn- read-ns-form "Given a reader on a Clojure source file, read until an ns form is found." [rdr] (let [form (try (read rdr false ::done) (catch Exception e ::done))] (if (try (and (list? form) (= 'ns (first form))) (catch Exception _)) (try (str form) ;; force the read to read the whole form, throwing on error (second form) (catch Exception _)) (when-not (= ::done form) (recur rdr))))) (defn namespaces-in-dir "Return a seq of all namespaces found in Clojure source files in dir." [dir] (for [f (file-seq (io/file dir)) :when (and (clj? f) (.canRead f)) :let [ns-form (with-open [r (PushbackReader. (io/reader f))] (read-ns-form r))] :when ns-form] ns-form)) (defn- ns-in-jar-entry [jarfile entry] (with-open [rdr (-> jarfile (.getInputStream (.getEntry jarfile (.getName entry))) InputStreamReader. BufferedReader. PushbackReader.)] (read-ns-form rdr))) (defn- namespaces-in-jar [jar] (try (let [jarfile (JarFile. jar)] (for [entry (enumeration-seq (.entries jarfile)) :when (clj? entry) :let [ns-form (ns-in-jar-entry jarfile entry)] :when ns-form] ns-form)) (catch ZipException e (throw (Exception. (str "jar file corrupt: " jar) e))))) (defn- split-classpath [classpath] (.split classpath (System/getProperty "path.separator"))) (defn loader-classpath "Returns a sequence of File objects from a classloader." [loader] (map io/as-file (dp/classpath-urls loader))) (defn classpath-files "Returns a sequence of File objects of the elements on the classpath." ([classloader] (map io/as-file (dp/all-classpath-urls classloader))) ([] (classpath-files (clojure.lang.RT/baseLoader)))) (defn- classpath->collection [classpath] (if (coll? classpath) classpath (split-classpath classpath))) (defn- classpath->files [classpath] (map io/file classpath)) (defn file->namespaces "Map a classpath file to the namespaces it contains. `prefix` allows for reducing the namespace search space. For large directories on the classpath, passing a `prefix` can provide significant efficiency gains." [prefix f] (cond (.isDirectory f) (namespaces-in-dir (if prefix (io/file f (-> prefix (.replaceAll "\\." "/") (.replaceAll "-" "_"))) f)) (jar? f) (let [ns-list (namespaces-in-jar f)] (if prefix (filter #(and % (.startsWith (name %) prefix)) ns-list) ns-list)))) (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." [& {:keys [prefix classpath] :or {classpath (classpath-files)}}] (mapcat (partial file->namespaces prefix) (->> classpath classpath->collection classpath->files))) (defn path-for "Transform a namespace into a .clj file path relative to classpath root." [namespace] (str (-> (str namespace) (.replace \- \_) (.replace \. \/)) ".clj"))