From 233f2ca90134a3e09178ed555be31978efaa30ff Mon Sep 17 00:00:00 2001 From: Matthew Darling Date: Thu, 11 Dec 2014 14:36:35 -0500 Subject: [PATCH 01/14] First draft of wrap-hook implementation --- src/dire/core.clj | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/dire/core.clj b/src/dire/core.clj index b98743e..557e990 100644 --- a/src/dire/core.clj +++ b/src/dire/core.clj @@ -111,6 +111,21 @@ [task-var f] (alter-meta! task-var disj-from-set-at-key :dire/post-hooks f)) +(defn with-wrap-hook + "After task-var is invoked and postconditions run, wrap-hooks will + run before post-hooks. You can register any number of wrap-hooks, + and they are not guaranteed to run in any specific order. Useful for + logging the return value of a function alongside its arguments." + ([task-var docstring? f] + (with-wrap-hook task-var f)) + ([task-var f] + (alter-meta! task-var update-in [:dire/wrap-hooks] (fnil conj #{}) f))) + +(defn remove-wrap-hook + "Removes any registered wrap-hook function f from task-var." + [task-var f] + (alter-meta! task-var disj-from-set-at-key :dire/wrap-hooks f)) + (defn- eval-preconditions [task-metadata & args] (doseq [[pre-name pre-fn] (:dire/preconditions task-metadata)] @@ -122,6 +137,11 @@ (when-not (post-fn result) (throw+ {:type ::postcondition :postcondition post-name :result result})))) +(defn- eval-wrap-hooks + [task-metadata result & args] + (doseq [f (:dire/wrap-hooks task-metadata)] + (f result args))) + (defn- eval-eager-pre-hooks [task-metadata & args] (doseq [f (:dire/eager-pre-hooks task-metadata)] (apply f args))) @@ -219,6 +239,7 @@ (apply eval-pre-hooks task-meta args) (let [result (apply task-var args)] (apply eval-postconditions task-meta result args) + (apply eval-wrap-hooks task-meta result args) (eval-post-hooks task-meta result) result) (catch [:type :dire.core/precondition] {:as conditions} @@ -356,3 +377,17 @@ (remove-supervise task-var) (hook-supervisor-to-fn task-var)) +(defn with-wrap-hook! + "Same as with-wrap-hook, but task-var can be invoked without supervise." + ([task-var docstring? f] (with-wrap-hook! task-var f)) + ([task-var f] + (with-wrap-hook task-var f) + (hook-supervisor-to-fn task-var))) + +(defn remove-wrap-hook! + "Removes any wrap-hook function f from task-var registered through + with-wrap-hook!" + [task-var f] + (remove-wrap-hook task-var f) + (remove-supervise task-var) + (hook-supervisor-to-fn task-var)) From 5515af49ecf5dcb1ae9092e43e69f272c669e0d8 Mon Sep 17 00:00:00 2001 From: Matthew Darling Date: Thu, 11 Dec 2014 14:41:11 -0500 Subject: [PATCH 02/14] Upversion Dire --- project.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project.clj b/project.clj index 051d27b..e720e09 100644 --- a/project.clj +++ b/project.clj @@ -1,4 +1,4 @@ -(defproject dire "0.5.2" +(defproject dire "0.5.3" :description "Erlang-style supervisor error handling for Clojure" :url "https://github.com/MichaelDrogalis/dire" :license {:name "Eclipse Public License" From b2a1127703aff72aab368511c325e29a75c77758 Mon Sep 17 00:00:00 2001 From: Matthew Darling Date: Sun, 18 Jan 2015 11:47:05 -0500 Subject: [PATCH 03/14] New ns for specifying Dire usage via metadata --- src/dire/metadata.clj | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/dire/metadata.clj diff --git a/src/dire/metadata.clj b/src/dire/metadata.clj new file mode 100644 index 0000000..ea1a207 --- /dev/null +++ b/src/dire/metadata.clj @@ -0,0 +1,5 @@ +(ns dire.metadata + "Functions to allow Dire hooks and conditions to be specified in the + metadata of functions, and applied or removed automatically as + needed." + (:require [dire.core :refer :all])) From 6ec20fbdf4b1f1f8fb92cb0c1ea5fdf6326f05d9 Mon Sep 17 00:00:00 2001 From: Matthew Darling Date: Sun, 18 Jan 2015 11:48:03 -0500 Subject: [PATCH 04/14] Some easy functions for adding hooks --- src/dire/metadata.clj | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/dire/metadata.clj b/src/dire/metadata.clj index ea1a207..f60fe5c 100644 --- a/src/dire/metadata.clj +++ b/src/dire/metadata.clj @@ -3,3 +3,16 @@ metadata of functions, and applied or removed automatically as needed." (:require [dire.core :refer :all])) + +;;; Implementation functions +(defn- apply-dire-wrap-hook + [fn-var hook-fn] + (dire/with-wrap-hook! fn-var + (-> hook-fn resolve meta :doc) + hook-fn)) + +(defn- apply-dire-eager-pre-hook + [fn-var hook-fn] + (dire/with-eager-pre-hook! fn-var + (-> hook-fn resolve meta :doc) + hook-fn)) From 299443d35a0ec01d88ba71fec8406cdc06b21ecc Mon Sep 17 00:00:00 2001 From: Matthew Darling Date: Sun, 18 Jan 2015 11:48:16 -0500 Subject: [PATCH 05/14] Somewhat trickier code to add precondition + handler --- src/dire/metadata.clj | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/dire/metadata.clj b/src/dire/metadata.clj index f60fe5c..83b4ec7 100644 --- a/src/dire/metadata.clj +++ b/src/dire/metadata.clj @@ -16,3 +16,17 @@ (dire/with-eager-pre-hook! fn-var (-> hook-fn resolve meta :doc) hook-fn)) + +(defn- apply-dire-pre + [fn-var possible-handlers pre-cond-fn] + (let [pre-cond-name (-> pre-cond-fn resolve meta ::pre-name) + correct-handler (first (filter #(= pre-cond-name (-> % resolve meta ::pre-name)) + possible-handlers))] + (dire/with-precondition! fn-var + (-> pre-cond-fn resolve meta :doc) + pre-cond-name + pre-cond-fn) + (dire/with-handler! fn-var + (-> correct-handler resolve meta :doc) + {:precondition pre-cond-name} + correct-handler))) From 447cda856c90dccb324aa770270b9b6757bca54d Mon Sep 17 00:00:00 2001 From: Matthew Darling Date: Sun, 18 Jan 2015 11:48:37 -0500 Subject: [PATCH 06/14] Removal functions (simpler than adding, yay!) --- src/dire/metadata.clj | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/dire/metadata.clj b/src/dire/metadata.clj index 83b4ec7..1fb4a96 100644 --- a/src/dire/metadata.clj +++ b/src/dire/metadata.clj @@ -30,3 +30,17 @@ (-> correct-handler resolve meta :doc) {:precondition pre-cond-name} correct-handler))) + +(defn- remove-dire-wrap-hook + [fn-var hook-fn] + (dire/remove-wrap-hook! fn-var hook-fn)) + +(defn- remove-dire-eager-pre-hook + [fn-var hook-fn] + (dire/remove-eager-pre-hook! fn-var hook-fn)) + +(defn- remove-dire-pre + [fn-var pre-cond-fn] + (let [pre-cond-name (-> pre-cond-fn resolve meta ::pre-name)] + (dire/remove-precondition! fn-var pre-cond-name) + (dire/remove-handler! fn-var pre-cond-name))) From cc68377dc07aa5c740cdc4c9c08b0196223a4f22 Mon Sep 17 00:00:00 2001 From: Matthew Darling Date: Sun, 18 Jan 2015 11:48:55 -0500 Subject: [PATCH 07/14] Function to calculate appropriate additions --- src/dire/metadata.clj | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/dire/metadata.clj b/src/dire/metadata.clj index 1fb4a96..6e6be1f 100644 --- a/src/dire/metadata.clj +++ b/src/dire/metadata.clj @@ -44,3 +44,15 @@ (let [pre-cond-name (-> pre-cond-fn resolve meta ::pre-name)] (dire/remove-precondition! fn-var pre-cond-name) (dire/remove-handler! fn-var pre-cond-name))) + +;;; Public API +(defn apply-dire-meta + [fn] + (let [fn-var (resolve fn) + preconditions (-> fn-var meta ::preconditions) + pre-handlers (-> fn-var meta ::handlers ::pre-handlers) + eager-pre-hooks (-> fn-var meta ::eager-pre-hooks) + wrap-hooks (-> fn-var meta ::wrap-hooks)] + (doall (map #(apply-dire-pre fn-var pre-handlers %) preconditions)) + (doall (map #(apply-dire-eager-pre-hook fn-var %) eager-pre-hooks)) + (doall (map #(apply-dire-wrap-hook fn-var %) wrap-hooks)))) From 786df687d7cd88c42430ddb4bcaa669be6fadad9 Mon Sep 17 00:00:00 2001 From: Matthew Darling Date: Sun, 18 Jan 2015 11:49:20 -0500 Subject: [PATCH 08/14] Function to do the removals --- src/dire/metadata.clj | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/dire/metadata.clj b/src/dire/metadata.clj index 6e6be1f..9f6ad57 100644 --- a/src/dire/metadata.clj +++ b/src/dire/metadata.clj @@ -56,3 +56,14 @@ (doall (map #(apply-dire-pre fn-var pre-handlers %) preconditions)) (doall (map #(apply-dire-eager-pre-hook fn-var %) eager-pre-hooks)) (doall (map #(apply-dire-wrap-hook fn-var %) wrap-hooks)))) + +(defn remove-dire + [fn] + (let [fn-var (resolve fn) + preconditions (-> fn-var resolve meta ::preconditions) + pre-handlers (-> fn-var resolve meta ::handlers ::pre-handlers) + eager-pre-hooks (-> fn-var resolve meta ::eager-pre-hooks) + wrap-hooks (-> fn-var resolve meta ::wrap-hooks)] + (doall (map #(remove-dire-pre fn-var %) preconditions)) + (doall (map #(remove-dire-eager-pre-hook fn-var %) eager-pre-hooks)) + (doall (map #(remove-dire-wrap-hook fn-var %) wrap-hooks)))) From a977e1afc3138b69e89b0b1e2bdef477e12056a2 Mon Sep 17 00:00:00 2001 From: Matthew Darling Date: Sun, 18 Jan 2015 11:49:37 -0500 Subject: [PATCH 09/14] Testing code similar to the mutation removal test --- src/dire/metadata.clj | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/dire/metadata.clj b/src/dire/metadata.clj index 9f6ad57..8b840e7 100644 --- a/src/dire/metadata.clj +++ b/src/dire/metadata.clj @@ -67,3 +67,18 @@ (doall (map #(remove-dire-pre fn-var %) preconditions)) (doall (map #(remove-dire-eager-pre-hook fn-var %) eager-pre-hooks)) (doall (map #(remove-dire-wrap-hook fn-var %) wrap-hooks)))) + +;;; Testing code +(defn precondition {::pre-name :pre} [a b] (prn "precond:") false) +(defn pre-handler {::pre-name :pre} [_ a b] (prn "handler:")) +(defn wrap-hook [r [a b]] (prn "wrap:")) +(defn eager-pre-hook [a b] (prn "eager:")) + +(defn ^{::preconditions '[precondition] + ::handlers {::pre-handlers '[pre-handler]} + ::eager-pre-hooks '[eager-pre-hook] + ::wrap-hooks '[wrap-hook]} + test-fn + "Docstring" + [a b] + (/ a b)) From 9269d9c516e6a66ae219a67c8f45cfa2fc1e987a Mon Sep 17 00:00:00 2001 From: Matthew Darling Date: Sun, 18 Jan 2015 12:28:16 -0500 Subject: [PATCH 10/14] Make it clearer that these functions aren't pure --- src/dire/metadata.clj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/dire/metadata.clj b/src/dire/metadata.clj index 8b840e7..370da9e 100644 --- a/src/dire/metadata.clj +++ b/src/dire/metadata.clj @@ -5,19 +5,19 @@ (:require [dire.core :refer :all])) ;;; Implementation functions -(defn- apply-dire-wrap-hook +(defn- apply-dire-wrap-hook! [fn-var hook-fn] (dire/with-wrap-hook! fn-var (-> hook-fn resolve meta :doc) hook-fn)) -(defn- apply-dire-eager-pre-hook +(defn- apply-dire-eager-pre-hook! [fn-var hook-fn] (dire/with-eager-pre-hook! fn-var (-> hook-fn resolve meta :doc) hook-fn)) -(defn- apply-dire-pre +(defn- apply-dire-pre! [fn-var possible-handlers pre-cond-fn] (let [pre-cond-name (-> pre-cond-fn resolve meta ::pre-name) correct-handler (first (filter #(= pre-cond-name (-> % resolve meta ::pre-name)) @@ -31,22 +31,22 @@ {:precondition pre-cond-name} correct-handler))) -(defn- remove-dire-wrap-hook +(defn- remove-dire-wrap-hook! [fn-var hook-fn] (dire/remove-wrap-hook! fn-var hook-fn)) -(defn- remove-dire-eager-pre-hook +(defn- remove-dire-eager-pre-hook! [fn-var hook-fn] (dire/remove-eager-pre-hook! fn-var hook-fn)) -(defn- remove-dire-pre +(defn- remove-dire-pre! [fn-var pre-cond-fn] (let [pre-cond-name (-> pre-cond-fn resolve meta ::pre-name)] (dire/remove-precondition! fn-var pre-cond-name) (dire/remove-handler! fn-var pre-cond-name))) ;;; Public API -(defn apply-dire-meta +(defn apply-dire-meta! [fn] (let [fn-var (resolve fn) preconditions (-> fn-var meta ::preconditions) @@ -57,7 +57,7 @@ (doall (map #(apply-dire-eager-pre-hook fn-var %) eager-pre-hooks)) (doall (map #(apply-dire-wrap-hook fn-var %) wrap-hooks)))) -(defn remove-dire +(defn remove-dire! [fn] (let [fn-var (resolve fn) preconditions (-> fn-var resolve meta ::preconditions) From cde912aa5c046e2cba93002828840cc735c3cfc8 Mon Sep 17 00:00:00 2001 From: Matthew Darling Date: Sun, 18 Jan 2015 12:33:29 -0500 Subject: [PATCH 11/14] Fix improper namespacing --- src/dire/metadata.clj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/dire/metadata.clj b/src/dire/metadata.clj index 370da9e..72eaea2 100644 --- a/src/dire/metadata.clj +++ b/src/dire/metadata.clj @@ -7,13 +7,13 @@ ;;; Implementation functions (defn- apply-dire-wrap-hook! [fn-var hook-fn] - (dire/with-wrap-hook! fn-var + (with-wrap-hook! fn-var (-> hook-fn resolve meta :doc) hook-fn)) (defn- apply-dire-eager-pre-hook! [fn-var hook-fn] - (dire/with-eager-pre-hook! fn-var + (with-eager-pre-hook! fn-var (-> hook-fn resolve meta :doc) hook-fn)) @@ -22,28 +22,28 @@ (let [pre-cond-name (-> pre-cond-fn resolve meta ::pre-name) correct-handler (first (filter #(= pre-cond-name (-> % resolve meta ::pre-name)) possible-handlers))] - (dire/with-precondition! fn-var + (with-precondition! fn-var (-> pre-cond-fn resolve meta :doc) pre-cond-name pre-cond-fn) - (dire/with-handler! fn-var + (with-handler! fn-var (-> correct-handler resolve meta :doc) {:precondition pre-cond-name} correct-handler))) (defn- remove-dire-wrap-hook! [fn-var hook-fn] - (dire/remove-wrap-hook! fn-var hook-fn)) + (remove-wrap-hook! fn-var hook-fn)) (defn- remove-dire-eager-pre-hook! [fn-var hook-fn] - (dire/remove-eager-pre-hook! fn-var hook-fn)) + (remove-eager-pre-hook! fn-var hook-fn)) (defn- remove-dire-pre! [fn-var pre-cond-fn] (let [pre-cond-name (-> pre-cond-fn resolve meta ::pre-name)] - (dire/remove-precondition! fn-var pre-cond-name) - (dire/remove-handler! fn-var pre-cond-name))) + (remove-precondition! fn-var pre-cond-name) + (remove-handler! fn-var pre-cond-name))) ;;; Public API (defn apply-dire-meta! From 882773ac172eef97f877d046622f3cd1fd3f4a80 Mon Sep 17 00:00:00 2001 From: Matthew Darling Date: Sun, 18 Jan 2015 12:36:48 -0500 Subject: [PATCH 12/14] Fix renaming of implementation functions --- src/dire/metadata.clj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/dire/metadata.clj b/src/dire/metadata.clj index 72eaea2..e6bb50e 100644 --- a/src/dire/metadata.clj +++ b/src/dire/metadata.clj @@ -53,9 +53,9 @@ pre-handlers (-> fn-var meta ::handlers ::pre-handlers) eager-pre-hooks (-> fn-var meta ::eager-pre-hooks) wrap-hooks (-> fn-var meta ::wrap-hooks)] - (doall (map #(apply-dire-pre fn-var pre-handlers %) preconditions)) - (doall (map #(apply-dire-eager-pre-hook fn-var %) eager-pre-hooks)) - (doall (map #(apply-dire-wrap-hook fn-var %) wrap-hooks)))) + (doall (map #(apply-dire-pre! fn-var pre-handlers %) preconditions)) + (doall (map #(apply-dire-eager-pre-hook! fn-var %) eager-pre-hooks)) + (doall (map #(apply-dire-wrap-hook! fn-var %) wrap-hooks)))) (defn remove-dire! [fn] @@ -64,9 +64,9 @@ pre-handlers (-> fn-var resolve meta ::handlers ::pre-handlers) eager-pre-hooks (-> fn-var resolve meta ::eager-pre-hooks) wrap-hooks (-> fn-var resolve meta ::wrap-hooks)] - (doall (map #(remove-dire-pre fn-var %) preconditions)) - (doall (map #(remove-dire-eager-pre-hook fn-var %) eager-pre-hooks)) - (doall (map #(remove-dire-wrap-hook fn-var %) wrap-hooks)))) + (doall (map #(remove-dire-pre! fn-var %) preconditions)) + (doall (map #(remove-dire-eager-pre-hook! fn-var %) eager-pre-hooks)) + (doall (map #(remove-dire-wrap-hook! fn-var %) wrap-hooks)))) ;;; Testing code (defn precondition {::pre-name :pre} [a b] (prn "precond:") false) From 142968df0649e7c23038a75612b2703ee5ee2a87 Mon Sep 17 00:00:00 2001 From: Matthew Darling Date: Sun, 18 Jan 2015 12:45:28 -0500 Subject: [PATCH 13/14] Correctly remove preconditon handlers --- src/dire/metadata.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dire/metadata.clj b/src/dire/metadata.clj index e6bb50e..e823250 100644 --- a/src/dire/metadata.clj +++ b/src/dire/metadata.clj @@ -43,7 +43,7 @@ [fn-var pre-cond-fn] (let [pre-cond-name (-> pre-cond-fn resolve meta ::pre-name)] (remove-precondition! fn-var pre-cond-name) - (remove-handler! fn-var pre-cond-name))) + (remove-handler! fn-var {:precondition pre-cond-name}))) ;;; Public API (defn apply-dire-meta! From 016335d2f06b90d9fd7caed31f138c74cc142f43 Mon Sep 17 00:00:00 2001 From: Matthew Darling Date: Sun, 18 Jan 2015 12:47:57 -0500 Subject: [PATCH 14/14] Pass in var to apply/remove fns Turns out you can't resolve stuff that's out of the current scope. Which is obvious in retrospect. --- src/dire/metadata.clj | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/dire/metadata.clj b/src/dire/metadata.clj index e823250..b012d9f 100644 --- a/src/dire/metadata.clj +++ b/src/dire/metadata.clj @@ -47,9 +47,8 @@ ;;; Public API (defn apply-dire-meta! - [fn] - (let [fn-var (resolve fn) - preconditions (-> fn-var meta ::preconditions) + [fn-var] + (let [preconditions (-> fn-var meta ::preconditions) pre-handlers (-> fn-var meta ::handlers ::pre-handlers) eager-pre-hooks (-> fn-var meta ::eager-pre-hooks) wrap-hooks (-> fn-var meta ::wrap-hooks)] @@ -58,12 +57,11 @@ (doall (map #(apply-dire-wrap-hook! fn-var %) wrap-hooks)))) (defn remove-dire! - [fn] - (let [fn-var (resolve fn) - preconditions (-> fn-var resolve meta ::preconditions) - pre-handlers (-> fn-var resolve meta ::handlers ::pre-handlers) - eager-pre-hooks (-> fn-var resolve meta ::eager-pre-hooks) - wrap-hooks (-> fn-var resolve meta ::wrap-hooks)] + [fn-var] + (let [preconditions (-> fn-var meta ::preconditions) + pre-handlers (-> fn-var meta ::handlers ::pre-handlers) + eager-pre-hooks (-> fn-var meta ::eager-pre-hooks) + wrap-hooks (-> fn-var meta ::wrap-hooks)] (doall (map #(remove-dire-pre! fn-var %) preconditions)) (doall (map #(remove-dire-eager-pre-hook! fn-var %) eager-pre-hooks)) (doall (map #(remove-dire-wrap-hook! fn-var %) wrap-hooks))))