From 3c837f1abcf1098cdd5e9f36428f251c6f5c5fc7 Mon Sep 17 00:00:00 2001 From: gered Date: Tue, 25 Mar 2014 09:03:56 -0400 Subject: [PATCH] initial commit --- .gitignore | 17 +++++++++ LICENSE | 21 +++++++++++ README.md | 11 ++++++ project.clj | 8 +++++ src/clj_metasearch/core.clj | 71 +++++++++++++++++++++++++++++++++++++ 5 files changed, 128 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 project.clj create mode 100644 src/clj_metasearch/core.clj diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..79a263d --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +.DS_Store +/target +/classes +/checkouts +pom.xml +pom.xml.asc +*.jar +*.class +/.lein-* +/.nrepl-port +/*.project +/*.classpath +/.settings/ +*.iml +*.ipr +*.iws +/.idea/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8d9476f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Gered King + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..0d74228 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# clj-metasearch + +Helper functions for searching through Clojure namespaces for vars containing specific bits of metadata. + +## Usage + +FIXME + +## License + +Distributed under the the MIT License. See LICENSE for more details. diff --git a/project.clj b/project.clj new file mode 100644 index 0000000..7b71535 --- /dev/null +++ b/project.clj @@ -0,0 +1,8 @@ +(defproject clj-metasearch "0.1.0-SNAPSHOT" + :description "Helper functions for searching through Clojure namespaces for vars containing specific bits of metadata." + :url "http://example.com/FIXME" + :license {:name "MIT License" + :url "http://opensource.org/licenses/MIT"} + :dependencies [[org.clojure/clojure "1.5.1"] + [org.clojure/java.classpath "0.2.2"] + [org.clojure/tools.namespace "0.2.4"]]) diff --git a/src/clj_metasearch/core.clj b/src/clj_metasearch/core.clj new file mode 100644 index 0000000..0df392e --- /dev/null +++ b/src/clj_metasearch/core.clj @@ -0,0 +1,71 @@ +(ns clj-metasearch.core + (:import (java.io File) + (java.util.jar JarFile)) + (:require [clojure.tools.namespace.find :refer [find-clojure-sources-in-dir find-namespaces-in-jarfile]] + [clojure.tools.namespace.file :refer [read-file-ns-decl]] + [clojure.java.classpath :refer [classpath jar-file?]])) + +(defn- find-namespaces-in-dirs [classpath-files] + (->> classpath-files + (filter (fn [^File file] + (.isDirectory file))) + (map find-clojure-sources-in-dir) + (apply concat) + (map #(second (read-file-ns-decl %))))) + +(defn- find-namespaces-in-jars [classpath-files] + (->> classpath-files + (filter jar-file?) + (map #(new JarFile %)) + (map find-namespaces-in-jarfile) + (apply concat))) + +(defn- find-vars-in [namespace pred & [require-all-namespaces?]] + (try + (when require-all-namespaces? + (require namespace)) + (->> (ns-interns namespace) + (reduce + (fn [matches [name var]] + (let [metadata (meta var)] + (if (pred metadata) + (conj matches {:ns namespace + :var var}) + matches))) + [])) + (catch Exception ex + ; some namespaces, such as clojure.core.reducers, cannot be loaded under Java 6 and when + ; we run this function on such a namespace we get an exception like: + ; + ; java.lang.Exception: No namespace: clojure.core.reducers found + ; + ; which kind of makes it hard to pick out only those cases. + ; also, the exact same type of exception will get thrown if we attempt to call + ; (ns-interns) on a namespace which has not been loaded (required/used) yet. + ; + ; so for now we'll just silently fail on any exception and return a blank list (what + ; else could we really do?) + []))) + +(defn find-namespaces + "Searches for all Clojure namespaces currently on the classpath and returns only those + for which pred returns true, or all Clojure namespaces if pred is not provided." + [& [pred]] + (let [classpath-files (classpath) + dir-namespaces (find-namespaces-in-dirs classpath-files) + jar-namespaces (find-namespaces-in-jars classpath-files) + all-namespaces (distinct (concat dir-namespaces jar-namespaces))] + (if pred + (filter pred all-namespaces) + all-namespaces))) + +(defn find-vars + "Finds vars in Clojure namespaces for which namespace-pred returns true that have metadata + for which meta-pred returns true. If namespace-pred is not provided, all Clojure namespaces + are checked. The returns vars will each be in a map where the :ns key is the namespace + which the var was found in, and :var is the Clojure var itself (which you can get the value + of by, e.g. using var-get)" + [meta-pred & [namespace-pred]] + (->> (find-namespaces namespace-pred) + (map #(find-vars-in % meta-pred)) + (apply concat)))