Well, not quite. (require "foo" "bar") will dynamically reload
foo.clj and bar.clj, but not the files that are 'require'd by those
files. But you could force reloading of dependencies like this:
(binding [require/*required* (ref (list))] (require "foo" "bar"))
Maybe "require!" should work that way.
(def
#^{:doc "The set of symbols representing provided packages."
:private true}
*packages* (ref #{}))
[...]
(defn require!
"Like 'require' but will reload packages (and their dependencies)
that have already been loaded."
[package & filters]
(let [global-packages *packages*]
(binding [*packages* (ref #{})]
(apply require package filters)
(dosync
(commute global-packages set/union @*packages*)))
nil))
(defn require
"Loads package if it's not previously provided. If the
implementation file called provide and defined a namespace of the
same name, refer to that namespace with filters."
[package & filters]
(when-not (provided? package)
(load-package package))
(when (and (provided? package) (find-ns package))
(apply refer package filters)))
I hadn't posted it all. Here's what I have currently. Thanks for
taking a look.
--Steve
; pkg.clj
;
; Clojure source file implementation loading and dependency via
; require/provide. Packages are represented by symbols.
;
; (load-package copied from Stuart Sierra's public domain require.clj)
;
; scgilardi (gmail)
; 30 March 2008
;
; Copyright (c) Stephen C. Gilardi. All rights reserved.
; The use and distribution terms for this software are covered by the
; Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
; which can be found in the file CPL.TXT at the root of the Clojure
; 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.
(clojure/in-ns 'pkg)
(clojure/refer 'clojure)
;; Private
(def
#^{:doc "The set of symbols representing provided packages."
:private true}
*packages* (ref #{}))
(defn- load-package
"Load a package implementation file from within CLASSPATH"
[package]
(let [full-name (str package ".clj")
url (. ClassLoader (getSystemResource full-name))]
(when-not url
(throw (new Exception (str "require: Cannot find \"" full-name
"\" in CLASSPATH."))))
(if (= "file" (. url (getProtocol)))
(load-file (. url (getFile)))
(with-open reader (new java.io.BufferedReader
(new java.io.InputStreamReader
(. url (openStream))))
(load reader)))
(println "loaded" package)))
;; Public
(defn packages
"Returns the set of symbols representing provided packages."
[]
@*packages*)
(defn provided?
"Returns true if package has been provided, else false."
[package]
(contains? @*packages* package))
(defn require
"Load packages if they have not already been marked as provided."
[& packages]
(doseq package packages
(when-not (provided? package)
(load-package package))
(when-not (provided? package)
(throw (new Exception
(str "\"" package ".clj\" did not provide "
package))))))
(defn require!
"Like 'require' but will reload packages (and their dependencies)
that have already been loaded."
[& packages]
(dosync
(commute *packages* set/union
(binding [*packages* (ref #{})]
(apply require packages)
@*packages*)))
nil)
(defn require-ns
"Requires a package and then refers to the namespace of the same
name with filters"
[package & filters]
(require package)
(apply refer package filters))
(defn require-ns!
"Like 'require-ns' but will reload packages (and their dependencies)
that have already been loaded."
[package & filters]
(dosync
(commute *packages* set/union
(binding [*packages* (ref #{})]
(apply require-ns package filters)
@*packages*)))
nil)
(defn provide
"Marks a package as provided."
[package]
(dosync
(commute *packages* conj package)
nil))
(provide 'pkg)