diff --git a/src/darkleaf/di/core.clj b/src/darkleaf/di/core.clj index 3da8438..18e7d50 100644 --- a/src/darkleaf/di/core.clj +++ b/src/darkleaf/di/core.clj @@ -92,12 +92,21 @@ :declared-deps deps :remaining-deps (seq deps)})) -(defn- build-obj [built-map head] +(defn- build-obj* [built-map head] (let [factory (:factory head) declared-deps (:declared-deps head) built-deps (select-keys built-map (keys declared-deps))] (p/build factory built-deps))) +(defn- build-obj [built-map stack] + (try + (build-obj* built-map (peek stack)) + (catch Exception ex + (throw (ex-info "An error during component build" + {:type ::build-error + :stack (map :key stack)} + ex))))) + (defn- build [{:keys [registry *stop-list]} key] (loop [stack (list (stack-frame key :required (registry key))) built-map {}] @@ -126,7 +135,7 @@ built-map)) :else - (let [obj (build-obj built-map head) + (let [obj (build-obj built-map stack) stop #(p/demolish factory obj)] (vswap! *stop-list conj stop) (case [obj dep-type] @@ -592,12 +601,19 @@ (defn- stop-fn [variable] (-> variable meta (::stop (fn no-op [_])))) +(defn- validate-component-obj! [obj variable] + (when (nil? obj) + (throw (ex-info "A component fn should not return nil" + {:variable variable})))) + (defn- var->0-component [variable] (let [stop (stop-fn variable)] (reify p/Factory (dependencies [_]) (build [_ _] - (variable)) + (let [obj (variable)] + (validate-component-obj! obj variable) + obj)) (demolish [_ obj] (stop obj))))) @@ -608,7 +624,9 @@ (dependencies [_] deps) (build [_ deps] - (variable deps)) + (let [obj (variable deps)] + (validate-component-obj! obj variable) + obj)) (demolish [_ obj] (stop obj))))) @@ -641,7 +659,7 @@ [0] (var->0-component variable) [1] (var->1-component variable) (throw (ex-info - "The component must only have 0 or 1 arity" + "A component fn must only have 0 or 1 arity" {:variable variable :arities arities}))) #_service (case arities diff --git a/test/darkleaf/di/component_test.clj b/test/darkleaf/di/component_test.clj new file mode 100644 index 0000000..33952d5 --- /dev/null +++ b/test/darkleaf/di/component_test.clj @@ -0,0 +1,33 @@ +(ns darkleaf.di.component-test + (:require + [clojure.test :as t] + [darkleaf.di.core :as di]) + (:import + (clojure.lang ExceptionInfo))) + +(defmacro try-catch [& body] + `(try + ~@body + nil + (catch Exception ex# + ex#))) + +(defn nil-component-0-arity + {::di/kind :component} + [] + nil) + +(defn nil-component-1-arity + {::di/kind :component} + [-deps] + nil) + +(t/deftest nil-component-0-arity-test + (let [ex (try-catch (di/start `nil-component-0-arity))] + (t/is (= "An error during component build" (-> ex ex-message))) + (t/is (= "A component fn should not return nil" (-> ex ex-cause ex-message))))) + +(t/deftest nil-component-1-arity-test + (let [ex (try-catch (di/start `nil-component-1-arity))] + (t/is (= "An error during component build" (-> ex ex-message))) + (t/is (= "A component fn should not return nil" (-> ex ex-cause ex-message))))) diff --git a/test/darkleaf/di/tutorial/y_graceful_stop_test.clj b/test/darkleaf/di/tutorial/y_graceful_stop_test.clj index 83909ad..fa4a0eb 100644 --- a/test/darkleaf/di/tutorial/y_graceful_stop_test.clj +++ b/test/darkleaf/di/tutorial/y_graceful_stop_test.clj @@ -32,7 +32,7 @@ ::on-stop-dep-ex on-stop-dep-ex} ex (try (di/start `root registry) - (catch Throwable ex + (catch Exception ex ex))] - (t/is (= on-start-root-ex ex)) + (t/is (= on-start-root-ex (ex-cause ex))) (t/is (= [on-stop-dep-ex] (vec (.getSuppressed ex))))))