blob: 9504872b67dd3715f03d27620a6c2826e9070e7c (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
|
;; 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 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.
;;
;; pkg.clj
;;
;; Clojure package loading and dependency via require/provide.
;;
;; A 'package' is a named set of capabilities represented by a symbol.
;; Its capabilities are expected to be defined in an implementation
;; file somewhere in CLASSPATH whose name is the package name followed
;; by ".clj". The implementation file may be in the filesystem, in a
;; jar file, or at any other valid CLASSPATH URL.
;;
;; A call to 'require' indicates that subsequent code depends on
;; capabilities provided by one or more packages and loads any of those
;; packages that have not already been provided.
;;
;; A call to 'provide' indicates that a package's capabilities have been
;; successfully loaded. A package's implementation file will generally
;; end with a call to provide.
;;
;; pkg.clj provides variations of 'require' that:
;;
;; - require a package and automatically 'refer' to a namespace of the
;; same name. This is for the common case of a package defining its
;; own namespace which dependent code wants to use without namespace
;; qualifiers. 'require-ns'
;;
;; - force the loading of all packages and dependencies regardless of
;; whether they have already been provided. 'require-force'
;;
;; - both refer to the package's namespace and force a reload of the
;; the package and its dependencies. 'require-ns-force'
;;
;; The "force" variations are useful during development.
;;
;; 'provide' is made available as a separate function (in addition to
;; being done automatically after loading an implementation file) to allow
;; flexibility in providing a package's capabilities by some means other
;; than loading an implementation file using 'require'.
;;
;; scgilardi (gmail)
;; 2 April 2008
;;
;; load-resource adapted from Stuart Sierra's public domain require.clj
(clojure/in-ns 'pkg)
(clojure/refer 'clojure)
;; Private
(def
#^{:doc "A ref to a set of symbols representing provided packages"
:private true}
*packages* (ref #{}))
(defn- load-resource
"Sequentially read and evaluate forms from a resource within CLASSPATH"
[name]
(let [url (. ClassLoader (getSystemResource name))]
(when-not url
(throw (new Exception (str \" name \" " not found 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)))))
;; Public
(defn packages
"Returns a set of symbols representing provided packages"
[]
@*packages*)
(defn provided?
"Returns true if package has been provided, else false"
[package]
(contains? @*packages* package))
(defn provide
"Marks a package as provided"
[package]
(dosync
(commute *packages* conj package)
nil))
(defn require
"Indicates that subsequent code depends on capabilities provided by
the specified packages. Loads any of those packages that have not
yet been provided."
[& packages]
(doseq package packages
(when-not (provided? package)
(let [resource (str package ".clj")]
(load-resource resource)
(provide package)))))
(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-force
"Like 'require' but will reload packages (and their dependencies) that
have already been provided"
[& packages]
(let [forced-packages
(binding [*packages* (ref #{})]
(apply require packages)
@*packages*)]
(dosync
(commute *packages* set/union forced-packages)))
nil)
(defn require-ns-force
"Like 'require-ns' but will reload packages (and their dependencies)
that have already been provided"
[package & filters]
(require-force package)
(apply refer package filters))
(provide 'pkg)
|