diff --git a/notebooks/index.clj b/notebooks/index.clj index d536a849..03993c8e 100644 --- a/notebooks/index.clj +++ b/notebooks/index.clj @@ -90,6 +90,7 @@ [:li [:a {:href (clerk/doc-url "test/darkleaf/di/tutorial/x_add_side_dependency_test.clj")} "Add a side dependency"]] #_[:li [:a {:href (clerk/doc-url "test/darkleaf/di/tutorial/x_instrument_test.clj")} "Instrument"]] [:li [:a {:href (clerk/doc-url "test/darkleaf/di/tutorial/x_update_key_test.clj")} "Update key"]] + [:li [:a {:href (clerk/doc-url "test/darkleaf/di/tutorial/x_log_test.clj")} "Log"]] [:li [:a {:href (clerk/doc-url "test/darkleaf/di/tutorial/y_graceful_stop_test.clj")} "Graceful stop"]] [:li [:a {:href (clerk/doc-url "test/darkleaf/di/tutorial/y_multi_arity_service_test.clj")} "Multi arity service"]] [:li [:a {:href (clerk/doc-url "test/darkleaf/di/tutorial/z_multi_system_test.clj")} "Multi system"]] diff --git a/src/darkleaf/di/core.clj b/src/darkleaf/di/core.clj index 00159dc9..b96998f9 100644 --- a/src/darkleaf/di/core.clj +++ b/src/darkleaf/di/core.clj @@ -797,3 +797,27 @@ ~@body)) (finally (.close resource#))))))) + +(defn log + "A logging middleware. + Calls `:after-build!` and `:after-demolish!` during `di/start`. + Must be the last one in the middleware chain. + Both callbacks are expected to accept + the following arg `{:keys [key object]}`." + [& {:keys [after-build! after-demolish!] + :or {after-build! (fn no-op [_]) + after-demolish! (fn no-op [_])}}] + (fn [registry] + (fn [key] + (let [factory (registry key)] + (reify p/Factory + (dependencies [_] + (p/dependencies factory)) + (build [_ deps] + (let [obj (p/build factory deps)] + (after-build! {:key key :object obj}) + obj)) + (demolish [_ obj] + (p/demolish factory obj) + (after-demolish! {:key key :object obj}) + nil)))))) diff --git a/test/darkleaf/di/add_side_dependency_test.clj b/test/darkleaf/di/add_side_dependency_test.clj index 408892d0..dbfeded6 100644 --- a/test/darkleaf/di/add_side_dependency_test.clj +++ b/test/darkleaf/di/add_side_dependency_test.clj @@ -26,62 +26,55 @@ (defn- a {::di/kind :component} - [{log ::log}] - (swap! log conj :a) + [] :a) (defn- b {::di/kind :component} - [{log ::log}] - (swap! log conj :b) + [] :b) (defn- c {::di/kind :component} - [{log ::log}] - (swap! log conj :c) + [] :c) (defn- d {::di/kind :component} - [{log ::log}] - (swap! log conj :d) + [] :d) (defn- e {::di/kind :component} - [{log ::log}] - (swap! log conj :e) + [] :e) (defn- f {::di/kind :component} - [{log ::log}] - (swap! log conj :f) + [] :f) (defn- g {::di/kind :component} - [{log ::log}] - (swap! log conj :g) + [] :g) (defn- h {::di/kind :component} - [{log ::log}] - (swap! log conj :h) + [] :h) (defn- side-dep {::di/kind :component} - [{log ::log}] - (swap! log conj :side-dep)) + [] + :side-dep) (t/deftest bug-array-map->hash-map - (let [log (atom [])] + (let [log (atom []) + after-build! (fn [{:keys [key]}] + (swap! log conj key))] (with-open [root (di/start ::root - {::log log - ::root (di/template + {::root (di/template {:a (di/ref `a) :b (di/ref `b) :c (di/ref `c) @@ -90,8 +83,9 @@ :f (di/ref `f) :g (di/ref `g) :h (di/ref `h)})} - (di/add-side-dependency `side-dep))] - (t/is (= [:a :b :c :d :e :f :g :h :side-dep] @log)) + (di/add-side-dependency `side-dep) + (di/log :after-build! after-build!))] + (t/is (= [`a `b `c `d `e `f `g `h `di/new-key#0 `side-dep ::root] @log)) (t/is (= {:a :a :b :b :c :c @@ -103,13 +97,14 @@ (defn- side-dep2 {::di/kind :component} - [{log ::log}] - (swap! log conj :side-dep2)) + [] + :side-dep2) (t/deftest bug-array-map->hash-map-2 - (let [log (atom [])] + (let [log (atom []) + after-build! (fn [{:keys [key]}] + (swap! log conj key))] (with-open [root (di/start ::root - {::log log} (di/add-side-dependency `side-dep) {::root (di/template {:a (di/ref `a) @@ -120,8 +115,11 @@ :f (di/ref `f) :g (di/ref `g) :h (di/ref `h)})} - (di/add-side-dependency `side-dep2))] - (t/is (= [:a :side-dep :b :c :d :e :f :g :h :side-dep2] @log)) + (di/add-side-dependency `side-dep2) + (di/log :after-build! after-build!))] + (t/is (= [`di/new-key#0 `side-dep `a + `b `c `d `e `f `g `h + `di/new-key#1 `side-dep2 ::root] @log)) (t/is (= {:a :a :b :b :c :c diff --git a/test/darkleaf/di/dependencies_test.clj b/test/darkleaf/di/dependencies_test.clj index 14cded89..0c87e1bf 100644 --- a/test/darkleaf/di/dependencies_test.clj +++ b/test/darkleaf/di/dependencies_test.clj @@ -11,33 +11,33 @@ ;; c (defn root - {::di/stop #(swap! % conj [`root :stopped])} - [{a `a, b `b, log ::log}] - (swap! log conj [`root :built]) - log) + {::di/kind :component} + [{a `a, b `b}] + :root) (defn a - {::di/stop #(swap! % conj [`a :stopped])} - [{c `c, log ::log}] - (swap! log conj [`a :built]) - log) + {::di/kind :component} + [{c `c}] + :a) (defn b - {::di/stop #(swap! % conj [`b :stopped])} - [{c `c, log ::log}] - (swap! log conj [`b :built]) - log) + {::di/kind :component} + [{c `c}] + :b) (defn c - {::di/stop #(swap! % conj [`c :stopped])} - [{log ::log}] - (swap! log conj [`c :built]) - log) + {::di/kind :component} + [] + :c) (t/deftest order-test - (let [log (atom [])] - (-> (di/start `root {::log log}) - (di/stop)) + (let [log (atom []) + after-build! (fn [{:keys [key]}] + (swap! log conj [key :built])) + after-demolish! (fn [{:keys [key]}] + (swap! log conj [key :stopped]))] + (with-open [root (di/start `root (di/log :after-build! after-build! + :after-demolish! after-demolish!))]) (t/is (= [[`c :built] [`a :built] [`b :built] diff --git a/test/darkleaf/di/tutorial/x_log_test.clj b/test/darkleaf/di/tutorial/x_log_test.clj new file mode 100644 index 00000000..ae8fa1ae --- /dev/null +++ b/test/darkleaf/di/tutorial/x_log_test.clj @@ -0,0 +1,35 @@ +(ns darkleaf.di.tutorial.x-log-test + (:require + [clojure.test :as t] + [darkleaf.di.core :as di])) + +(defn a + {::di/kind :component} + [] + :a) + +(defn b [{a `a}] + :b) + +(defn c + {::di/kind :component} + [{b `b}] + :c) + +(t/deftest log + (let [logs (atom []) + after-build! (fn [{:keys [key object]}] + (swap! logs conj [:built key (pr-str object)])) + after-demolish! (fn [{:keys [key object]}] + (swap! logs conj [:demolished key (pr-str object)]))] + (with-open [root (di/start `c (di/log :after-build! after-build! + :after-demolish! after-demolish!))]) + (t/is (= [[:built `a ":a"] + [:built `b + "#darkleaf.di.core/service #'darkleaf.di.tutorial.x-log-test/b"] + [:built `c ":c"] + [:demolished `c ":c"] + [:demolished `b + "#darkleaf.di.core/service #'darkleaf.di.tutorial.x-log-test/b"] + [:demolished `a ":a"]] + @logs))))