Skip to content

Commit

Permalink
Add di/with-open
Browse files Browse the repository at this point in the history
  • Loading branch information
darkleaf committed Oct 15, 2024
1 parent c5507af commit 9b36a26
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 13 deletions.
23 changes: 22 additions & 1 deletion src/darkleaf/di/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
;; **********************************************************************/

(ns darkleaf.di.core
(:refer-clojure :exclude [ref key ns-publics derive])
(:refer-clojure :exclude [ref key ns-publics derive with-open])
(:require
[clojure.core :as c]
[clojure.set :as set]
Expand Down Expand Up @@ -759,3 +759,24 @@
(update-keys deps #(-> % name keyword)))
(demolish [_ _])))
(registry key)))))

(defmacro with-open
"A `c/with-open` variant that supports destructuring in bindings.
bindings => [name init ...]
Evaluates body in a try expression with names bound to the values
of the inits, and a finally clause that calls (.close name) on each
name in reverse order."
[bindings & body]
{:pre [(vector? bindings)
(even? (count bindings))]}
(if (zero? (count bindings))
`(do ~@body)
(let [[binding-form init-expr] (subvec bindings 0 2)]
`(let [resource# ~init-expr]
(try
(let [~binding-form resource#]
(with-open ~(subvec bindings 2)
~@body))
(finally
(.close resource#)))))))
24 changes: 12 additions & 12 deletions test/darkleaf/di/tutorial/q_starting_many_keys_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,29 @@
[darkleaf.di.core :as di]
[clojure.test :as t]))

;; The standard `with-open` does not support destructuring in bindings.
;; Use `di/with-open` to handle resources with destructuring support.

(def a :a)
(def b :b)

(t/deftest verbose-test
(with-open [root (di/start ::root {::root (di/template [(di/ref `a) (di/ref `b)])})]
(let [[a b] @root]
(t/is (= :a a))
(t/is (= :b b)))))
(di/with-open [[a b] (di/start ::root {::root (di/template [(di/ref `a) (di/ref `b)])})]
(t/is (= :a a))
(t/is (= :b b))))

;; The root container implements `clojure.lang.Indexed`
;; so you can use destructuring without derefing the root.

(t/deftest indexed-test
(with-open [root (di/start [`a `b])]
(let [[a b] root]
(t/is (= :a a))
(t/is (= :b b)))))
(di/with-open [[a b] (di/start [`a `b])]
(t/is (= :a a))
(t/is (= :b b))))

;; The root container implements `clojure.lang.ILookup`
;; so you can use destructuring without derefing the root.

(t/deftest lookup-test
(with-open [root (di/start {:a `a :b `b})]
(let [{:keys [a b]} root]
(t/is (= :a a))
(t/is (= :b b)))))
(di/with-open [{:keys [a b]} (di/start {:a `a :b `b})]
(t/is (= :a a))
(t/is (= :b b))))

0 comments on commit 9b36a26

Please sign in to comment.