diff options
author | scgilardi <scgilardi@gmail.com> | 2008-05-07 01:59:20 +0000 |
---|---|---|
committer | scgilardi <scgilardi@gmail.com> | 2008-05-07 01:59:20 +0000 |
commit | 23b1910648f9e1a32f40bb6207fbd67070c7e5ce (patch) | |
tree | e4999d7b970642c89bc470f16a7440427940db86 | |
parent | 30b0f082297a861d8ee8d6f0eae4ced68433b95a (diff) |
lib.clj: added :ns option to specify a namespace explicitly, refined documentation
-rw-r--r-- | lib.clj | 151 |
1 files changed, 93 insertions, 58 deletions
@@ -6,80 +6,111 @@ ;; the terms of this license. ;; You must not remove this notice, or any other, from this software. ;; -;; lib.clj +;; File: lib.clj ;; -;; A 'lib' is a unit of Clojure code contained in a file that follows -;; these conventions: +;; lib.clj provides facilities for loading and managing libs. A lib is +;; is a unit of Clojure code contained in a file or other resource within +;; classpath. The name of the lib's container is the lib's name followed +;; by ".clj". A lib's name must be a valid Clojure symbol name. ;; -;; - has a basename that is a valid symbol name in Clojure -;; - has the extension ".clj" +;; A lib will typically contain useful functions, macros, and other vars. ;; -;; A lib's name is the basename of its implementation file. +;; Core ;; -;; A lib will typically contain forms that provide something useful for -;; a Clojure program to use. It may also define a namespace which shares -;; its name. +;; Function: load-libs +;; +;; load-libs is the core function provided by lib.clj. Its arguments are +;; libspecs and flags. It uses libspecs to find lib containers and flags +;; to control how the libs are loaded. In an explicit call to load-libs +;; libspecs must be quoted. This requirement is relaxed by the 'require' +;; and 'use' macros described below. ;; ;; Libspecs ;; -;; A lib is specified by a libspec which is either a lib name or a seq -;; beginning with a lib name and followed by zero or more options -;; expressed as sequential keywords and values. The options may include -;; any of the filters documented for clojure/refer or the :in option which -;; specifies the path to the lib's parent directory relative to one of the -;; classpath roots. +;; A libspec is either a lib name or a list beginning with the lib name +;; and followed by zero or more options. +;; +;; Options +;; +;; Options in a libspec are keywords followed by values. These are the +;; options supported by load-libs and the kind of value each expects: +;; +;; :in a string specifying the path to the parent directory +;; of the lib's container relative to one of the +;; directories in classpath +;; :ns a symbol specifying a namespace for the lib. If :ns +;; is not present, its value defaults to the lib's name. +;; See the :use flag below. +;; :exclude a list as documented for clojure/refer +;; :only a list as documented for clojure/refer +;; :rename a map as documented for clojure/refer ;; ;; Flags ;; -;; Several flags are available to control the loading of libs: +;; Flags apply to all the libs specified in a single call to load-libs. +;; These are the flags supported by load-libs: ;; ;; :require indicates that already loaded libs need not be reloaded ;; :use triggers a call to clojure/refer for each lib's namespace -;; after ensuring the lib is loaded +;; after ensuring the lib is loaded. The call to refer +;; includes any filter options in the libspec. ;; :reload forces reloading of libs that are already loaded ;; :reload-all implies :reload and also forces reloading of all libs ;; on which each lib directly or indirectly depends ;; :verbose triggers printing a message each time a lib is loaded ;; -;; The :reload and :reload-all flags supersede :require. +;; (The :reload and :reload-all flags supersede :require.) ;; -;; Examples +;; Function: libs ;; -;; (require sql) -;; (require (test :in "private/resources")) -;; (use sql ns-utils :verbose) -;; (use :reload-all :verbose -;; (sql :exclude (get-connection) :rename {execute-commands do-commands}) -;; ns-utils) -;; (use (sql)) +;; The libs function returns a sorted seq of symbols naming the currently +;; loaded libs. ;; -;; lib.clj provides the following functions and macros: +;; Convenience ;; -;; Foundation +;; lib.clj provides two convenience macros to make calls to load-libs +;; easier to write and read. Libspecs in calls to these macros do not +;; need to be quoted. ;; -;; 'load-libs' searches classpath for libs and loads them -;; based on libspecs and flags +;; Macro: require ;; -;; 'libs' returns a sorted sequence of symbols naming -;; loaded libs +;; The require macro accepts libspecs and flags and ensures that the +;; specified libs are loaded. By default, require will not reload a lib +;; that is already loaded. ;; -;; Dependency Management +;; Macro: use ;; -;; 'require' searches classpath for libs and loads them -;; if they are not already loaded (macro) +;; The use macro accepts libspecs and flags and first requires the libs +;; and then refers to each lib's namespace using any filter options present +;; in its libspec. ;; -;; 'use' requires libs and refers to their namespaces -;; with options (macro) +;; Examples +;; +;; (load-libs :require 'sql '(test :in "private/resources")) +;; (require sql (test :in "private/resources")) +;; +;; (load-libs :require :use 'sql 'ns-utils :verbose) +;; (use sql ns-utils :verbose) +;; +;; (use :reload-all :verbose +;; (sql :exclude (get-connection) :rename {execute-commands do-commands}) +;; ns-utils) +;; (use (sql)) +;; +;; (use (genclass :ns clojure)) ;; ;; Loading ;; +;; lib.clj provides these functions for loading arbitrary Clojure source +;; files: +;; ;; 'load-uri' loads Clojure source from a location ;; ;; 'load-system-resource' loads Clojure source from a resource in ;; classpath ;; ;; scgilardi (gmail) -;; 23 April 2008 +;; 06 May 2008 ;; ;; Thanks to Stuart Sierra for providing many useful ideas, discussions ;; and code contributions for lib.clj. @@ -92,7 +123,7 @@ ;; Private (defmacro init-once - "Initializes a var exactly once. The var must already exist." + "Initializes a var exactly once. The var must already exist." {:private true} [var init] `(let [v# (resolve '~var)] @@ -114,13 +145,14 @@ (def load-system-resource) (defn- load-lib - "Loads a lib from <classpath>/in/" - [sym in need-ns] + "Loads a lib from <classpath>/in/ and ensures the namespace + named by ns (if any) exists" + [sym in ns] (let [res (str sym ".clj")] (load-system-resource res in) - (when (and need-ns (not (find-ns sym))) + (when (and ns (not (find-ns ns))) (throw (new Exception - (str "namespace '" sym "' not found after " + (str "namespace '" ns "' not found after " "loading resource '" res "'"))))) (dosync (commute *libs* conj sym)) @@ -130,11 +162,11 @@ (defn- load-all "Loads a lib from <classpath>/in/ and forces a load of any libs on which it directly or indirectly depends" - [sym in need-ns] + [sym in ns] (dosync (commute *libs* set/union (binding [*libs* (ref #{})] - (load-lib sym in need-ns) + (load-lib sym in ns) @*libs*)))) (defn- load-with-options @@ -143,19 +175,21 @@ [sym & options] (let [opts (apply hash-map options) in (:in opts) + ns (:ns opts) reload (:reload opts) reload-all (:reload-all opts) require (:require opts) use (:use opts) verbose (:verbose opts) - loaded (contains? @*libs* sym)] + loaded (contains? @*libs* sym) + namespace (and use (or ns sym))] (binding [*verbose* (or *verbose* verbose)] (cond reload-all - (load-all sym in use) + (load-all sym in namespace) (or reload (not require) (not loaded)) - (load-lib sym in use))) - (when use - (apply refer sym options)))) + (load-lib sym in namespace))) + (when namespace + (apply refer namespace options)))) (defn- remove-quote "If form is a 'quote' special form, return the unquoted value @@ -166,7 +200,7 @@ (= 2 (count form))) (second form) form)) -;; Foundation +;; Core (defn load-libs "Searches classpath for libs and loads them based on libspecs @@ -181,17 +215,16 @@ flags (filter keyword? args) options (interleave flags (repeat true))] (doseq libspec libspecs - (let [libspec (remove-quote libspec)] - (apply load-with-options - ((if (symbol? libspec) cons concat) - libspec options)))))) + (let [libspec (remove-quote libspec) + combine (if (symbol? libspec) cons concat)] + (apply load-with-options (combine libspec options)))))) (defn libs "Returns a sorted sequence of symbols naming loaded libs" [] (sort @*libs*)) -;; Dependency Management +;; Convenience (defmacro require "Searches classpath for libs and loads them if they are not @@ -218,7 +251,9 @@ (defmacro use "Requires and refers to the named libs (see clojure/refer). Arguments are like those of 'lib/require', except that libspecs - can contain additional options which are filters for refer." + can contain an :ns option specifying a namespace to refer to + (ns defaults to the lib's name) and additional options which + are filters for clojure/refer." [& args] `(apply load-libs :require :use '~args)) @@ -226,7 +261,7 @@ (defn load-uri "Loads Clojure source from a URI, which may be a java.net.URI - java.net.URL, or String. Accepts any URI scheme supported by + java.net.URL, or String. Accepts any URI scheme supported by java.net.URLConnection (http and jar), plus file URIs." [uri] (let [url (cond ; coerce argument into java.net.URL |