|
| 1 | +(ns nsfw.reup |
| 2 | + "Utilities for supporting a clojure.tools.namespace reloading dev |
| 3 | + lifecycle. |
| 4 | +
|
| 5 | + Add the following to your project.clj |
| 6 | +
|
| 7 | + `:repl-options {:init (load-file \"reup.clj\")}`" |
| 8 | + (:require [clojure.tools.namespace.repl :as repl] |
| 9 | + [clojure.tools.namespace.find :as ns-find] |
| 10 | + [clojure.java.classpath :as cp] |
| 11 | + [clojure.string :as str])) |
| 12 | + |
| 13 | +(defn exception? [e] |
| 14 | + (isa? (type e) Exception)) |
| 15 | + |
| 16 | +(defn ns-for-sym [sym] |
| 17 | + (when (.contains (str sym) "/") |
| 18 | + (-> sym |
| 19 | + str |
| 20 | + (str/split #"/") |
| 21 | + first |
| 22 | + symbol))) |
| 23 | + |
| 24 | +(defn setup |
| 25 | + "Helper for initializing a clojure.tools.namespace dev |
| 26 | + lifecycle. See |
| 27 | + http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded |
| 28 | + for more info. |
| 29 | +
|
| 30 | + This will return a function that, when called, will stop the |
| 31 | + current environment, reload all namespaces, and start a new |
| 32 | + environment. |
| 33 | +
|
| 34 | + Params: |
| 35 | + * `start-app-sym` -- FQ symbol of a no-arg function which |
| 36 | + starts the environment |
| 37 | + * `stop-app-sym` -- FQ symbol of a 1-arg |
| 38 | + function which stops the environment. The result of calling the |
| 39 | + start app function is passed in as it's first parameter |
| 40 | + * `tests-regex` -- Run tests after reload for all namespaces matching" |
| 41 | + |
| 42 | + [{:keys [start-app-sym stop-app-sym tests-regex]}] |
| 43 | + (when start-app-sym |
| 44 | + (when-not (resolve 'user/reup-app) |
| 45 | + (intern 'user 'reup-app nil)) |
| 46 | + (when-not (resolve 'user/after-reup) |
| 47 | + (intern 'user 'after-reup |
| 48 | + (fn [] |
| 49 | + (when start-app-sym |
| 50 | + (binding [*ns* (find-ns 'user)] |
| 51 | + (alter-var-root (resolve 'user/reup-app) |
| 52 | + (constantly (when-let [a (resolve start-app-sym)] |
| 53 | + (let [f (deref a)] |
| 54 | + (f)))))))))) |
| 55 | + |
| 56 | + (require (ns-for-sym start-app-sym) :reload) |
| 57 | + (require (ns-for-sym stop-app-sym) :reload) |
| 58 | + |
| 59 | + (when-not (resolve start-app-sym) |
| 60 | + (throw (Exception. (str "Can't resolve start-app-sym: " start-app-sym)))) |
| 61 | + |
| 62 | + (when-not (resolve stop-app-sym) |
| 63 | + (throw (Exception. (str "Can't resolve stop-app-sym: " stop-app-sym))))) |
| 64 | + |
| 65 | + (fn [] |
| 66 | + (time |
| 67 | + (do |
| 68 | + (when start-app-sym |
| 69 | + (binding [*ns* (find-ns 'user)] |
| 70 | + (do |
| 71 | + (try |
| 72 | + (@(resolve stop-app-sym) @(resolve 'user/reup-app)) |
| 73 | + (catch Exception e |
| 74 | + (println "Exception stopping app:" e))))) |
| 75 | + (alter-var-root (resolve 'user/reup-app) (constantly nil))) |
| 76 | + (let [res (if start-app-sym |
| 77 | + (repl/refresh :after 'user/after-reup) |
| 78 | + (repl/refresh))] |
| 79 | + (when (exception? res) |
| 80 | + (throw res))) |
| 81 | + |
| 82 | + (when tests-regex |
| 83 | + (doseq [ns-sym (->> (cp/classpath-directories) |
| 84 | + ns-find/find-namespaces |
| 85 | + (filter #(re-find tests-regex (str %))))] |
| 86 | + (require ns-sym)) |
| 87 | + (clojure.test/run-all-tests tests-regex)))))) |
0 commit comments