Skip to content
Newer
Older
100644 166 lines (138 sloc) 6.01 KB
6fbff40 @stuartsierra Add REPL helpers namespace
stuartsierra authored Aug 3, 2012
1 ;; Copyright (c) Stuart Sierra, 2012. All rights reserved. The use and
2 ;; distribution terms for this software are covered by the Eclipse
3 ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 ;; which can be found in the file epl-v10.html at the root of this
5 ;; distribution. By using this software in any fashion, you are
6 ;; agreeing to be bound by the terms of this license. You must not
7 ;; remove this notice, or any other, from this software.
8
9 (ns ^{:author "Stuart Sierra"
10 :doc "REPL utilities for working with namespaces"}
11 clojure.tools.namespace.repl
12 (:require [clojure.tools.namespace.track :as track]
13 [clojure.tools.namespace.dir :as dir]
14 [clojure.tools.namespace.reload :as reload]))
15
16 (defonce ^:private refresh-tracker (track/tracker))
17
18 (defonce ^:private refresh-dirs [])
19
20 (defn- print-and-return [tracker]
21 (if-let [e (::reload/error tracker)]
22 (do (when (thread-bound? #'*e)
23 (set! *e e))
24 (prn :error-while-loading (::reload/error-ns tracker))
25 e)
26 :ok))
27
92af6b6 @stuartsierra Improve REPL experience; add disable-load/unload
stuartsierra authored Aug 10, 2012
28 (defn- print-pending-reloads [tracker]
29 (prn :reloading (::track/load tracker)))
30
31 (defn- load-disabled? [sym]
32 (false? (::load (meta (find-ns sym)))))
33
34 (defn- unload-disabled? [sym]
35 (or (false? (::unload (meta (find-ns sym))))
36 (load-disabled? sym)))
37
38 (defn- remove-disabled [tracker]
39 (-> tracker
40 (update-in [::track/unload] #(remove unload-disabled? %))
41 (update-in [::track/load] #(remove load-disabled? %))))
42
6723baf @stuartsierra Attempt partial recovery of REPL namespace on error
stuartsierra authored Feb 22, 2013
43 (defn- referred
44 "Given a Namespace object, returns a map of symbols describing the
45 Vars it refers from other namespaces, in the following form:
46
47 {other-namespace-name {symbol-in-other-ns symbol-in-this-ns}}"
48 [ns]
49 (reduce (fn [m [sym var]]
50 (let [ns-name (ns-name (:ns (meta var)))
51 var-name (:name (meta var))]
52 (assoc-in m [ns-name var-name] sym)))
53 {}
54 (ns-refers ns)))
55
56 (defn- aliased
57 "Given a namespace object, returns a map of symbols describing its
58 aliases, in the following form:
59
60 {alias-symbol namespace-name}"
61 [ns]
62 (reduce (fn [m [alias n]] (assoc m alias (ns-name n)))
63 {} (ns-aliases ns)))
64
65 (defn- recover-ns
66 "Given the maps returned by 'referred' and 'aliased', attempts to
67 restore as many bindings as possible into the current namespace. Any
68 bindings to namespaces or Vars which do not currently exist will be
69 ignored."
70 [refers aliases]
71 (doseq [[ns-name symbol-map] refers]
72 (when-let [ns (find-ns ns-name)]
73 (doseq [[source-name target-name] symbol-map]
74 (when (ns-resolve ns source-name)
75 (if (= source-name target-name)
76 (refer ns-name :only (list source-name))
77 (refer ns-name :only () :rename {source-name target-name}))))))
78 (doseq [[alias ns-name] aliases]
79 (when (find-ns ns-name)
80 (alias alias ns-name))))
81
a544efc @stuartsierra Add :after option to c.t.n.repl/refresh
stuartsierra authored Nov 27, 2012
82 (defn- do-refresh [scan-fn after-sym]
6831271 @stuartsierra Fix arguments & support :after in refresh-all
stuartsierra authored Dec 4, 2012
83 (when after-sym
84 (assert (symbol? after-sym) ":after value must be a symbol")
85 (assert (namespace after-sym)
86 ":after value must be a namespace-qualified symbol"))
6723baf @stuartsierra Attempt partial recovery of REPL namespace on error
stuartsierra authored Feb 22, 2013
87 (let [current-ns-name (ns-name *ns*)
88 current-ns-refers (referred *ns*)
89 current-ns-aliases (aliased *ns*)]
bc9d5c1 @stuartsierra TNS-3: Actually use 'refresh-dirs' in 'refresh'
stuartsierra authored Oct 8, 2012
90 (alter-var-root #'refresh-tracker
91 #(apply scan-fn % refresh-dirs))
96f05e7 @stuartsierra Do in-ns before returning to get proper return value
stuartsierra authored Sep 18, 2012
92 (alter-var-root #'refresh-tracker remove-disabled)
93 (print-pending-reloads refresh-tracker)
94 (alter-var-root #'refresh-tracker reload/track-reload)
6723baf @stuartsierra Attempt partial recovery of REPL namespace on error
stuartsierra authored Feb 22, 2013
95 (in-ns current-ns-name)
a544efc @stuartsierra Add :after option to c.t.n.repl/refresh
stuartsierra authored Nov 28, 2012
96 (let [result (print-and-return refresh-tracker)]
6723baf @stuartsierra Attempt partial recovery of REPL namespace on error
stuartsierra authored Feb 22, 2013
97 (if (= :ok result)
98 (if after-sym
99 ((ns-resolve *ns* after-sym))
100 result)
101 ;; There was an error, recover as much as we can:
52aa183 @stuartsierra Don't try to recover namespace with unloading disabled
stuartsierra authored Mar 19, 2013
102 (do (when-not (or (false? (::unload (meta *ns*)))
103 (false? (::load (meta *ns*))))
104 (recover-ns current-ns-refers current-ns-aliases))
6723baf @stuartsierra Attempt partial recovery of REPL namespace on error
stuartsierra authored Feb 22, 2013
105 ;; Return the Exception to the REPL:
106 result)))))
92af6b6 @stuartsierra Improve REPL experience; add disable-load/unload
stuartsierra authored Aug 10, 2012
107
108 (defn disable-unload!
109 "Adds metadata to namespace (or *ns* if unspecified) telling
110 'refresh' not to unload it. The namespace may still be reloaded, it
37dae6b @stuartsierra Warn about breaking alaises in disable-unload/reload docstring
stuartsierra authored Mar 19, 2013
111 just won't be removed first.
112
113 Warning: Aliases to reloaded namespaces will break."
92af6b6 @stuartsierra Improve REPL experience; add disable-load/unload
stuartsierra authored Aug 10, 2012
114 ([] (disable-unload! *ns*))
115 ([namespace] (alter-meta! namespace assoc ::unload false)))
116
117 (defn disable-reload!
118 "Adds metadata to namespace (or *ns* if unspecified) telling
37dae6b @stuartsierra Warn about breaking alaises in disable-unload/reload docstring
stuartsierra authored Mar 19, 2013
119 'refresh' not to load it. Implies disable-unload! also.
120
121 Warning: Aliases to reloaded namespaces will break."
92af6b6 @stuartsierra Improve REPL experience; add disable-load/unload
stuartsierra authored Aug 10, 2012
122 ([] (disable-reload! *ns*))
123 ([namespace] (alter-meta! namespace assoc ::load false)))
7ff4f96 @stuartsierra Attempt to keep REPL namespace even if it gets reloaded
stuartsierra authored Aug 3, 2012
124
6fbff40 @stuartsierra Add REPL helpers namespace
stuartsierra authored Aug 3, 2012
125 (defn refresh
126 "Scans source code directories for files which have changed (since
127 the last time this function was run) and reloads them in dependency
128 order. Returns :ok or an error; sets the latest exception to
129 clojure.core/*e (if *e is thread-bound).
130
131 The directories to be scanned are controlled by 'set-refresh-dirs';
a544efc @stuartsierra Add :after option to c.t.n.repl/refresh
stuartsierra authored Nov 28, 2012
132 defaults to all directories on the Java classpath.
133
134 Options are key-value pairs. Valid options are:
135
136 :after Namespace-qualified symbol naming a zero-argument
137 function to be invoked after a successful refresh. This
138 symbol will be resolved *after* all namespaces have
139 been reloaded."
140 [& options]
141 (let [{:keys [after]} options]
142 (do-refresh dir/scan after)))
6fbff40 @stuartsierra Add REPL helpers namespace
stuartsierra authored Aug 3, 2012
143
144 (defn refresh-all
145 "Scans source code directories for all Clojure source files and
146 reloads them in dependency order.
147
148 The directories to be scanned are controlled by 'set-refresh-dirs';
6831271 @stuartsierra Fix arguments & support :after in refresh-all
stuartsierra authored Dec 4, 2012
149 defaults to all directories on the Java classpath.
150
151 Options are key-value pairs. Valid options are:
152
153 :after Namespace-qualified symbol naming a zero-argument
154 function to be invoked after a successful refresh. This
155 symbol will be resolved *after* all namespaces have
156 been reloaded."
157 [& options]
158 (let [{:keys [after]} options]
159 (do-refresh dir/scan-all after)))
6fbff40 @stuartsierra Add REPL helpers namespace
stuartsierra authored Aug 3, 2012
160
161 (defn set-refresh-dirs
162 "Sets the directories which are scanned by 'refresh'. Supports the
163 same types as clojure.java.io/file."
164 [& dirs]
165 (alter-var-root #'refresh-dirs (constantly dirs)))
Something went wrong with that request. Please try again.