From dae36ef549e845d8ea9f4417b2f452be4d41969e Mon Sep 17 00:00:00 2001 From: Peter Taoussanis Date: Fri, 29 Mar 2024 12:30:02 +0100 Subject: [PATCH] [mod] Rework (simplify) `with-signal` API --- .../signal-docstrings/catch-to-error!.txt | 2 +- resources/signal-docstrings/error!.txt | 2 +- resources/signal-docstrings/event!.txt | 2 +- resources/signal-docstrings/log!.txt | 2 +- resources/signal-docstrings/signal!.txt | 2 +- resources/signal-docstrings/spy!.txt | 2 +- resources/signal-docstrings/trace!.txt | 2 +- src/taoensso/telemere.cljc | 4 +- src/taoensso/telemere/impl.cljc | 123 ++++++++---------- src/taoensso/telemere/streams.clj | 2 +- 10 files changed, 63 insertions(+), 80 deletions(-) diff --git a/resources/signal-docstrings/catch-to-error!.txt b/resources/signal-docstrings/catch-to-error!.txt index edfc89d..d047f4d 100644 --- a/resources/signal-docstrings/catch-to-error!.txt +++ b/resources/signal-docstrings/catch-to-error!.txt @@ -24,7 +24,7 @@ Examples: Tips: - - Test using `with-signals`: (with-signals (catch->error! ...)). + - Test using `with-signal`: (with-signal (catch->error! ...)). - Supports the same options as other signals [1]. - Useful for recording errors in forms, futures, callbacks, etc. diff --git a/resources/signal-docstrings/error!.txt b/resources/signal-docstrings/error!.txt index 655eb16..eafc4ab 100644 --- a/resources/signal-docstrings/error!.txt +++ b/resources/signal-docstrings/error!.txt @@ -18,7 +18,7 @@ Examples: Tips: - - Test using `with-signals`: (with-signals (error! ...)). + - Test using `with-signal`: (with-signal (error! ...)). - Supports the same options as other signals [3]. - `error` arg is a platform error (`java.lang.Throwable` or `js/Error`). diff --git a/resources/signal-docstrings/event!.txt b/resources/signal-docstrings/event!.txt index f449772..5cce496 100644 --- a/resources/signal-docstrings/event!.txt +++ b/resources/signal-docstrings/event!.txt @@ -18,7 +18,7 @@ Examples: Tips: - - Test using `with-signals`: (with-signals (error! ...)). + - Test using `with-signal`: (with-signal (event! ...)). - Supports the same options as other signals [3]. - A good general-purpose signal, prefer to `log!` by default, since it diff --git a/resources/signal-docstrings/log!.txt b/resources/signal-docstrings/log!.txt index 6a41edb..d0374c9 100644 --- a/resources/signal-docstrings/log!.txt +++ b/resources/signal-docstrings/log!.txt @@ -19,7 +19,7 @@ Examples: Tips: - - Test using `with-signals`: (with-signals (log! ...)). + - Test using `with-signal`: (with-signal (log! ...)). - Supports the same options as other signals [3]. - Prefer `event!` to `log!` by default, since it better encourages structured diff --git a/resources/signal-docstrings/signal!.txt b/resources/signal-docstrings/signal!.txt index 6cd2cd5..5649acb 100644 --- a/resources/signal-docstrings/signal!.txt +++ b/resources/signal-docstrings/signal!.txt @@ -26,7 +26,7 @@ their defaults and the focus of their call APIs (args and return values): Tips: - - Test using `with-signals`: (with-signals (signal! ...)). + - Test using `with-signal`: (with-signal (signal! ...)). - Supports the same options as other signals [3]. ---------------------------------------- diff --git a/resources/signal-docstrings/spy!.txt b/resources/signal-docstrings/spy!.txt index d725d97..08e6771 100644 --- a/resources/signal-docstrings/spy!.txt +++ b/resources/signal-docstrings/spy!.txt @@ -21,7 +21,7 @@ Examples: Tips: - - Test using `with-signals`: (with-signals (spy! ...)). + - Test using `with-signal`: (with-signal (spy! ...)). - Supports the same options as other signals [3]. - Identical to `trace!`, but focused on form + level rather than form + id. diff --git a/resources/signal-docstrings/trace!.txt b/resources/signal-docstrings/trace!.txt index 556cfd2..43dc17a 100644 --- a/resources/signal-docstrings/trace!.txt +++ b/resources/signal-docstrings/trace!.txt @@ -21,7 +21,7 @@ Examples: Tips: - - Test using `with-signals`: (with-signals (trace! ...)). + - Test using `with-signal`: (with-signal (trace! ...)). - Supports the same options as other signals [3]. - Identical to `spy!`, but focused on form + id rather than form + level. diff --git a/src/taoensso/telemere.cljc b/src/taoensso/telemere.cljc index b3a6dee..4410e89 100644 --- a/src/taoensso/telemere.cljc +++ b/src/taoensso/telemere.cljc @@ -20,7 +20,7 @@ [set-ctx! with-ctx with-ctx+ set-middleware! with-middleware - with-signals with-signal + with-signal with-signals signal! event! log! trace! spy! catch->error! ;; Via `sigs/def-api` @@ -72,8 +72,8 @@ impl/msg-splice impl/msg-skip - #?(:clj impl/with-signals) #?(:clj impl/with-signal) + #?(:clj impl/with-signals) #?(:clj impl/signal!)) ;;;; Signal help diff --git a/src/taoensso/telemere/impl.cljc b/src/taoensso/telemere/impl.cljc index 400d37e..245bede 100644 --- a/src/taoensso/telemere/impl.cljc +++ b/src/taoensso/telemere/impl.cljc @@ -5,7 +5,11 @@ (:refer-clojure :exclude [binding]) (:require [taoensso.encore :as enc :refer [binding have have?]] - [taoensso.encore.signals :as sigs])) + [taoensso.encore.signals :as sigs]) + + #?(:cljs + (:require-macros + [taoensso.telemere.impl :refer [with-signal]]))) (comment (remove-ns 'taoensso.telemere.impl) @@ -243,92 +247,72 @@ (enc/defonce ^:dynamic *sig-spy* "To support `with-signals`, etc." nil) (enc/defonce ^:dynamic *sig-handlers* "?[]" nil) -(defn- force-msg [sig] - (if-not (map? sig) +(defn force-msg-in-sig [sig] + (if-not (map? sig) sig (if-let [e (find sig :msg_)] (assoc sig :msg_ (force (val e))) (do sig)))) -(defn -with-signals - "Private util to support `with-signals` macro." - [form-fn - {:keys [handle? trap-errors? force-msg?] - :or {handle? true}}] +#?(:clj + (defmacro ^:public with-signal + "Experimental. + Executes given form, trapping errors. Returns the LAST signal triggered by form. + Useful for tests/debugging. - (let [sigs_ (volatile! nil)] - (binding [*sig-spy* [sigs_ (not :last-only?) handle?]] - (let [form-result - (if-not trap-errors? - (form-fn) - (enc/try* - (do [(form-fn) nil]) - (catch :all t t [nil t])))] + Options: + `trap-signals?` (default: false) + Should ALL signals triggered by form be trapped to prevent normal dispatch + to registered handlers? - [form-result - (when-let [sigs @sigs_] - (if force-msg? - (mapv force-msg sigs) - (do sigs)))])))) + `raw-msg?` (default: false) + Should delayed `:msg_` in returned signal be retained as-is? + Delay is otherwise replaced by realized string. + + See also `with-signals`." + ([ form] `(with-signal false false ~form)) + ([ trap-signals? form] `(with-signal false ~trap-signals? ~form)) + ([raw-msg? trap-signals? form] + `(let [sig_# (volatile! nil)] + (binding [*sig-spy* [sig_# :last-only ~trap-signals?]] + (enc/try* ~form (catch :all _#))) + + (if ~raw-msg? + (do @sig_#) + (force-msg-in-sig @sig_#)))))) #?(:clj (defmacro ^:public with-signals "Experimental. - Executes given form and records any signals triggered by it. - Return value depends on given options. Useful for tests/debugging. + Like `with-signal` but returns [[ ] [ ...]]. + Useful for tests/debugging." + ([ form] `(with-signals false false ~form)) + ([ trap-signals? form] `(with-signals false ~trap-signals? ~form)) + ([raw-msgs? trap-signals? form] + `(let [sigs_# (volatile! nil) + form-result# + (binding [*sig-spy* [sigs_# (not :last-only) ~trap-signals?]] + (enc/try* + (do [~form nil]) + (catch :all t# [nil t#]))) - Options: + sigs# + (if ~raw-msgs? + (do @sigs_#) + (mapv force-msg-in-sig @sigs_#))] - `handle?` - Should registered handlers receive signals triggered by form, as usual? - Default: true. - - `trap-errors?` - If true: returns [[form-value form-error] signals], trapping any form error. - If false: returns [ form-value signals], throwing on form error. - Default: false. - - `force-msg?` - Should delayed `:msg_` keys in signals be replaced with realized strings? - Default: false. - - See also `with-signal` for a simpler API." - {:arglists - '([form] - [{:keys [handle? trap-errors? force-msg?] - :or {handle? true}} form])} - - ([ form] `(-with-signals (fn [] ~form) nil)) - ([opts form] `(-with-signals (fn [] ~form) ~opts)))) - -#?(:clj - (defmacro ^:public with-signal - "Experimental - Minimal version of `with-signals`. - Executes given form and returns the last signal triggered by it. - Useful for tests/debugging. - - - Always allows registered handlers to receive signals as usual. - - Always traps form errors. - - Never forces `:msg_` key. - - See also `with-signals` for more options." - [form] - `(let [sig_# (volatile! nil)] - (binding [*sig-spy* [sig_# :last-only :handle]] - (enc/catching ~form)) - @sig_#))) + [form-result# (not-empty sigs#)])))) (defn dispatch-signal! - "Dispatches given signal to registered handlers, supports `with-signals`." + "Dispatches given signal to registered handlers, supports `with-signal/s`." [signal] (or - (when-let [[v_ last-only? handle?] *sig-spy*] + (when-let [[v_ last-only? trap-signals?] *sig-spy*] (let [sv (sigs/signal-value signal nil)] (if last-only? (vreset! v_ sv) (vswap! v_ #(conj (or % []) sv)))) - (when-not handle? :stop)) + (when trap-signals? :stop)) (sigs/call-handlers! *sig-handlers* signal))) @@ -618,7 +602,7 @@ true)))))))) (comment - (with-signals (signal! {:level :warn :let [x :x] :msg ["Test" "message" x] :data {:a :A :x x} :run (+ 1 2)})) + (with-signal (signal! {:level :warn :let [x :x] :msg ["Test" "message" x] :data {:a :A :x x} :run (+ 1 2)})) (macroexpand '(signal! {:level :warn :let [x :x] :msg ["Test" "message" x] :data {:a :A :x x} :run (+ 1 2)})) (do @@ -664,9 +648,8 @@ (defn test-interop! [msg test-fn] (let [msg (str "Interop test: " msg " (" (enc/uuid-str) ")") - [_ [signal]] + signal (binding [*rt-sig-filter* nil] ; Without runtime filters - (-with-signals (fn [] (test-fn msg)) - {:handle? false}))] + (with-signal :raw :trap (test-fn msg)))] (= (force (get signal :msg_)) msg))) diff --git a/src/taoensso/telemere/streams.clj b/src/taoensso/telemere/streams.clj index d18452d..8ae621d 100644 --- a/src/taoensso/telemere/streams.clj +++ b/src/taoensso/telemere/streams.clj @@ -72,7 +72,7 @@ *err* (if-let [err# ~err] (osw (telemere-print-stream err#)) *err*)] ~form))) -(comment (impl/with-signals (with-out->telemere (println "hello")))) +(comment (impl/with-signal (with-out->telemere (println "hello")))) (enc/defonce ^:private orig-out_ "Original `System/out`, or nil" (atom nil)) (enc/defonce ^:private orig-err_ "Original `System/err`, or nil" (atom nil))