` is a number with a suffix like `m` for megabytes.
To find the default MaxPermSize for your JDK, run
`java -XX:+PrintFlagsFinal` and search the results for "MaxPermSize".
Try doubling it.
The Permanent Generation was removed in JDK 1.8 ([JEP 122]) so this
section no longer applies.
In some older JDKs (1.5) the default garbage collector did not collect
the Permanent Generation at all unless it was explicitly enabled with
`-XX:+CMSPermGenSweepingEnabled`.
Disabling Refresh In a Namespace
--------------------------------
Some projects have a "project REPL" or a "scratch" namespace where you
want keep state during development. You can use the functions
`disable-unload!` and `disable-reload!` in
`clojure.tools.namespace.repl` to prevent `refresh` from automatically
un/reloading those namespaces.
Use this feature sparingly: it exists as a development-time
convenience, not a work-around for code that is not reload-safe. Also,
see the warnings about aliases, below. Aliases to reloaded namespaces
will break if the namespace *containing* the alias is not reloaded
also.
After an error, `refresh` will **not** attempt to recover symbol
mappings and aliases for namespaces with `disable-unload!` or
`disable-reload!` set.
Developer Information
----------------------------------------
* [GitHub project](https://github.com/clojure/tools.namespace)
* [How to contribute](http://dev.clojure.org/display/community/Contributing)
* [Bug Tracker](http://dev.clojure.org/jira/browse/TNS)
* [Continuous Integration](http://build.clojure.org/job/tools.namespace/)
* [Compatibility Test Matrix](http://build.clojure.org/job/tools.namespace-test-matrix/)
Change Log
----------------------------------------
### Version 0.2.12-SNAPSHOT
* In development, current Git master branch
### Version 0.2.11 on 19-Jun-2015
* [TNS-34] Allow reader conditionals in parsed source files
### Version 0.2.10 on 26-Feb-2015
* Widen existing functions to handle both clj and cljc files in
advance of reader conditional support in Clojure 1.7.
### Version 0.2.9 on 31-Jan-2015
* Fix [TNS-20]: Undefined 'unload' order after namespaces are first
added to an new, empty tracker.
* Improvement [TNS-21]: Support `ns` clauses which use vectors
instead of lists for clauses, contrary to docs.
* Improvement [TNS-32]: Support `ns` clauses which use symbols as
clause heads instead of keywords, contrary to docs.
### Version 0.2.8 on 19-Dec-2014
* Improvement [TNS-31]: Specific error message when `:after` symbol
passed to `refresh` cannot be resolved.
* Fix [TNS-26]: namespace alias recovery after failed reload did not
work due to local binding shadowing global Var
### Version 0.2.7 on 19-Sept-2014
* [Revert bad commit](https://github.com/clojure/tools.namespace/commit/27194f2edfe3f5f9e1343f993beca4b43f0bafe8)
mistakenly included in 0.2.6 which could cause the tracker's
'unload' order to be incorrect. See discussion at [TNS-20].
### **BROKEN** Version 0.2.6 on 7-Sept-2014 **DO NOT USE**
* `clojure.tools.namespace.parse/read-ns-decl` asserts that its
argument is a PushbackReader, instead of silently returning nil
* Fix [TNS-22]: broken `clojure.string/replace` with Windows path
separator
### Version 0.2.5 on 15-Jul-2014
* New `clojure.tools.namespace.repl/clear` empties the state of the
REPL dependency tracker. This can help repair the dependency
tracker after a failed load or a circular dependency error.
* Enhancement [TNS-19]: `deps-from-ns-decl` should return an empty
set instead of nil. This may be a breaking change for some but
is consistent with the original docstring.
* Enhancement [TNS-18]: Compute transitive dependencies in linear time.
* Enhancement [TNS-17]: The `ns` form doesn't need to be the first
top-level form in a file.
* Fix [TNS-16]: Don't depend on specific hash ordering in tests.
Exposed by new hash functions in Clojure 1.6.0.
* Fix [TNS-15]: Handle spaces in classpath directories (old
`clojure.tools.namespace`)
* Fix [TNS-12]: Duplicate definition of `jar-file?`
### Version 0.2.4 on 19-Jul-2013
* Fix [TNS-10]: Forbid circular dependency when a namespace depends
on itself
* Fix [TNS-9] and [TNS-11]: support other prefix-list forms
* Fix [TNS-8]: In `move-ns`, do not modify files whose contents does
not change
### Version 0.2.3 on 01-Apr-2013
* New: Attempt recovery of aliases/refers in REPL after error
### Version 0.2.2 on 14-Dec-2012
* New: Add `:after` option to `refresh`
* New: Add `clojure.tools.namespace.move`
* Fix [TNS-4], reflection warnings
### Version 0.2.1 on 26-Oct-2012
* Fix: Restore deprecated 0.1.x APIs in `clojure.tools.namespace`
* Fix [TNS-3], actually use `refresh-dirs`
### Version 0.2.0 on 05-Oct-2012
* **Not recommended for use**: this release introduced breaking API
changes (renaming core namespaces and functions) without
backwards-compatibility. Applications with dependencies on both
the 0.2.x and 0.1.x APIs cannot use this version.
* New dependency tracking & reloading features
* Eliminate dependency on [java.classpath]
### Version 0.1.3 on 24-Apr-2012
* Fix [TNS-1] Workaround for Clojure 1.2 reader bug
### Version 0.1.2 on 10-Feb-2012
* Fix: Eliminate reflection warnings
### Version 0.1.1 on 18-May-2011
### Version 0.1.0 on 24-Apr-2011
* Source-compatible with clojure.contrib.find-namespaces in old
clojure-contrib 1.2.0
[TNS-1]: http://dev.clojure.org/jira/browse/TNS-1
[TNS-3]: http://dev.clojure.org/jira/browse/TNS-3
[TNS-4]: http://dev.clojure.org/jira/browse/TNS-4
[TNS-8]: http://dev.clojure.org/jira/browse/TNS-8
[TNS-9]: http://dev.clojure.org/jira/browse/TNS-9
[TNS-10]: http://dev.clojure.org/jira/browse/TNS-10
[TNS-11]: http://dev.clojure.org/jira/browse/TNS-11
[TNS-12]: http://dev.clojure.org/jira/browse/TNS-12
[TNS-15]: http://dev.clojure.org/jira/browse/TNS-15
[TNS-16]: http://dev.clojure.org/jira/browse/TNS-16
[TNS-17]: http://dev.clojure.org/jira/browse/TNS-17
[TNS-18]: http://dev.clojure.org/jira/browse/TNS-18
[TNS-19]: http://dev.clojure.org/jira/browse/TNS-19
[TNS-20]: http://dev.clojure.org/jira/browse/TNS-20
[TNS-21]: http://dev.clojure.org/jira/browse/TNS-21
[TNS-22]: http://dev.clojure.org/jira/browse/TNS-22
[TNS-23]: http://dev.clojure.org/jira/browse/TNS-23
[TNS-24]: http://dev.clojure.org/jira/browse/TNS-24
[TNS-25]: http://dev.clojure.org/jira/browse/TNS-25
[TNS-26]: http://dev.clojure.org/jira/browse/TNS-26
[TNS-27]: http://dev.clojure.org/jira/browse/TNS-27
[TNS-28]: http://dev.clojure.org/jira/browse/TNS-28
[TNS-29]: http://dev.clojure.org/jira/browse/TNS-29
[TNS-30]: http://dev.clojure.org/jira/browse/TNS-30
[TNS-31]: http://dev.clojure.org/jira/browse/TNS-31
[TNS-32]: http://dev.clojure.org/jira/browse/TNS-32
[TNS-33]: http://dev.clojure.org/jira/browse/TNS-33
[TNS-34]: http://dev.clojure.org/jira/browse/TNS-34
[java.classpath]: https://github.com/clojure/java.classpath
[JEP 122]: http://openjdk.java.net/jeps/122
Copyright and License
----------------------------------------
Copyright © 2012 Stuart Sierra All rights reserved. The use and
distribution terms for this software are covered by the
[Eclipse Public License 1.0] which can be found in the file
epl-v10.html at the root of this distribution. By using this software
in any fashion, you are agreeing to be bound by the terms of this
license. You must not remove this notice, or any other, from this
software.
[Eclipse Public License 1.0]: http://opensource.org/licenses/eclipse-1.0.php
tools.namespace-tools.namespace-0.2.11/epl.html 0000664 0000000 0000000 00000030536 12541067461 0021442 0 ustar 00root root 0000000 0000000
Eclipse Public License - Version 1.0
Eclipse Public License - v 1.0
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR
DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS
AGREEMENT.
1. DEFINITIONS
"Contribution" means:
a) in the case of the initial Contributor, the initial
code and documentation distributed under this Agreement, and
b) in the case of each subsequent Contributor:
i) changes to the Program, and
ii) additions to the Program;
where such changes and/or additions to the Program
originate from and are distributed by that particular Contributor. A
Contribution 'originates' from a Contributor if it was added to the
Program by such Contributor itself or anyone acting on such
Contributor's behalf. Contributions do not include additions to the
Program which: (i) are separate modules of software distributed in
conjunction with the Program under their own license agreement, and (ii)
are not derivative works of the Program.
"Contributor" means any person or entity that distributes
the Program.
"Licensed Patents" mean patent claims licensable by a
Contributor which are necessarily infringed by the use or sale of its
Contribution alone or when combined with the Program.
"Program" means the Contributions distributed in accordance
with this Agreement.
"Recipient" means anyone who receives the Program under
this Agreement, including all Contributors.
2. GRANT OF RIGHTS
a) Subject to the terms of this Agreement, each
Contributor hereby grants Recipient a non-exclusive, worldwide,
royalty-free copyright license to reproduce, prepare derivative works
of, publicly display, publicly perform, distribute and sublicense the
Contribution of such Contributor, if any, and such derivative works, in
source code and object code form.
b) Subject to the terms of this Agreement, each
Contributor hereby grants Recipient a non-exclusive, worldwide,
royalty-free patent license under Licensed Patents to make, use, sell,
offer to sell, import and otherwise transfer the Contribution of such
Contributor, if any, in source code and object code form. This patent
license shall apply to the combination of the Contribution and the
Program if, at the time the Contribution is added by the Contributor,
such addition of the Contribution causes such combination to be covered
by the Licensed Patents. The patent license shall not apply to any other
combinations which include the Contribution. No hardware per se is
licensed hereunder.
c) Recipient understands that although each Contributor
grants the licenses to its Contributions set forth herein, no assurances
are provided by any Contributor that the Program does not infringe the
patent or other intellectual property rights of any other entity. Each
Contributor disclaims any liability to Recipient for claims brought by
any other entity based on infringement of intellectual property rights
or otherwise. As a condition to exercising the rights and licenses
granted hereunder, each Recipient hereby assumes sole responsibility to
secure any other intellectual property rights needed, if any. For
example, if a third party patent license is required to allow Recipient
to distribute the Program, it is Recipient's responsibility to acquire
that license before distributing the Program.
d) Each Contributor represents that to its knowledge it
has sufficient copyright rights in its Contribution, if any, to grant
the copyright license set forth in this Agreement.
3. REQUIREMENTS
A Contributor may choose to distribute the Program in object code
form under its own license agreement, provided that:
a) it complies with the terms and conditions of this
Agreement; and
b) its license agreement:
i) effectively disclaims on behalf of all Contributors
all warranties and conditions, express and implied, including warranties
or conditions of title and non-infringement, and implied warranties or
conditions of merchantability and fitness for a particular purpose;
ii) effectively excludes on behalf of all Contributors
all liability for damages, including direct, indirect, special,
incidental and consequential damages, such as lost profits;
iii) states that any provisions which differ from this
Agreement are offered by that Contributor alone and not by any other
party; and
iv) states that source code for the Program is available
from such Contributor, and informs licensees how to obtain it in a
reasonable manner on or through a medium customarily used for software
exchange.
When the Program is made available in source code form:
a) it must be made available under this Agreement; and
b) a copy of this Agreement must be included with each
copy of the Program.
Contributors may not remove or alter any copyright notices contained
within the Program.
Each Contributor must identify itself as the originator of its
Contribution, if any, in a manner that reasonably allows subsequent
Recipients to identify the originator of the Contribution.
4. COMMERCIAL DISTRIBUTION
Commercial distributors of software may accept certain
responsibilities with respect to end users, business partners and the
like. While this license is intended to facilitate the commercial use of
the Program, the Contributor who includes the Program in a commercial
product offering should do so in a manner which does not create
potential liability for other Contributors. Therefore, if a Contributor
includes the Program in a commercial product offering, such Contributor
("Commercial Contributor") hereby agrees to defend and
indemnify every other Contributor ("Indemnified Contributor")
against any losses, damages and costs (collectively "Losses")
arising from claims, lawsuits and other legal actions brought by a third
party against the Indemnified Contributor to the extent caused by the
acts or omissions of such Commercial Contributor in connection with its
distribution of the Program in a commercial product offering. The
obligations in this section do not apply to any claims or Losses
relating to any actual or alleged intellectual property infringement. In
order to qualify, an Indemnified Contributor must: a) promptly notify
the Commercial Contributor in writing of such claim, and b) allow the
Commercial Contributor to control, and cooperate with the Commercial
Contributor in, the defense and any related settlement negotiations. The
Indemnified Contributor may participate in any such claim at its own
expense.
For example, a Contributor might include the Program in a commercial
product offering, Product X. That Contributor is then a Commercial
Contributor. If that Commercial Contributor then makes performance
claims, or offers warranties related to Product X, those performance
claims and warranties are such Commercial Contributor's responsibility
alone. Under this section, the Commercial Contributor would have to
defend claims against the other Contributors related to those
performance claims and warranties, and if a court requires any other
Contributor to pay any damages as a result, the Commercial Contributor
must pay those damages.
5. NO WARRANTY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION,
ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
responsible for determining the appropriateness of using and
distributing the Program and assumes all risks associated with its
exercise of rights under this Agreement , including but not limited to
the risks and costs of program errors, compliance with applicable laws,
damage to or loss of data, programs or equipment, and unavailability or
interruption of operations.
6. DISCLAIMER OF LIABILITY
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT
NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
7. GENERAL
If any provision of this Agreement is invalid or unenforceable under
applicable law, it shall not affect the validity or enforceability of
the remainder of the terms of this Agreement, and without further action
by the parties hereto, such provision shall be reformed to the minimum
extent necessary to make such provision valid and enforceable.
If Recipient institutes patent litigation against any entity
(including a cross-claim or counterclaim in a lawsuit) alleging that the
Program itself (excluding combinations of the Program with other
software or hardware) infringes such Recipient's patent(s), then such
Recipient's rights granted under Section 2(b) shall terminate as of the
date such litigation is filed.
All Recipient's rights under this Agreement shall terminate if it
fails to comply with any of the material terms or conditions of this
Agreement and does not cure such failure in a reasonable period of time
after becoming aware of such noncompliance. If all Recipient's rights
under this Agreement terminate, Recipient agrees to cease use and
distribution of the Program as soon as reasonably practicable. However,
Recipient's obligations under this Agreement and any licenses granted by
Recipient relating to the Program shall continue and survive.
Everyone is permitted to copy and distribute copies of this
Agreement, but in order to avoid inconsistency the Agreement is
copyrighted and may only be modified in the following manner. The
Agreement Steward reserves the right to publish new versions (including
revisions) of this Agreement from time to time. No one other than the
Agreement Steward has the right to modify this Agreement. The Eclipse
Foundation is the initial Agreement Steward. The Eclipse Foundation may
assign the responsibility to serve as the Agreement Steward to a
suitable separate entity. Each new version of the Agreement will be
given a distinguishing version number. The Program (including
Contributions) may always be distributed subject to the version of the
Agreement under which it was received. In addition, after a new version
of the Agreement is published, Contributor may elect to distribute the
Program (including its Contributions) under the new version. Except as
expressly stated in Sections 2(a) and 2(b) above, Recipient receives no
rights or licenses to the intellectual property of any Contributor under
this Agreement, whether expressly, by implication, estoppel or
otherwise. All rights in the Program not expressly granted under this
Agreement are reserved.
This Agreement is governed by the laws of the State of New York and
the intellectual property laws of the United States of America. No party
to this Agreement will bring a legal action under this Agreement more
than one year after the cause of action arose. Each party waives its
rights to a jury trial in any resulting litigation.
tools.namespace-tools.namespace-0.2.11/pom.xml 0000664 0000000 0000000 00000001706 12541067461 0021306 0 ustar 00root root 0000000 0000000
4.0.0
tools.namespace
0.2.11
${artifactId}
org.clojure
pom.contrib
0.1.2
true
Stuart Sierra
scm:git:git@github.com:clojure/tools.namespace.git
scm:git:git@github.com:clojure/tools.namespace.git
git@github.com:clojure/tools.namespace.git
tools.namespace-0.2.11
tools.namespace-tools.namespace-0.2.11/src/ 0000775 0000000 0000000 00000000000 12541067461 0020554 5 ustar 00root root 0000000 0000000 tools.namespace-tools.namespace-0.2.11/src/main/ 0000775 0000000 0000000 00000000000 12541067461 0021500 5 ustar 00root root 0000000 0000000 tools.namespace-tools.namespace-0.2.11/src/main/clojure/ 0000775 0000000 0000000 00000000000 12541067461 0023143 5 ustar 00root root 0000000 0000000 tools.namespace-tools.namespace-0.2.11/src/main/clojure/clojure/ 0000775 0000000 0000000 00000000000 12541067461 0024606 5 ustar 00root root 0000000 0000000 tools.namespace-tools.namespace-0.2.11/src/main/clojure/clojure/tools/ 0000775 0000000 0000000 00000000000 12541067461 0025746 5 ustar 00root root 0000000 0000000 tools.namespace-tools.namespace-0.2.11/src/main/clojure/clojure/tools/namespace.clj 0000664 0000000 0000000 00000015471 12541067461 0030404 0 ustar 00root root 0000000 0000000 ;; Copyright (c) Stuart Sierra, 2012. All rights reserved. The use
;; and distribution terms for this software are covered by the Eclipse
;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this
;; distribution. By using this software in any fashion, you are
;; agreeing to be bound by the terms of this license. You must not
;; remove this notice, or any other, from this software.
(ns
^{:author "Stuart Sierra",
:doc "This namespace is DEPRECATED; most functions have been moved to
other namespaces"}
clojure.tools.namespace
(:require [clojure.java.io :as io])
(:import (java.io File FileReader BufferedReader PushbackReader
InputStreamReader)
(java.util.jar JarFile JarEntry)))
;;; Finding namespaces in a directory tree
(defn clojure-source-file?
"DEPRECATED; trivial to implement locally
Returns true if file is a normal file with a .clj or .cljc extension."
[^File file]
(and (.isFile file)
(or
(.endsWith (.getName file) ".clj")
(.endsWith (.getName file) ".cljc"))))
(defn find-clojure-sources-in-dir
"DEPRECATED; moved to clojure.tools.namespace.find
Searches recursively under dir for Clojure source files (.clj, .cljc).
Returns a sequence of File objects, in breadth-first sort order."
[^File dir]
;; Use sort by absolute path to get breadth-first search.
(sort-by #(.getAbsolutePath ^File %)
(filter clojure-source-file? (file-seq dir))))
(defn comment?
"DEPRECATED; moved to clojure.tools.namespace.parse
Returns true if form is a (comment ...)"
[form]
(and (list? form) (= 'comment (first form))))
(defn ns-decl?
"DEPRECATED; moved to clojure.tools.namespace.parse
Returns true if form is a (ns ...) declaration."
[form]
(and (list? form) (= 'ns (first form))))
(defn read-ns-decl
"DEPRECATED; moved to clojure.tools.namespace.parse
Attempts to read a (ns ...) declaration from rdr, and returns the
unevaluated form. Returns nil if read fails or if a ns declaration
cannot be found. The ns declaration must be the first Clojure form
in the file, except for (comment ...) forms."
[^PushbackReader rdr]
(try
(loop [] (let [form (doto (read rdr) str)]
(cond
(ns-decl? form) form
(comment? form) (recur)
:else nil)))
(catch Exception e nil)))
(defn read-file-ns-decl
"DEPRECATED; moved to clojure.tools.namespace.file
Attempts to read a (ns ...) declaration from file, and returns the
unevaluated form. Returns nil if read fails, or if the first form
is not a ns declaration."
[^File file]
(with-open [rdr (PushbackReader. (BufferedReader. (FileReader. file)))]
(read-ns-decl rdr)))
(defn find-ns-decls-in-dir
"DEPRECATED; moved to clojure.tools.namespace.find
Searches dir recursively for (ns ...) declarations in Clojure
source files; returns the unevaluated ns declarations."
[^File dir]
(filter identity (map read-file-ns-decl (find-clojure-sources-in-dir dir))))
(defn find-namespaces-in-dir
"DEPRECATED; moved to clojure.tools.namespace.find
Searches dir recursively for (ns ...) declarations in Clojure
source files; returns the symbol names of the declared namespaces."
[^File dir]
(map second (find-ns-decls-in-dir dir)))
;;; copied from clojure.java.classpath to preserve deprecated API
;;; without an explicit dependency
(defn- loader-classpath [loader]
(when (instance? java.net.URLClassLoader loader)
(map
#(java.io.File. (.toURI ^java.net.URL %))
(.getURLs ^java.net.URLClassLoader loader))))
(defn- classpath
([classloader]
(distinct
(mapcat
loader-classpath
(take-while
identity
(iterate #(.getParent ^ClassLoader %) classloader)))))
([] (classpath (clojure.lang.RT/baseLoader))))
(defn- classpath-directories []
(filter #(.isDirectory ^File %) (classpath)))
(defn- jar-file? [f]
(let [file (io/file f)]
(and (.isFile file)
(or (.endsWith (.getName file) ".jar")
(.endsWith (.getName file) ".JAR")))))
(defn- classpath-jarfiles []
(map #(JarFile. ^File %) (filter jar-file? (classpath))))
(defn- filenames-in-jar [^JarFile jar-file]
(map #(.getName ^JarEntry %)
(filter #(not (.isDirectory ^JarEntry %))
(enumeration-seq (.entries jar-file)))))
;;; Finding namespaces in JAR files
(defn clojure-sources-in-jar
"DEPRECATED; moved to clojure.tools.namespace.find
Returns a sequence of filenames ending in .clj or .cljc found in the JAR file."
[^JarFile jar-file]
(filter #(or (.endsWith ^String % ".clj") (.endsWith ^String % ".cljc"))
(filenames-in-jar jar-file)))
(defn read-ns-decl-from-jarfile-entry
"DEPRECATED; moved to clojure.tools.namespace.find
Attempts to read a (ns ...) declaration from the named entry in the
JAR file, and returns the unevaluated form. Returns nil if the read
fails, or if the first form is not a ns declaration."
[^JarFile jarfile ^String entry-name]
(with-open [rdr (PushbackReader.
(BufferedReader.
(InputStreamReader.
(.getInputStream jarfile (.getEntry jarfile entry-name)))))]
(read-ns-decl rdr)))
(defn find-ns-decls-in-jarfile
"DEPRECATED; moved to clojure.tools.namespace.find
Searches the JAR file for Clojure source files containing (ns ...)
declarations; returns the unevaluated ns declarations."
[^JarFile jarfile]
(filter identity
(map #(read-ns-decl-from-jarfile-entry jarfile %)
(clojure-sources-in-jar jarfile))))
(defn find-namespaces-in-jarfile
"DEPRECATED; moved to clojure.tools.namespace.find
Searches the JAR file for Clojure source files containing (ns ...)
declarations. Returns a sequence of the symbol names of the
declared namespaces."
[^JarFile jarfile]
(map second (find-ns-decls-in-jarfile jarfile)))
;;; Finding namespaces anywhere on CLASSPATH
(defn find-ns-decls-on-classpath
"DEPRECATED; use clojure.tools.namespace.find/find-ns-decls
and clojure.java.classpath/classpath from
http://github.com/clojure/java.classpath
Searches CLASSPATH (both directories and JAR files) for Clojure
source files containing (ns ...) declarations. Returns a sequence of
the unevaluated ns declaration forms." []
(concat
(mapcat find-ns-decls-in-dir (classpath-directories))
(mapcat find-ns-decls-in-jarfile (classpath-jarfiles))))
(defn find-namespaces-on-classpath
"DEPRECATED; use clojure.tools.namespace.find/find-namespaces
and clojure.java.classpath/classpath from
http://github.com/clojure/java.classpath
Searches CLASSPATH (both directories and JAR files) for Clojure
source files containing (ns ...) declarations. Returns a sequence
of the symbol names of the declared namespaces."
[]
(map second (find-ns-decls-on-classpath)))
tools.namespace-tools.namespace-0.2.11/src/main/clojure/clojure/tools/namespace/ 0000775 0000000 0000000 00000000000 12541067461 0027702 5 ustar 00root root 0000000 0000000 tools.namespace-tools.namespace-0.2.11/src/main/clojure/clojure/tools/namespace/dependency.clj 0000664 0000000 0000000 00000013156 12541067461 0032520 0 ustar 00root root 0000000 0000000 ;; Copyright (c) Stuart Sierra, 2012. All rights reserved. The use and
;; distribution terms for this software are covered by the Eclipse
;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this
;; distribution. By using this software in any fashion, you are
;; agreeing to be bound by the terms of this license. You must not
;; remove this notice, or any other, from this software.
(ns ^{:author "Stuart Sierra"
:doc "Bidirectional graphs of dependencies and dependent objects."}
clojure.tools.namespace.dependency
(:require [clojure.set :as set]))
(defprotocol DependencyGraph
(immediate-dependencies [graph node]
"Returns the set of immediate dependencies of node.")
(immediate-dependents [graph node]
"Returns the set of immediate dependents of node.")
(transitive-dependencies [graph node]
"Returns the set of all things which node depends on, directly or
transitively.")
(transitive-dependencies-set [graph node-set]
"Returns the set of all things which any node in node-set depends
on, directly or transitively.")
(transitive-dependents [graph node]
"Returns the set of all things which depend upon node, directly or
transitively.")
(transitive-dependents-set [graph node-set]
"Returns the set of all things which depend upon any node in
node-set, directly or transitively.")
(nodes [graph]
"Returns the set of all nodes in graph."))
(defprotocol DependencyGraphUpdate
(depend [graph node dep]
"Returns a new graph with a dependency from node to dep (\"node depends
on dep\"). Forbids circular dependencies.")
(remove-edge [graph node dep]
"Returns a new graph with the dependency from node to dep removed.")
(remove-all [graph node]
"Returns a new dependency graph with all references to node removed.")
(remove-node [graph node]
"Removes the node from the dependency graph without removing it as a
dependency of other nodes. That is, removes all outgoing edges from
node."))
(defn- remove-from-map [amap x]
(reduce (fn [m [k vs]]
(assoc m k (disj vs x)))
{} (dissoc amap x)))
(defn- transitive
"Recursively expands the set of dependency relationships starting
at (get neighbors x), for each x in node-set"
[neighbors node-set]
(loop [unexpanded (mapcat neighbors node-set)
expanded #{}]
(if-let [[node & more] (seq unexpanded)]
(if (contains? expanded node)
(recur more expanded)
(recur (concat more (neighbors node))
(conj expanded node)))
expanded)))
(declare depends?)
(def set-conj (fnil conj #{}))
(defrecord MapDependencyGraph [dependencies dependents]
DependencyGraph
(immediate-dependencies [graph node]
(get dependencies node #{}))
(immediate-dependents [graph node]
(get dependents node #{}))
(transitive-dependencies [graph node]
(transitive dependencies #{node}))
(transitive-dependencies-set [graph node-set]
(transitive dependencies node-set))
(transitive-dependents [graph node]
(transitive dependents #{node}))
(transitive-dependents-set [graph node-set]
(transitive dependents node-set))
(nodes [graph]
(clojure.set/union (set (keys dependencies))
(set (keys dependents))))
DependencyGraphUpdate
(depend [graph node dep]
(when (or (= node dep) (depends? graph dep node))
(throw (Exception. (str "Circular dependency between "
(pr-str node) " and " (pr-str dep)))))
(MapDependencyGraph.
(update-in dependencies [node] set-conj dep)
(update-in dependents [dep] set-conj node)))
(remove-edge [graph node dep]
(MapDependencyGraph.
(update-in dependencies [node] disj dep)
(update-in dependents [dep] disj node)))
(remove-all [graph node]
(MapDependencyGraph.
(remove-from-map dependencies node)
(remove-from-map dependents node)))
(remove-node [graph node]
(MapDependencyGraph.
(dissoc dependencies node)
dependents)))
(defn graph "Returns a new, empty, dependency graph." []
(->MapDependencyGraph {} {}))
(defn depends?
"True if x is directly or transitively dependent on y."
[graph x y]
(contains? (transitive-dependencies graph x) y))
(defn dependent?
"True if y is a dependent of x."
[graph x y]
(contains? (transitive-dependents graph x) y))
(defn topo-sort
"Returns a topologically-sorted list of nodes in graph."
[graph]
(loop [sorted ()
g graph
todo (set (filter #(empty? (immediate-dependents graph %))
(nodes graph)))]
(if (empty? todo)
sorted
(let [[node & more] (seq todo)
deps (immediate-dependencies g node)
[add g'] (loop [deps deps
g g
add #{}]
(if (seq deps)
(let [d (first deps)
g' (remove-edge g node d)]
(if (empty? (immediate-dependents g' d))
(recur (rest deps) g' (conj add d))
(recur (rest deps) g' add)))
[add g]))]
(recur (cons node sorted)
(remove-node g' node)
(clojure.set/union (set more) (set add)))))))
(defn topo-comparator
"Returns a comparator fn which produces a topological sort based on
the dependencies in graph. Nodes not present in the graph will sort
after nodes in the graph."
[graph]
(let [pos (zipmap (topo-sort graph) (range))]
(fn [a b]
(compare (get pos a Long/MAX_VALUE)
(get pos b Long/MAX_VALUE)))))
tools.namespace-tools.namespace-0.2.11/src/main/clojure/clojure/tools/namespace/dir.clj 0000664 0000000 0000000 00000005316 12541067461 0031157 0 ustar 00root root 0000000 0000000 ;; Copyright (c) Stuart Sierra, 2012. All rights reserved. The use and
;; distribution terms for this software are covered by the Eclipse
;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this
;; distribution. By using this software in any fashion, you are
;; agreeing to be bound by the terms of this license. You must not
;; remove this notice, or any other, from this software.
(ns ^{:author "Stuart Sierra"
:doc "Track namespace dependencies and changes by monitoring
file-modification timestamps"}
clojure.tools.namespace.dir
(:require [clojure.tools.namespace.file :as file]
[clojure.tools.namespace.track :as track]
[clojure.java.io :as io]
[clojure.set :as set]
[clojure.string :as string])
(:import (java.io File) (java.util.regex Pattern)))
(defn- find-files [dirs]
(->> dirs
(map io/file)
(filter #(.exists ^File %))
(mapcat file-seq)
(filter file/clojure-file?)
(map #(.getCanonicalFile ^File %))))
(defn- modified-files [tracker files]
(filter #(< (::time tracker 0) (.lastModified ^File %)) files))
(defn- deleted-files [tracker files]
(set/difference (::files tracker #{}) (set files)))
(defn- update-files [tracker deleted modified]
(let [now (System/currentTimeMillis)]
(-> tracker
(update-in [::files] #(if % (apply disj % deleted) #{}))
(file/remove-files deleted)
(update-in [::files] into modified)
(file/add-files modified)
(assoc ::time now))))
(defn- dirs-on-classpath []
(filter #(.isDirectory ^File %)
(map #(File. ^String %)
(string/split
(System/getProperty "java.class.path")
(Pattern/compile (Pattern/quote File/pathSeparator))))))
(defn scan
"Scans directories for files which have changed since the last time
'scan' was run; update the dependency tracker with
new/changed/deleted files.
If no dirs given, defaults to all directories on the classpath."
[tracker & dirs]
(let [ds (or (seq dirs) (dirs-on-classpath))
files (find-files ds)
deleted (seq (deleted-files tracker files))
modified (seq (modified-files tracker files))]
(if (or deleted modified)
(update-files tracker deleted modified)
tracker)))
(defn scan-all
"Scans directories for all Clojure source files and updates the
dependency tracker to reload files. If no dirs given, defaults to
all directories on the classpath."
[tracker & dirs]
(let [ds (or (seq dirs) (dirs-on-classpath))
files (find-files ds)
deleted (seq (deleted-files tracker files))]
(update-files tracker deleted files)))
tools.namespace-tools.namespace-0.2.11/src/main/clojure/clojure/tools/namespace/file.clj 0000664 0000000 0000000 00000004420 12541067461 0031313 0 ustar 00root root 0000000 0000000 ;; Copyright (c) Stuart Sierra, 2012. All rights reserved. The use and
;; distribution terms for this software are covered by the Eclipse
;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this
;; distribution. By using this software in any fashion, you are
;; agreeing to be bound by the terms of this license. You must not
;; remove this notice, or any other, from this software.
(ns ^{:author "Stuart Sierra"
:doc "Read and track namespace information from files"}
clojure.tools.namespace.file
(:require [clojure.java.io :as io]
[clojure.tools.namespace.parse :as parse]
[clojure.tools.namespace.track :as track])
(:import (java.io PushbackReader)))
(defn read-file-ns-decl
"Attempts to read a (ns ...) declaration from file, and returns the
unevaluated form. Returns nil if read fails, or if the first form
is not a ns declaration."
[file]
(with-open [rdr (PushbackReader. (io/reader file))]
(parse/read-ns-decl rdr)))
(defn clojure-file?
"Returns true if the java.io.File represents a normal Clojure source
file."
[^java.io.File file]
(and (.isFile file)
(or
(.endsWith (.getName file) ".clj")
(.endsWith (.getName file) ".cljc"))))
;;; Dependency tracker
(defn- files-and-deps [files]
(reduce (fn [m file]
(if-let [decl (read-file-ns-decl file)]
(let [deps (parse/deps-from-ns-decl decl)
name (second decl)]
(-> m
(assoc-in [:depmap name] deps)
(assoc-in [:filemap file] name)))
m))
{} files))
(def ^:private merge-map (fnil merge {}))
(defn add-files
"Reads ns declarations from files; returns an updated dependency
tracker with those files added."
[tracker files]
(let [{:keys [depmap filemap]} (files-and-deps files)]
(-> tracker
(track/add depmap)
(update-in [::filemap] merge-map filemap))))
(defn remove-files
"Returns an updated dependency tracker with files removed. The files
must have been previously added with add-files."
[tracker files]
(-> tracker
(track/remove (keep (::filemap tracker {}) files))
(update-in [::filemap] #(apply dissoc % files))))
tools.namespace-tools.namespace-0.2.11/src/main/clojure/clojure/tools/namespace/find.clj 0000664 0000000 0000000 00000011131 12541067461 0031311 0 ustar 00root root 0000000 0000000 ;; Copyright (c) Stuart Sierra, 2012. All rights reserved. The use and
;; distribution terms for this software are covered by the Eclipse
;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this
;; distribution. By using this software in any fashion, you are
;; agreeing to be bound by the terms of this license. You must not
;; remove this notice, or any other, from this software.
(ns
^{:author "Stuart Sierra",
:doc "Search for namespace declarations in directories and JAR files."}
clojure.tools.namespace.find
(:require [clojure.java.io :as io]
[clojure.set :as set]
[clojure.tools.namespace.file :as file]
[clojure.tools.namespace.parse :as parse])
(:import (java.io File FileReader BufferedReader PushbackReader
InputStreamReader)
(java.util.jar JarFile JarEntry)))
;;; JAR-file utilities, adapted from clojure.java.classpath
(defn- jar-file?
"Returns true if file is a normal file with a .jar or .JAR extension."
[f]
(let [file (io/file f)]
(and (.isFile file)
(or (.endsWith (.getName file) ".jar")
(.endsWith (.getName file) ".JAR")))))
(defn- jar-files
"Given a sequence of File objects, filters it for JAR files, returns
a sequence of java.util.jar.JarFile objects."
[files]
(map #(JarFile. ^File %) (filter jar-file? files)))
(defn- filenames-in-jar
"Returns a sequence of Strings naming the non-directory entries in
the JAR file."
[^JarFile jar-file]
(map #(.getName ^JarEntry %)
(filter #(not (.isDirectory ^JarEntry %))
(enumeration-seq (.entries jar-file)))))
;;; Finding namespaces in a directory tree
(defn find-clojure-sources-in-dir
"Searches recursively under dir for Clojure source files (.clj, .cljc).
Returns a sequence of File objects, in breadth-first sort order."
[^File dir]
;; Use sort by absolute path to get breadth-first search.
(sort-by #(.getAbsolutePath ^File %)
(filter file/clojure-file? (file-seq dir))))
(defn find-ns-decls-in-dir
"Searches dir recursively for (ns ...) declarations in Clojure
source files; returns the unevaluated ns declarations."
[^File dir]
(keep file/read-file-ns-decl (find-clojure-sources-in-dir dir)))
(defn find-namespaces-in-dir
"Searches dir recursively for (ns ...) declarations in Clojure
source files; returns the symbol names of the declared namespaces."
[^File dir]
(map second (find-ns-decls-in-dir dir)))
;;; Finding namespaces in JAR files
(defn clojure-sources-in-jar
"Returns a sequence of filenames ending in .clj or .cljc found in the JAR file."
[^JarFile jar-file]
(filter #(or (.endsWith ^String % ".clj") (.endsWith ^String % ".cljc"))
(filenames-in-jar jar-file)))
(defn read-ns-decl-from-jarfile-entry
"Attempts to read a (ns ...) declaration from the named entry in the
JAR file, and returns the unevaluated form. Returns nil if the read
fails, or if the first form is not a ns declaration."
[^JarFile jarfile ^String entry-name]
(with-open [rdr (PushbackReader.
(io/reader
(.getInputStream jarfile (.getEntry jarfile entry-name))))]
(parse/read-ns-decl rdr)))
(defn find-ns-decls-in-jarfile
"Searches the JAR file for Clojure source files containing (ns ...)
declarations; returns the unevaluated ns declarations."
[^JarFile jarfile]
(filter identity
(map #(read-ns-decl-from-jarfile-entry jarfile %)
(clojure-sources-in-jar jarfile))))
(defn find-namespaces-in-jarfile
"Searches the JAR file for Clojure source files containing (ns ...)
declarations. Returns a sequence of the symbol names of the
declared namespaces."
[^JarFile jarfile]
(map second (find-ns-decls-in-jarfile jarfile)))
;;; Finding namespaces
(defn find-ns-decls
"Searches a sequence of java.io.File objects (both directories and
JAR files) for .clj or .cljc source files containing (ns...) declarations.
Returns a sequence of the unevaluated ns declaration forms. Use with
clojure.java.classpath to search Clojure's classpath."
[files]
(concat
(mapcat find-ns-decls-in-dir (filter #(.isDirectory ^File %) files))
(mapcat find-ns-decls-in-jarfile (jar-files files))))
(defn find-namespaces
"Searches a sequence of java.io.File objects (both directories and
JAR files) for .clj or .cljc source files containing (ns...) declarations.
Returns a sequence of the symbol names of the declared
namespaces. Use with clojure.java.classpath to search Clojure's
classpath."
[files]
(map second (find-ns-decls files)))
tools.namespace-tools.namespace-0.2.11/src/main/clojure/clojure/tools/namespace/move.clj 0000664 0000000 0000000 00000007465 12541067461 0031356 0 ustar 00root root 0000000 0000000 ;; Copyright (c) Stuart Sierra, 2012. All rights reserved. The use and
;; distribution terms for this software are covered by the Eclipse
;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this
;; distribution. By using this software in any fashion, you are
;; agreeing to be bound by the terms of this license. You must not
;; remove this notice, or any other, from this software.
(ns ^{:author "Stuart Sierra"
:doc "Refactoring tool to move a Clojure namespace from one name/file to
another, and update all references to that namespace in your other
Clojure source files.
WARNING: This code is ALPHA and subject to change. It also modifies
and deletes your source files! Make sure you have a backup or
version control."}
clojure.tools.namespace.move
(:require [clojure.string :as str]
[clojure.java.io :as io])
(:import (java.io File)))
(defn- update-file
"Reads file as a string, calls f on the string plus any args, then
writes out return value of f as the new contents of file. Does not
modify file if the content is unchanged."
[file f & args]
(let [old (slurp file)
new (str (apply f old args))]
(when-not (= old new)
(spit file new))))
(defn- ns-file-name [sym]
(str (-> (name sym)
(str/replace "-" "_")
(str/replace "." File/separator))
".clj"))
(defn- clojure-source-files [dirs]
(->> dirs
(map io/file)
(filter #(.exists ^File %))
(mapcat file-seq)
(filter (fn [^File file]
(and (.isFile file)
(.endsWith (.getName file) ".clj"))))
(map #(.getCanonicalFile ^File %))))
(def ^:private symbol-regex
;; LispReader.java uses #"[:]?([\D&&[^/]].*/)?([\D&&[^/]][^/]*)" but
;; that's too broad; we don't want a whole namespace-qualified symbol,
;; just each part individually.
#"[a-zA-Z0-9$%*+=?!<>_-]['.a-zA-Z0-9$%*+=?!<>_-]*")
(defn replace-ns-symbol
"ALPHA: subject to change. Given Clojure source as a string, replaces
all occurrences of the namespace name old-sym with new-sym and
returns modified source as a string."
[source old-sym new-sym]
(let [old-name (name old-sym)
new-name (name new-sym)]
;; A lossless parser would be better, but this is adequate
(str/replace source symbol-regex
(fn [match]
(if (= match old-name)
new-name
match)))))
(defn move-ns-file
"ALPHA: subject to change. Moves the .clj source file (found relative
to source-path) for the namespace named old-sym to a file for a
namespace named new-sym.
WARNING: This function moves and deletes your source files! Make
sure you have a backup or version control."
[old-sym new-sym source-path]
(let [old-file (io/file source-path (ns-file-name old-sym))
new-file (io/file source-path (ns-file-name new-sym))]
(.mkdirs (.getParentFile new-file))
(io/copy old-file new-file)
(.delete old-file)
(loop [dir (.getParentFile old-file)]
(when (empty? (.listFiles dir))
(.delete dir)
(recur (.getParentFile dir))))))
(defn move-ns
"ALPHA: subject to change. Moves the .clj source file (found relative
to source-path) for the namespace named old-sym to new-sym and
replace all occurrences of the old name with the new name in all
Clojure source files found in dirs.
This is a purely textual transformation. It does not work on
namespaces require'd or use'd from a prefix list.
WARNING: This function modifies and deletes your source files! Make
sure you have a backup or version control."
[old-sym new-sym source-path dirs]
(move-ns-file old-sym new-sym source-path)
(doseq [file (clojure-source-files dirs)]
(update-file file replace-ns-symbol old-sym new-sym)))
tools.namespace-tools.namespace-0.2.11/src/main/clojure/clojure/tools/namespace/parse.clj 0000664 0000000 0000000 00000007076 12541067461 0031520 0 ustar 00root root 0000000 0000000 ;; Copyright (c) Stuart Sierra, 2012. All rights reserved. The use and
;; distribution terms for this software are covered by the Eclipse
;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this
;; distribution. By using this software in any fashion, you are
;; agreeing to be bound by the terms of this license. You must not
;; remove this notice, or any other, from this software.
(ns ^{:author "Stuart Sierra"
:doc "Parse Clojure namespace (ns) declarations and extract
dependencies."}
clojure.tools.namespace.parse
(:require [clojure.set :as set]))
(defn- read-clj
"Calls clojure.core/read. If reader conditionals are
supported (Clojure 1.7) then adds options {:read-cond :allow}."
[rdr]
(if (resolve 'clojure.core/reader-conditional?)
(read {:read-cond :allow} rdr)
(read rdr)))
(defn comment?
"Returns true if form is a (comment ...)"
[form]
(and (list? form) (= 'comment (first form))))
(defn ns-decl?
"Returns true if form is a (ns ...) declaration."
[form]
(and (list? form) (= 'ns (first form))))
(defn read-ns-decl
"Attempts to read a (ns ...) declaration from a
java.io.PushbackReader, and returns the unevaluated form. Returns
the first top-level ns form found. Returns nil if read fails or if a
ns declaration cannot be found. Note that read can execute code
(controlled by *read-eval*), and as such should be used only with
trusted sources."
[rdr]
{:pre [(instance? java.io.PushbackReader rdr)]}
(try
(loop []
(let [form (doto (read-clj rdr) str)] ; str forces errors, see TNS-1
(if (ns-decl? form)
form
(recur))))
(catch Exception e nil)))
;;; Parsing dependencies
(defn- prefix-spec?
"Returns true if form represents a libspec prefix list like
(prefix name1 name1) or [com.example.prefix [name1 :as name1]]"
[form]
(and (sequential? form) ; should be a list, but often is not
(symbol? (first form))
(not-any? keyword? form)
(< 1 (count form)))) ; not a bare vector like [foo]
(defn- option-spec?
"Returns true if form represents a libspec vector containing optional
keyword arguments like [namespace :as alias] or
[namespace :refer (x y)] or just [namespace]"
[form]
(and (sequential? form) ; should be a vector, but often is not
(symbol? (first form))
(or (keyword? (second form)) ; vector like [foo :as f]
(= 1 (count form))))) ; bare vector like [foo]
(defn- deps-from-libspec [prefix form]
(cond (prefix-spec? form)
(mapcat (fn [f] (deps-from-libspec
(symbol (str (when prefix (str prefix "."))
(first form)))
f))
(rest form))
(option-spec? form)
(deps-from-libspec prefix (first form))
(symbol? form)
(list (symbol (str (when prefix (str prefix ".")) form)))
(keyword? form) ; Some people write (:require ... :reload-all)
nil
:else
(throw (IllegalArgumentException.
(pr-str "Unparsable namespace form:" form)))))
(defn- deps-from-ns-form [form]
(when (and (sequential? form) ; should be list but sometimes is not
(contains? #{:use :require 'use 'require} (first form)))
(mapcat #(deps-from-libspec nil %) (rest form))))
(defn deps-from-ns-decl
"Given an (ns...) declaration form (unevaluated), returns a set of
symbols naming the dependencies of that namespace. Handles :use and
:require clauses but not :load."
[decl]
(set (mapcat deps-from-ns-form decl)))
tools.namespace-tools.namespace-0.2.11/src/main/clojure/clojure/tools/namespace/reload.clj 0000664 0000000 0000000 00000004031 12541067461 0031640 0 ustar 00root root 0000000 0000000 ;; Copyright (c) Stuart Sierra, 2012. All rights reserved. The use and
;; distribution terms for this software are covered by the Eclipse
;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this
;; distribution. By using this software in any fashion, you are
;; agreeing to be bound by the terms of this license. You must not
;; remove this notice, or any other, from this software.
(ns ^{:author "Stuart Sierra"
:doc "Force reloading namespaces on demand or through a
dependency tracker"}
clojure.tools.namespace.reload
(:require [clojure.tools.namespace.track :as track]))
(defn remove-lib
"Remove lib's namespace and remove lib from the set of loaded libs."
[lib]
(remove-ns lib)
(dosync (alter @#'clojure.core/*loaded-libs* disj lib)))
(defn track-reload-one
"Executes the next pending unload/reload operation in the dependency
tracker. Returns the updated dependency tracker. If reloading caused
an error, it is captured as ::error and the namespace which caused
the error is ::error-ns."
[tracker]
(let [{unload ::track/unload, load ::track/load} tracker]
(cond
(seq unload)
(let [n (first unload)]
(remove-lib n)
(update-in tracker [::track/unload] rest))
(seq load)
(let [n (first load)]
(try (require n :reload)
(update-in tracker [::track/load] rest)
(catch Throwable t
(assoc tracker
::error t ::error-ns n ::track/unload load))))
:else
tracker)))
(defn track-reload
"Executes all pending unload/reload operations on dependency tracker
until either an error is encountered or there are no more pending
operations."
[tracker]
(loop [tracker (dissoc tracker ::error ::error-ns)]
(let [{error ::error, unload ::track/unload, load ::track/load} tracker]
(if (and (not error)
(or (seq load) (seq unload)))
(recur (track-reload-one tracker))
tracker))))
tools.namespace-tools.namespace-0.2.11/src/main/clojure/clojure/tools/namespace/repl.clj 0000664 0000000 0000000 00000015042 12541067461 0031340 0 ustar 00root root 0000000 0000000 ;; Copyright (c) Stuart Sierra, 2012. All rights reserved. The use and
;; distribution terms for this software are covered by the Eclipse
;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this
;; distribution. By using this software in any fashion, you are
;; agreeing to be bound by the terms of this license. You must not
;; remove this notice, or any other, from this software.
(ns ^{:author "Stuart Sierra"
:doc "REPL utilities for working with namespaces"}
clojure.tools.namespace.repl
(:require [clojure.tools.namespace.track :as track]
[clojure.tools.namespace.dir :as dir]
[clojure.tools.namespace.reload :as reload]))
(defonce ^:private refresh-tracker (track/tracker))
(defonce ^:private refresh-dirs [])
(defn- print-and-return [tracker]
(if-let [e (::reload/error tracker)]
(do (when (thread-bound? #'*e)
(set! *e e))
(prn :error-while-loading (::reload/error-ns tracker))
e)
:ok))
(defn- print-pending-reloads [tracker]
(prn :reloading (::track/load tracker)))
(defn- load-disabled? [sym]
(false? (::load (meta (find-ns sym)))))
(defn- unload-disabled? [sym]
(or (false? (::unload (meta (find-ns sym))))
(load-disabled? sym)))
(defn- remove-disabled [tracker]
(-> tracker
(update-in [::track/unload] #(remove unload-disabled? %))
(update-in [::track/load] #(remove load-disabled? %))))
(defn- referred
"Given a Namespace object, returns a map of symbols describing the
Vars it refers from other namespaces, in the following form:
{other-namespace-name {symbol-in-other-ns symbol-in-this-ns}}"
[ns]
(reduce (fn [m [sym var]]
(let [ns-name (ns-name (:ns (meta var)))
var-name (:name (meta var))]
(assoc-in m [ns-name var-name] sym)))
{}
(ns-refers ns)))
(defn- aliased
"Given a namespace object, returns a map of symbols describing its
aliases, in the following form:
{alias-symbol namespace-name}"
[ns]
(reduce (fn [m [alias n]] (assoc m alias (ns-name n)))
{} (ns-aliases ns)))
(defn- recover-ns
"Given the maps returned by 'referred' and 'aliased', attempts to
restore as many bindings as possible into the current namespace. Any
bindings to namespaces or Vars which do not currently exist will be
ignored."
[refers aliases]
(doseq [[ns-name symbol-map] refers]
(when-let [ns (find-ns ns-name)]
(doseq [[source-name target-name] symbol-map]
(when (ns-resolve ns source-name)
(if (= source-name target-name)
(refer ns-name :only (list source-name))
(refer ns-name :only () :rename {source-name target-name}))))))
(doseq [[alias-sym ns-name] aliases]
(when (find-ns ns-name)
(alias alias-sym ns-name))))
(defn- do-refresh [scan-fn after-sym]
(when after-sym
(assert (symbol? after-sym) ":after value must be a symbol")
(assert (namespace after-sym)
":after value must be a namespace-qualified symbol"))
(let [current-ns-name (ns-name *ns*)
current-ns-refers (referred *ns*)
current-ns-aliases (aliased *ns*)]
(alter-var-root #'refresh-tracker
#(apply scan-fn % refresh-dirs))
(alter-var-root #'refresh-tracker remove-disabled)
(print-pending-reloads refresh-tracker)
(alter-var-root #'refresh-tracker reload/track-reload)
(in-ns current-ns-name)
(let [result (print-and-return refresh-tracker)]
(if (= :ok result)
(if after-sym
(if-let [after (ns-resolve *ns* after-sym)]
(after)
(throw (Exception.
(str "Cannot resolve :after symbol " after-sym))))
result)
;; There was an error, recover as much as we can:
(do (when-not (or (false? (::unload (meta *ns*)))
(false? (::load (meta *ns*))))
(recover-ns current-ns-refers current-ns-aliases))
;; Return the Exception to the REPL:
result)))))
(defn disable-unload!
"Adds metadata to namespace (or *ns* if unspecified) telling
'refresh' not to unload it. The namespace may still be reloaded, it
just won't be removed first.
Warning: Aliases to reloaded namespaces will break."
([] (disable-unload! *ns*))
([namespace] (alter-meta! namespace assoc ::unload false)))
(defn disable-reload!
"Adds metadata to namespace (or *ns* if unspecified) telling
'refresh' not to load it. Implies disable-unload! also.
Warning: Aliases to reloaded namespaces will break."
([] (disable-reload! *ns*))
([namespace] (alter-meta! namespace assoc ::load false)))
(defn refresh
"Scans source code directories for files which have changed (since
the last time this function was run) and reloads them in dependency
order. Returns :ok or an error; sets the latest exception to
clojure.core/*e (if *e is thread-bound).
The directories to be scanned are controlled by 'set-refresh-dirs';
defaults to all directories on the Java classpath.
Options are key-value pairs. Valid options are:
:after Namespace-qualified symbol naming a zero-argument
function to be invoked after a successful refresh. This
symbol will be resolved *after* all namespaces have
been reloaded."
[& options]
(let [{:keys [after]} options]
(do-refresh dir/scan after)))
(defn refresh-all
"Scans source code directories for all Clojure source files and
reloads them in dependency order.
The directories to be scanned are controlled by 'set-refresh-dirs';
defaults to all directories on the Java classpath.
Options are key-value pairs. Valid options are:
:after Namespace-qualified symbol naming a zero-argument
function to be invoked after a successful refresh. This
symbol will be resolved *after* all namespaces have
been reloaded."
[& options]
(let [{:keys [after]} options]
(do-refresh dir/scan-all after)))
(defn set-refresh-dirs
"Sets the directories which are scanned by 'refresh'. Supports the
same types as clojure.java.io/file."
[& dirs]
(alter-var-root #'refresh-dirs (constantly dirs)))
(defn clear
"Clears all state from the namespace/file tracker. This may help
repair the namespace tracker when it gets into an inconsistent
state, without restarting the Clojure process. The next call to
'refresh' will reload all source files, but may not completely
remove stale code from deleted files."
[]
(alter-var-root #'refresh-tracker (constantly (track/tracker))))
tools.namespace-tools.namespace-0.2.11/src/main/clojure/clojure/tools/namespace/track.clj 0000664 0000000 0000000 00000012614 12541067461 0031504 0 ustar 00root root 0000000 0000000 ;; Copyright (c) Stuart Sierra, 2012. All rights reserved. The use and
;; distribution terms for this software are covered by the Eclipse
;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;; which can be found in the file epl-v10.html at the root of this
;; distribution. By using this software in any fashion, you are
;; agreeing to be bound by the terms of this license. You must not
;; remove this notice, or any other, from this software.
(ns ^{:author "Stuart Sierra"
:doc "Dependency tracker which can compute which namespaces need to be
reloaded after files have changed. This is the low-level
implementation that requires you to find the namespace dependencies
yourself: most uses will interact with the wrappers in
clojure.tools.namespace.file and clojure.tools.namespace.dir or the
public API in clojure.tools.namespace.repl."}
clojure.tools.namespace.track
(:refer-clojure :exclude (remove))
(:require [clojure.set :as set]
[clojure.tools.namespace.dependency :as dep]))
(defn- remove-deps [deps names]
(reduce dep/remove-node deps names))
(defn- add-deps [deps depmap]
(reduce (fn [ds [name dependencies]]
(reduce (fn [g dep] (dep/depend g name dep))
ds dependencies))
deps depmap))
(defn- update-deps [deps depmap]
(-> deps
(remove-deps (keys depmap))
(add-deps depmap)))
(defn- affected-namespaces [deps names]
(set/union (set names)
(dep/transitive-dependents-set deps names)))
(defn add
"Returns an updated dependency tracker with new/updated namespaces.
Depmap is a map describing the new or modified namespaces. Keys in
the map are namespace names (symbols). Values in the map are sets of
symbols naming the direct dependencies of each namespace. For
example, assuming these ns declarations:
(ns alpha (:require beta))
(ns beta (:require gamma delta))
the depmap would look like this:
{alpha #{beta}
beta #{gamma delta}}
After adding new/updated namespaces, the dependency tracker will
have two lists associated with the following keys:
:clojure.tools.namespace.track/unload
is the list of namespaces that need to be removed
:clojure.tools.namespace.track/load
is the list of namespaces that need to be reloaded
To reload namespaces in the correct order, first remove/unload all
namespaces in the 'unload' list, then (re)load all namespaces in the
'load' list. The clojure.tools.namespace.reload namespace has
functions to do this."
[tracker depmap]
(let [{load ::load
unload ::unload
deps ::deps
:or {load (), unload (), deps (dep/graph)}} tracker
new-deps (update-deps deps depmap)
changed (affected-namespaces new-deps (keys depmap))
;; With a new tracker, old dependencies are empty, so
;; unload order will be undefined unless we use new
;; dependencies (TNS-20).
old-deps (if (empty? (dep/nodes deps)) new-deps deps)]
(assoc tracker
::deps new-deps
::unload (distinct
(concat (reverse (sort (dep/topo-comparator old-deps) changed))
unload))
::load (distinct
(concat (sort (dep/topo-comparator new-deps) changed)
load)))))
(defn remove
"Returns an updated dependency tracker from which the namespaces
(symbols) have been removed. The ::unload and ::load lists are
populated as with 'add'."
[tracker names]
(let [{load ::load
unload ::unload
deps ::deps
:or {load (), unload (), deps (dep/graph)}} tracker
known (set (dep/nodes deps))
removed-names (filter known names)
new-deps (remove-deps deps removed-names)
changed (affected-namespaces deps removed-names)]
(assoc tracker
::deps new-deps
::unload (distinct
(concat (reverse (sort (dep/topo-comparator deps) changed))
unload))
::load (distinct
(filter (complement (set removed-names))
(concat (sort (dep/topo-comparator new-deps) changed)
load))))))
(defn tracker
"Returns a new, empty dependency tracker"
[]
{})
(comment
;; Structure of the namespace tracker map
{;; Dependency graph of namespace names (symbols) as defined in
;; clojure.tools.namespace.dependency/graph
:clojure.tools.namespace.track/deps {}
;; Ordered list of namespace names (symbols) that need to be
;; removed to bring the running system into agreement with the
;; source files.
:clojure.tools.namespace.track/unload ()
;; Ordered list of namespace names (symbols) that need to be
;; (re)loaded to bring the running system into agreement with the
;; source files.
:clojure.tools.namespace.track/load ()
;; Added by clojure.tools.namespace.file: Map from source files
;; (java.io.File) to the names (symbols) of namespaces they
;; represent.
:clojure.tools.namespace.file/filemap {}
;; Added by clojure.tools.namespace.dir: Set of source files
;; (java.io.File) which have been seen by this dependency tracker;
;; used to determine when files have been deleted.
:clojure.tools.namespace.dir/files #{}
;; Added by clojure.tools.namespace.dir: Instant when the
;; directories were last scanned, as returned by
;; System/currentTimeMillis.
:clojure.tools.namespace.dir/time 1405201862262})
tools.namespace-tools.namespace-0.2.11/src/test/ 0000775 0000000 0000000 00000000000 12541067461 0021533 5 ustar 00root root 0000000 0000000 tools.namespace-tools.namespace-0.2.11/src/test/clojure/ 0000775 0000000 0000000 00000000000 12541067461 0023176 5 ustar 00root root 0000000 0000000 tools.namespace-tools.namespace-0.2.11/src/test/clojure/clojure/ 0000775 0000000 0000000 00000000000 12541067461 0024641 5 ustar 00root root 0000000 0000000 tools.namespace-tools.namespace-0.2.11/src/test/clojure/clojure/tools/ 0000775 0000000 0000000 00000000000 12541067461 0026001 5 ustar 00root root 0000000 0000000 tools.namespace-tools.namespace-0.2.11/src/test/clojure/clojure/tools/namespace/ 0000775 0000000 0000000 00000000000 12541067461 0027735 5 ustar 00root root 0000000 0000000 tools.namespace-tools.namespace-0.2.11/src/test/clojure/clojure/tools/namespace/dependency_test.clj 0000664 0000000 0000000 00000022602 12541067461 0033606 0 ustar 00root root 0000000 0000000 (ns clojure.tools.namespace.dependency-test
(:use clojure.test
clojure.tools.namespace.dependency))
;; building a graph like:
;;
;; :a
;; / |
;; :b |
;; \ |
;; :c
;; |
;; :d
;;
(def g1 (-> (graph)
(depend :b :a) ; "B depends on A"
(depend :c :b) ; "C depends on B"
(depend :c :a) ; "C depends on A"
(depend :d :c))) ; "D depends on C"
;; 'one 'five
;; | |
;; 'two |
;; / \ |
;; / \ |
;; / \ /
;; 'three 'four
;; | /
;; 'six /
;; | /
;; | /
;; | /
;; 'seven
;;
(def g2 (-> (graph)
(depend 'two 'one)
(depend 'three 'two)
(depend 'four 'two)
(depend 'four 'five)
(depend 'six 'three)
(depend 'seven 'six)
(depend 'seven 'four)))
;; :level0
;; / | | \
;; ----- | | -----
;; / | | \
;; :level1a :level1b :level1c :level1d
;; \ | | /
;; ----- | | -----
;; \ | | /
;; :level2
;; / | | \
;; ----- | | -----
;; / | | \
;; :level3a :level3b :level3c :level3d
;; \ | | /
;; ----- | | -----
;; \ | | /
;; :level4
;;
;; ... and so on in a repeating pattern like that, up to :level26
(def g3 (-> (graph)
(depend :level1a :level0)
(depend :level1b :level0)
(depend :level1c :level0)
(depend :level1d :level0)
(depend :level2 :level1a)
(depend :level2 :level1b)
(depend :level2 :level1c)
(depend :level2 :level1d)
(depend :level3a :level2)
(depend :level3b :level2)
(depend :level3c :level2)
(depend :level3d :level2)
(depend :level4 :level3a)
(depend :level4 :level3b)
(depend :level4 :level3c)
(depend :level4 :level3d)
(depend :level5a :level4)
(depend :level5b :level4)
(depend :level5c :level4)
(depend :level5d :level4)
(depend :level6 :level5a)
(depend :level6 :level5b)
(depend :level6 :level5c)
(depend :level6 :level5d)
(depend :level7a :level6)
(depend :level7b :level6)
(depend :level7c :level6)
(depend :level7d :level6)
(depend :level8 :level7a)
(depend :level8 :level7b)
(depend :level8 :level7c)
(depend :level8 :level7d)
(depend :level9a :level8)
(depend :level9b :level8)
(depend :level9c :level8)
(depend :level9d :level8)
(depend :level10 :level9a)
(depend :level10 :level9b)
(depend :level10 :level9c)
(depend :level10 :level9d)
(depend :level11a :level10)
(depend :level11b :level10)
(depend :level11c :level10)
(depend :level11d :level10)
(depend :level12 :level11a)
(depend :level12 :level11b)
(depend :level12 :level11c)
(depend :level12 :level11d)
(depend :level13a :level12)
(depend :level13b :level12)
(depend :level13c :level12)
(depend :level13d :level12)
(depend :level14 :level13a)
(depend :level14 :level13b)
(depend :level14 :level13c)
(depend :level14 :level13d)
(depend :level15a :level14)
(depend :level15b :level14)
(depend :level15c :level14)
(depend :level15d :level14)
(depend :level16 :level15a)
(depend :level16 :level15b)
(depend :level16 :level15c)
(depend :level16 :level15d)
(depend :level17a :level16)
(depend :level17b :level16)
(depend :level17c :level16)
(depend :level17d :level16)
(depend :level18 :level17a)
(depend :level18 :level17b)
(depend :level18 :level17c)
(depend :level18 :level17d)
(depend :level19a :level18)
(depend :level19b :level18)
(depend :level19c :level18)
(depend :level19d :level18)
(depend :level20 :level19a)
(depend :level20 :level19b)
(depend :level20 :level19c)
(depend :level20 :level19d)
(depend :level21a :level20)
(depend :level21b :level20)
(depend :level21c :level20)
(depend :level21d :level20)
(depend :level22 :level21a)
(depend :level22 :level21b)
(depend :level22 :level21c)
(depend :level22 :level21d)
(depend :level23a :level22)
(depend :level23b :level22)
(depend :level23c :level22)
(depend :level23d :level22)
(depend :level24 :level23a)
(depend :level24 :level23b)
(depend :level24 :level23c)
(depend :level24 :level23d)
(depend :level25a :level24)
(depend :level25b :level24)
(depend :level25c :level24)
(depend :level25d :level24)
(depend :level26 :level25a)
(depend :level26 :level25b)
(depend :level26 :level25c)
(depend :level26 :level25d)))
(deftest t-transitive-dependencies
(is (= #{:a :c :b}
(transitive-dependencies g1 :d)))
(is (= '#{two four six one five three}
(transitive-dependencies g2 'seven))))
(deftest t-transitive-dependencies-deep
(is (= #{:level0
:level1a :level1b :level1c :level1d
:level2
:level3a :level3b :level3c :level3d
:level4
:level5a :level5b :level5c :level5d
:level6
:level7a :level7b :level7c :level7d
:level8
:level9a :level9b :level9c :level9d
:level10
:level11a :level11b :level11c :level11d
:level12
:level13a :level13b :level13c :level13d
:level14
:level15a :level15b :level15c :level15d
:level16
:level17a :level17b :level17c :level17d
:level18
:level19a :level19b :level19c :level19d
:level20
:level21a :level21b :level21c :level21d
:level22
:level23a :level23b :level23c :level23d}
(transitive-dependencies g3 :level24)))
(is (= #{:level0
:level1a :level1b :level1c :level1d
:level2
:level3a :level3b :level3c :level3d
:level4
:level5a :level5b :level5c :level5d
:level6
:level7a :level7b :level7c :level7d
:level8
:level9a :level9b :level9c :level9d
:level10
:level11a :level11b :level11c :level11d
:level12
:level13a :level13b :level13c :level13d
:level14
:level15a :level15b :level15c :level15d
:level16
:level17a :level17b :level17c :level17d
:level18
:level19a :level19b :level19c :level19d
:level20
:level21a :level21b :level21c :level21d
:level22
:level23a :level23b :level23c :level23d
:level24
:level25a :level25b :level25c :level25d}
(transitive-dependencies g3 :level26))))
(deftest t-transitive-dependents
(is (= '#{four seven}
(transitive-dependents g2 'five)))
(is (= '#{four seven six three}
(transitive-dependents g2 'two))))
(defn- before?
"True if x comes before y in an ordered collection."
[coll x y]
(loop [[item & more] (seq coll)]
(cond (nil? item) true ; end of the seq
(= x item) true ; x comes first
(= y item) false
:else (recur more))))
(deftest t-before
(is (true? (before? [:a :b :c :d] :a :b)))
(is (true? (before? [:a :b :c :d] :b :c)))
(is (false? (before? [:a :b :c :d] :d :c)))
(is (false? (before? [:a :b :c :d] :c :a))))
(deftest t-topo-comparator-1
(let [sorted (sort (topo-comparator g1) [:d :a :b :foo])]
(are [x y] (before? sorted x y)
:a :b
:a :d
:a :foo
:b :d
:b :foo
:d :foo)))
(deftest t-topo-comparator-2
(let [sorted (sort (topo-comparator g2) '[three seven nine eight five])]
(are [x y] (before? sorted x y)
'three 'seven
'three 'eight
'three 'nine
'five 'eight
'five 'nine
'seven 'eight
'seven 'nine)))
(deftest t-topo-sort
(let [sorted (topo-sort g2)]
(are [x y] (before? sorted x y)
'one 'two
'one 'three
'one 'four
'one 'six
'one 'seven
'two 'three
'two 'four
'two 'six
'two 'seven
'three 'six
'three 'seven
'four 'seven
'five 'four
'five 'seven
'six 'seven)))
(deftest t-no-cycles
(is (thrown? Exception
(-> (graph)
(depend :a :b)
(depend :b :c)
(depend :c :a)))))
(deftest t-no-self-cycles
(is (thrown? Exception
(-> (graph)
(depend :a :b)
(depend :a :a)))))
tools.namespace-tools.namespace-0.2.11/src/test/clojure/clojure/tools/namespace/move_test.clj 0000664 0000000 0000000 00000004560 12541067461 0032441 0 ustar 00root root 0000000 0000000 (ns clojure.tools.namespace.move-test
(:use [clojure.java.io :as io]
[clojure.test :only (deftest is)]
[clojure.tools.namespace.move :only (move-ns)])
(:import (java.io File)))
(defn- create-temp-dir
"Creates and returns a new temporary directory java.io.File."
[name]
(let [temp-file (File/createTempFile name nil)]
(.delete temp-file)
(.mkdirs temp-file)
temp-file))
(def ^:private file-one-contents "
(ns com.example.one
(:require [com.example.two :as two]
[com.example.three :as three]))
(defn foo []
(com.example.a.four/foo))
")
(def ^:private file-two-contents "
(ns com.example.two
(:require [com.example.three :as three]
[com.example.a.four :as four]))
")
(def ^:private file-three-contents "
(ns com.example.three
(:use com.example.five))
")
(def ^:private file-four-contents "
(ns com.example.a.four)
(defn foo [] \"foo\")
")
(deftest t-move-ns
(let [temp-dir (create-temp-dir "tools-namespace-t-move-ns")
src-dir (io/file temp-dir "src")
example-dir (io/file temp-dir "src" "com" "example")
file-one (io/file example-dir "one.clj")
file-two (io/file example-dir "two.clj")
file-three (io/file example-dir "three.clj")
old-file-four (io/file example-dir "a" "four.clj")
new-file-four (io/file example-dir "b" "four.clj")]
(.mkdirs (io/file example-dir "a"))
(spit file-one file-one-contents)
(spit file-two file-two-contents)
(spit file-three file-three-contents)
(spit old-file-four file-four-contents)
(Thread/sleep 1500) ;; ensure file timestamps are different
(let [file-three-last-modified (.lastModified file-three)]
(move-ns 'com.example.a.four 'com.example.b.four src-dir [src-dir])
(is (.exists new-file-four)
"new file should exist")
(is (not (.exists old-file-four))
"old file should not exist")
(is (not (.exists (.getParentFile old-file-four)))
"old empty directory should not exist")
(is (= file-three-last-modified (.lastModified file-three))
"unaffected file should not have been modified")
(is (not-any? #(.contains (slurp %) "com.example.a.four")
[file-one file-two file-three new-file-four]))
(is (every? #(.contains (slurp %) "com.example.b.four")
[file-one file-two new-file-four])))))
tools.namespace-tools.namespace-0.2.11/src/test/clojure/clojure/tools/namespace/parse_test.clj 0000664 0000000 0000000 00000012650 12541067461 0032604 0 ustar 00root root 0000000 0000000 (ns clojure.tools.namespace.parse-test
(:use [clojure.test :only (deftest is)]
[clojure.tools.namespace.parse :only (deps-from-ns-decl
read-ns-decl)]))
(def ns-decl-prefix-list
'(ns com.example.one
(:require (com.example two
[three :as three]
[four :refer (a b)])
(com.example.sub [five :as five]
six))
(:use (com.example seven
[eight :as eight]
(nine :only (c d))
[ten]))))
;; Some people like to write prefix lists as vectors, not lists. The
;; use/require functions accept this form.
(def ns-decl-prefix-list-as-vector
'(ns com.example.one
(:require [com.example
two
[three :as three]
[four :refer (a b)]]
[com.example.sub
[five :as five]
six])
(:use [com.example
seven
[eight :as eight]
(nine :only (c d))
[ten]])))
(def ns-decl-prefix-list-clauses-as-vectors
"Sometimes people even write the clauses inside ns as vectors, which
clojure.core/ns allows. See TNS-21."
'(ns com.example.one
[:require [com.example
two
[three :as three]
[four :refer (a b)]]
[com.example.sub
[five :as five]
six]]
[:use [com.example
seven
[eight :as eight]
(nine :only (c d))
[ten]]]))
(def deps-from-prefix-list
'#{com.example.two
com.example.three
com.example.four
com.example.sub.five
com.example.sub.six
com.example.seven
com.example.eight
com.example.nine
com.example.ten})
(deftest t-prefix-list
(is (= deps-from-prefix-list
(deps-from-ns-decl ns-decl-prefix-list))))
(deftest t-prefix-list-as-vector
(is (= deps-from-prefix-list
(deps-from-ns-decl ns-decl-prefix-list-as-vector))))
(deftest t-prefix-list-clauses-as-vectors
(is (= deps-from-prefix-list
(deps-from-ns-decl ns-decl-prefix-list-clauses-as-vectors))))
(deftest t-no-deps-returns-empty-set
(is (= #{} (deps-from-ns-decl '(ns com.example.one)))))
(def multiple-ns-decls
'((ns one)
(ns two (:require one))
(ns three (:require [one :as o] [two :as t]))))
(def multiple-ns-decls-string
" (println \"Code before first ns\")
(ns one)
(println \"Some code\")
(defn hello-world [] \"Hello, World!\")
(ns two (:require one))
(println \"Some more code\")
(ns three (:require [one :as o] [two :as t]))")
(deftest t-read-multiple-ns-decls
(with-open [rdr (java.io.PushbackReader.
(java.io.StringReader. multiple-ns-decls-string))]
(is (= multiple-ns-decls
(take-while identity (repeatedly #(read-ns-decl rdr)))))))
(def ns-docstring-example
"The example ns declaration used in the docstring of clojure.core/ns"
'(ns foo.bar
(:refer-clojure :exclude [ancestors printf])
(:require (clojure.contrib sql combinatorics))
(:use (my.lib this that))
(:import (java.util Date Timer Random)
(java.sql Connection Statement))))
(def deps-from-ns-docstring-example
'#{clojure.contrib.sql
clojure.contrib.combinatorics
my.lib.this
my.lib.that})
(deftest t-ns-docstring-example
(is (= deps-from-ns-docstring-example
(deps-from-ns-decl ns-docstring-example))))
(def require-docstring-example
"The example ns declaration used in the docstring of
clojure.core/require"
'(ns (:require (clojure zip [set :as s]))))
(def deps-from-require-docstring-example
'#{clojure.zip
clojure.set})
(deftest t-require-docstring-example
(is (= deps-from-require-docstring-example
(deps-from-ns-decl require-docstring-example))))
(def multiple-clauses
"Example showing more than one :require or :use clause in one ns
declaration, which clojure.core/ns allows."
'(ns foo.bar
(:require com.example.one)
(:import java.io.File)
(:require (com.example two three))
(:use (com.example [four :only [x]]))
(:use (com.example (five :only [x])))))
(def deps-from-multiple-clauses
'#{com.example.one
com.example.two
com.example.three
com.example.four
com.example.five})
(deftest t-deps-from-multiple-clauses
(is (= deps-from-multiple-clauses
(deps-from-ns-decl multiple-clauses))))
(def clauses-without-keywords
"Example of require/use clauses with symbols instead of keywords,
which clojure.core/ns allows."
'(ns foo.bar
(require com.example.one)
(import java.io.File)
(use (com.example (prefixes (two :only [x])
three)))))
(def deps-from-clauses-without-keywords
'#{com.example.one
com.example.prefixes.two
com.example.prefixes.three})
(deftest t-clauses-without-keywords
(is (= deps-from-clauses-without-keywords
(deps-from-ns-decl clauses-without-keywords))))
(def reader-conditionals-string
"(ns com.examples.one
(:require #?(:clj clojure.string
:cljs goog.string)))")
(deftest t-reader-conditionals
(when (resolve 'clojure.core/reader-conditional?)
(let [actual (-> reader-conditionals-string
java.io.StringReader.
java.io.PushbackReader.
read-ns-decl
deps-from-ns-decl)]
(is (= #{'clojure.string} actual)))))