Skip to content
This repository has been archived by the owner on Jul 27, 2020. It is now read-only.

Add scopes for hooks #10

Merged
merged 1 commit into from Oct 5, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 35 additions & 0 deletions src/robert/hooke.clj
Expand Up @@ -55,6 +55,40 @@
::hooks hooks
::original original)))))))

(defonce hook-scopes [])

(defn start-scope []
(locking hook-scopes
(alter-var-root #'hook-scopes conj {})))

(defn- scope-update-fn
[scopes target-var]
(conj
(pop scopes)
(update-in (peek scopes) [target-var] #(if % % @(hooks target-var)))))

(defn- possibly-record-in-scope
[target-var]
(locking hook-scopes
(when (seq hook-scopes)
(alter-var-root #'hook-scopes scope-update-fn target-var))))

(defn end-scope []
(locking hook-scopes
(let [head (peek hook-scopes)]
(alter-var-root #'hook-scopes pop)
(doseq [[var old-hooks] head]
(reset! (hooks var) old-hooks)))))

(defmacro hook-scope
"Defines a scope which records any change to hooks during the dynamic scope of
its body, and restores hooks to their original state on exit of the scope."
[& body]
`(try
(start-scope)
~@body
(finally (end-scope))))

(defn add-hook
"Add a hook function f to target-var. Hook functions are passed the
target function and all their arguments and must apply the target to
Expand All @@ -63,6 +97,7 @@
(add-hook target-var f f))
([target-var key f]
(prepare-for-hooks target-var)
(possibly-record-in-scope target-var)
(swap! (hooks target-var) assoc key f)))

(defn- clear-hook-mechanism [target-var]
Expand Down
7 changes: 7 additions & 0 deletions test/robert/test_hooke.clj
Expand Up @@ -83,3 +83,10 @@
(is (= (keyed 1) 4))
(clear-hooks #'keyed)
(is (= (keyed 1) 1)))

(deftest hook-scope-test
(is (hooked))
(hook-scope
(add-hook #'hooked asplode)
(is (thrown? Exception (hooked))))
(is (hooked)))