Back
ref (clj)
(source)function
(ref key)
Create a reference to a top-level key in a config map.
Examples
integrant
(ns integrant.core-test
(:require #?(:clj [clojure.test :refer [are deftest is testing]]
:cljs [cljs.test :refer-macros [are deftest is testing]])
[integrant.core :as ig]
[weavejester.dependency :as dep]))
(defmethod ig/prep-key ::p [_ v]
(merge {:a (ig/ref ::a)} v))
(deftest ref-test
(is (ig/ref? (ig/ref ::foo)))
(is (ig/ref? (ig/ref [::foo ::bar])))
(is (ig/reflike? (ig/ref ::foo)))
(is (ig/reflike? (ig/ref [::foo ::bar]))))
(deftest refset-test
(is (ig/refset? (ig/refset ::foo)))
(is (ig/refset? (ig/refset [::foo ::bar])))
(is (ig/reflike? (ig/refset ::foo)))
(is (ig/reflike? (ig/refset [::foo ::bar]))))
#?(:clj
(deftest read-string-test
(is (= (ig/read-string "{:foo/a #ig/ref :foo/b, :foo/b 1}")
{:foo/a (ig/ref :foo/b), :foo/b 1}))
(is (= (ig/read-string "{:foo/a #ig/refset :foo/b, :foo/b 1}")
{:foo/a (ig/refset :foo/b), :foo/b 1}))
(is (= (ig/read-string {:readers {'test/var find-var}}
"{:foo/a #test/var clojure.core/+}")
{:foo/a #'+}))))
(testing "some namespaces"
(remove-lib 'integrant.test.foo)
(remove-lib 'integrant.test.bar)
(remove-lib 'integrant.test.baz)
(remove-lib 'integrant.test.quz)
(is (= (set (ig/load-namespaces
{:integrant.test/foo 1
:integrant.test/bar (ig/ref :integrant.test/foo)
:integrant.test/baz 3}
[:integrant.test/bar]))
'#{integrant.test.foo
integrant.test.bar}))
(is (some? (find-ns 'integrant.test.foo)))
(is (some? (find-ns 'integrant.test.bar)))
(is (nil? (find-ns 'integrant.test.baz))))
(deftest dependency-graph-test
(let [m {::a (ig/ref ::p), ::b (ig/refset ::ppp) ::p 1, ::pp 2}]
(testing "graph with refsets"
(let [g (ig/dependency-graph m)]
(is (dep/depends? g ::a ::p))
(is (dep/depends? g ::b ::p))
(is (dep/depends? g ::b ::pp))))
(testing "graph without refsets"
(let [g (ig/dependency-graph m {:include-refsets? false})]
(is (dep/depends? g ::a ::p))
(is (not (dep/depends? g ::b ::p)))
(is (not (dep/depends? g ::b ::pp)))))))
(deftest key-comparator-test
(let [graph (ig/dependency-graph {::a (ig/ref ::ppp) ::p 1, ::b 2})]
(is (= (sort (ig/key-comparator graph) [::b ::a ::p])
[::p ::a ::b]))))
(testing "custom prep-key"
(is (= (ig/prep {::p {:b 2}, ::a 1})
{::p {:a (ig/ref ::a), :b 2}, ::a 1})))
(deftest expand-test
(testing "default expand"
(is (= (ig/expand {::unique 1})
{::unique 1})))
(testing "empty map values"
(is (= (ig/expand {::unique {}})
{::unique {}}))
(is (= (ig/expand {::a {}, ::mod-a {:x 1}})
{::a {:x 1}}))
(is (= (ig/expand {::z {}, ::mod-z {:x 1}})
{::z {:x 1}})))
(testing "single expand"
(is (= (ig/expand {::mod 1})
{::a 1, ::b {:v 1}})))
(testing "expand with unrelated keys"
(is (= (ig/expand {::mod 1, ::b {:x 1}, ::c 2})
{::a 1, ::b {:v 1, :x 1}, ::c 2})))
(testing "expand with direct override"
(is (= (ig/expand {::mod {:x 1}, ::a ^:override {:x 2}})
{::a {:x 2}, ::b {:v {:x 1}}})))
(testing "expand with nested override"
(is (= (ig/expand {::mod 1, ::b ^:override {:v 2}})
{::a 1, ::b {:v 2}}))
(is (= (ig/expand {::mod-c 1, ::c ^:override {:x {:y {:z 2}}}})
{::c {:x {:y {:z 2}}}})))
(testing "unresolved conflicting index"
(is (thrown-with-msg?
#?(:clj clojure.lang.ExceptionInfo :cljs cljs.core.ExceptionInfo)
(re-pattern (str "^Conflicting values at index "
"\\[:integrant\\.core-test/a\\] "
"for expansions: :integrant\\.core-test/mod, "
":integrant\\.core-test/mod-a\\. Use the "
"\\^:override metadata to set the preferred "
"value\\.$"))
(ig/expand {::mod 1, ::mod-a 2}))))
(testing "unresolved conflicting nested index"
(is (thrown-with-msg?
#?(:clj clojure.lang.ExceptionInfo :cljs cljs.core.ExceptionInfo)
(re-pattern (str "^Conflicting values at index "
"\\[:integrant\\.core-test/b :v\\] "
"for expansions: :integrant\\.core-test/mod, "
":integrant\\.core-test/mod-b\\. Use the "
"\\^:override metadata to set the preferred "
"value\\.$"))
(ig/expand {::mod 1, ::mod-b 2}))))
(testing "resolved conflict"
(is (= (ig/expand {::mod {:x 1}, ::mod-a {:x 2}, ::a ^:override {:x 3}})
{::a {:x 3}, ::b {:v {:x 1}}})))
(testing "resolved nested conflict"
(is (= (ig/expand {::mod 1, ::mod-b 2, ::b ^:override {:v 3}})
{::a 1, ::b {:v 3}}))
(is (= (ig/expand {[::one ::mod-c] 1
[::two ::mod-c] 2
::c ^:override {:x {:y {:z 3}}}})
{::c {:x {:y {:z 3}}}})))
(testing "expand with refs"
(let [m {::a (ig/ref ::b) ::b 1}]
(is (= m (ig/expand m))))
(let [m {::a (ig/refset ::b) ::b 1}]
(is (= m (ig/expand m))))))
(deftest init-test
(testing "without keys"
(reset! log [])
(let [m (ig/init {::a (ig/ref ::b), ::b 1})]
(is (= m {::a [[1]], ::b [1]}))
(is (= @log [[:init ::b 1]
[:init ::a [1]]]))))
(testing "with keys"
(reset! log [])
(let [m (ig/init {::a (ig/ref ::b), ::b 1, ::c 2} [::a])]
(is (= m {::a [[1]], ::b [1]}))
(is (= @log [[:init ::b 1]
[:init ::a [1]]]))))
(testing "with inherited keys"
(reset! log [])
(let [m (ig/init {::p (ig/ref ::a), ::a 1} [::pp])]
(is (= m {::p [[1]], ::a [1]}))
(is (= @log [[:init ::a 1]
[:init ::p [1]]]))))
(testing "with composite keys"
(reset! log [])
(let [m (ig/init {::a (ig/ref ::b), [::x ::b] 1})]
(is (= m {::a [:x], [::x ::b] :x}))
(is (= @log [[:init [::x ::b] 1]
[:init ::a :x]]))))
(testing "with composite refs"
(reset! log [])
(let [m (ig/init {::a (ig/ref [::b ::c]), [::b ::c ::e] 1, [::b ::d] 2})]
(is (= m {::a [[1]], [::b ::c ::e] [1], [::b ::d] [2]}))
(is (or (= @log [[:init [::b ::c ::e] 1]
[:init ::a [1]]
[:init [::b ::d] 2]])
(= @log [[:init [::b ::d] 2]
[:init [::b ::c ::e] 1]
[:init ::a [1]]])))))
(testing "with failing composite refs"
(reset! log [])
(is (thrown-with-msg?
#?(:clj clojure.lang.ExceptionInfo :cljs cljs.core.ExceptionInfo)
(re-pattern (str "^Invalid composite key: "
"\\[:integrant.core-test/a :b\\]. "
"Every keyword must be namespaced.$"))
(ig/init {[::a :b] :anything}))))
(testing "with custom resolve-key"
(let [m (ig/init {::a (ig/ref ::r), ::r 1})]
(is (= m {::a [1], ::r {:v 1}}))))
(testing "with refsets"
(reset! log [])
(let [m (ig/init {::a (ig/refset ::ppp), ::p 1, ::pp 2})]
(is (= m {::a [#{[1] [2]}], ::p [1], ::pp [2]}))
(is (= @log [[:init ::p 1]
[:init ::pp 2]
[:init ::a #{[1] [2]}]]))))
(testing "with refsets and keys"
(reset! log [])
(let [m {::a (ig/refset ::ppp), ::p 1, ::pp 2}]
(is (= (ig/init m [::a]) {::a [#{}]}))
(is (= (ig/init m [::a ::p]) {::a [#{[1]}] ::p [1]}))
(is (= (ig/init m [::a ::pp]) {::a [#{[1] [2]}] ::p [1] ::pp [2]}))))
(testing "large config"
(is (= (ig/init {:a/a1 {} :a/a2 {:_ (ig/ref :a/a1)}
:a/a3 {} :a/a4 {} :a/a5 {}
:a/a6 {} :a/a7 {} :a/a8 {}
:a/a9 {} :a/a10 {}})
{:a/a1 [{}] :a/a2 [{:_ [{}]}]
:a/a3 [{}] :a/a4 [{}] :a/a5 [{}]
:a/a6 [{}] :a/a7 [{}] :a/a8 [{}]
:a/a9 [{}] :a/a10 [{}]})))
(testing "with passing specs"
(let [m (ig/init {::n (ig/ref ::k), ::k 1})]
(is (= m {::n 2, ::k 1}))))
(testing "with failing asserts"
(is (thrown-with-msg?
#?(:clj clojure.lang.ExceptionInfo :cljs cljs.core.ExceptionInfo)
(re-pattern (str "Assertion failed on key " ::n
" when building system"))
(ig/init {::n (ig/ref ::k), ::k 1.1}))))
(deftest halt-test
(testing "without keys"
(reset! log [])
(let [m (ig/init {::a (ig/ref ::b), ::b 1})]
(ig/halt! m)
(is (= @log [[:init ::b 1]
[:init ::a [1]]
[:halt ::a [[1]]]
[:halt ::b [1]]]))))
(testing "with keys"
(reset! log [])
(let [m (ig/init {::a (ig/ref ::b), ::b (ig/ref ::c), ::c 1})]
(ig/halt! m [::a])
(is (= @log [[:init ::c 1]
[:init ::b [1]]
[:init ::a [[1]]]
[:halt ::a [[[1]]]]]))
(reset! log [])
(ig/halt! m [::c])
(is (= @log [[:halt ::a [[[1]]]]
[:halt ::b [[1]]]
[:halt ::c [1]]]))))
(testing "with partial system"
(reset! log [])
(let [m (ig/init {::a 1, ::b (ig/ref ::a)} [::a])]
(ig/halt! m)
(is (= @log [[:init ::a 1]
[:halt ::a [1]]]))))
(testing "with inherited keys"
(reset! log [])
(let [m (ig/init {::a (ig/ref ::p), ::p 1} [::a])]
(ig/halt! m [::pp])
(is (= @log [[:init ::p 1]
[:init ::a [1]]
[:halt ::a [[1]]]
[:halt ::p [1]]]))))
(testing "with composite keys"
(reset! log [])
(let [m (ig/init {::a (ig/ref ::b), [::x ::b] 1})]
(ig/halt! m)
(is (= @log [[:init [::x ::b] 1]
[:init ::a :x]
[:halt ::a [:x]]
[:halt [::x ::b] :x]])))))
(deftest suspend-resume-test
(testing "same configuration"
(reset! log [])
(let [c {::a (ig/ref ::b), ::b 1}
m (ig/init c)]
(ig/suspend! m)
(ig/resume c m)
(is (= @log [[:init ::b 1]
[:init ::a [1]]
[:suspend ::a [[1]]]
[:suspend ::b [1]]
[:resume ::b 1 1 [1]]
[:resume ::a [1] [1] [[1]]]]))))
(testing "missing keys"
(reset! log [])
(let [c {::a (ig/ref ::b), ::b 1}
m (ig/init c)]
(ig/suspend! m)
(ig/resume (dissoc c ::a) m)
(is (= @log [[:init ::b 1]
[:init ::a [1]]
[:suspend ::a [[1]]]
[:suspend ::b [1]]
[:halt ::a [[1]]]
[:resume ::b 1 1 [1]]]))))
(testing "missing refs"
(reset! log [])
(let [c {::a {:b (ig/ref ::b)}, ::b 1}
m (ig/init c)]
(ig/suspend! m)
(ig/resume {::a []} m)
(is (= @log [[:init ::b 1]
[:init ::a {:b [1]}]
[:suspend ::a [{:b [1]}]]
[:suspend ::b [1]]
[:halt ::b [1]]
[:resume ::a [] {:b [1]} [{:b [1]}]]]))))
(testing "with custom resolve-key"
(let [c {::a (ig/ref ::r), ::r 1}
m (ig/init c)
_ (ig/suspend! m)
m' (ig/resume c m)]
(is (= m m'))))
(testing "composite keys"
(reset! log [])
(let [c {::a (ig/ref ::x), [::b ::x] 1}
m (ig/init c)]
(ig/suspend! m)
(ig/resume c m)
(is (= @log [[:init [::b ::x] 1]
[:init ::a :x]
[:suspend ::a [:x]]
[:suspend [::b ::x] :x]
[:resume [::b ::x] 1 1 :x]
[:resume ::a :rx :x [:x]]]))))
(testing "resume key with dependencies"
(reset! log [])
(let [c {::a {:b (ig/ref ::b)}, ::b 1}
m (ig/init c [::a])]
(ig/suspend! m)
(ig/resume c m [::a])
(is (= @log
[[:init ::b 1]
[:init ::a {:b [1]}]
[:suspend ::a [{:b [1]}]]
[:suspend ::b [1]]
[:resume ::b 1 1 [1]]
[:resume ::a {:b [1]} {:b [1]} [{:b [1]}]]])))))
(deftest invalid-configs-test
(testing "ambiguous refs"
(is (thrown-with-msg?
#?(:clj clojure.lang.ExceptionInfo :cljs cljs.core.ExceptionInfo)
(re-pattern (str "Ambiguous key: " ::ppp "\\. "
"Found multiple candidates: "
"(" ::p ", " ::pp "|" ::pp ", " ::p ")"))
(ig/init {::a (ig/ref ::ppp), ::p 1, ::pp 2}))))
(testing "missing refs"
(is (thrown-with-msg?
#?(:clj clojure.lang.ExceptionInfo :cljs cljs.core.ExceptionInfo)
(re-pattern (str "Missing definitions for refs: " ::b))
(ig/init {::a (ig/ref ::b)}))))
(testing "missing refs with explicit keys"
(is (= (ig/init {::a (ig/ref ::ppp), ::p 1, ::pp 2} [::p ::pp])
{::p [1], ::pp [2]})))
(testing "missing refs with explicit keys"
(is (= (ig/init {::a 1, ::b (ig/ref ::c)} [::a])
{::a [1]}))))
(deftest build-test
(is (= [{::a [:build ::a [:build ::b 1]]
::b [:build ::b 1]}
[[:build ::b 1]
[:build ::a [:build ::b 1]]]]
(build-log {::a (ig/ref ::b)
::b 1}))))
(deftest run-test
(let [config {::a (ig/ref ::b), ::b 1}
[system _] (build-log config)]
(is (= [nil
[[:test ::b [:build ::b 1]]
[:test ::a [:build ::a [:build ::b 1]]]]]
(test-log ig/run! system)))
(is (= [nil
[[:test ::a [:build ::a [:build ::b 1]]]
[:test ::b [:build ::b 1]]]]
(test-log ig/reverse-run! system)))))
(deftest fold-test
(let [config {::a (ig/ref ::ppp), ::b (ig/ref ::pp), ::p 1, ::c 2}
system (ig/init config)]
(is (= (ig/fold system #(conj %1 [%2 %3]) [])
[[::p [1]] [::a [[1]]] [::b [[1]]] [::c [2]]]))))
(deftest wrapped-exception-test
(testing "exception when building"
(let [ex (try (ig/init {::a 1, ::error-init (ig/ref ::a)}) nil
(catch #?(:clj Throwable :cljs :default) t t))]
(is (some? ex))
(is (= (#?(:clj .getMessage :cljs ex-message) ex)
(str "Error on key " ::error-init " when building system")))
(is (= (ex-data ex)
{:reason ::ig/build-threw-exception
:system {::a [1]}
:function ig/init-key
:key ::error-init
:value [1]}))
(let [cause (#?(:clj .getCause :cljs ex-cause) ex)]
(is (some? cause))
(is (= (#?(:clj .getMessage :cljs ex-message) cause) "Testing"))
(is (= (ex-data cause) {:reason ::test})))))
(testing "exception when running"
(let [system (ig/init {::a 1
::error-halt (ig/ref ::a)
::b (ig/ref ::error-halt)
::c (ig/ref ::b)})
ex (try (ig/halt! system)
(catch #?(:clj Throwable :cljs :default) t t))]
(is (some? ex))
(is (= (#?(:clj .getMessage :cljs ex-message) ex)
(str "Error on key " ::error-halt " when running system")))
(is (= (ex-data ex)
{:reason ::ig/run-threw-exception
:system {::a [1], ::error-halt [[1]]
::b [[[1]]], ::c [[[[1]]]]}
:completed-keys '(::c ::b)
:remaining-keys '(::a)
:function ig/halt-key!
:key ::error-halt
:value [[1]]}))
(let [cause (#?(:clj .getCause :cljs ex-cause) ex)]
(is (some? cause))
(is (= (#?(:clj .getMessage :cljs ex-message) cause) "Testing"))
(is (= (ex-data cause) {:reason ::test}))))))
madstap/igviz
(ns kafka
(:require [integrant.core :as ig]
[madstap.igviz.alpha :as igviz]
[medley.core :as medley]))
(def sconf-old
{::db {:url "..."
:db-name "foo-db"}
::cache {:url "..."}
::server {:port 1234
:db (ig/ref ::db)
:cache (ig/ref ::cache)}})
(def sconf-new
(-> sconf-old
(dissoc ::cache)
(medley/dissoc-in [::server :cache])
(assoc ::elasticsearch {:url "..."})
(assoc-in [::server :elastic] (ig/ref ::elasticsearch))))
(def config
{::db {:url "..."}
::cache {:url "..."}
::server {:db (ig/ref ::db)
:cache (ig/ref ::cache)
:daemons (ig/refset :duct/daemon)
:all-topics (ig/refset ::topic)
;; :all-consumers (ig/refset ::consumer)
}
[::consumer1 ::consumer] {:topics [(ig/ref ::foo-topic)
(ig/ref ::bar-topic)]}
[::consumer2 ::consumer] {:topics [(ig/ref ::foo-topic)
(ig/ref ::bar-topic)
(ig/ref ::baz-topic)]}
::producer {:topic (ig/ref ::baz-topic)}
::error-component {:producer (ig/ref ::producer)
:consumer (ig/ref ::consumer1)
:foo (ig/ref ::bar-topic)}
[::foo-topic ::topic] {:topic-name "foo"}
[::bar-topic ::topic] {:topic-name "bar"}
[::baz-topic ::topic] {:topic-name "baz"}})