Skip to content

Instantly share code, notes, and snippets.

@walterl
Created June 18, 2020 02:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save walterl/70607e342ea8bf6cd3f0b5b4c97379c8 to your computer and use it in GitHub Desktop.
Save walterl/70607e342ea8bf6cd3f0b5b4c97379c8 to your computer and use it in GitHub Desktop.
Figuring out how to change all references to a duct component, with another component
(ns overridetest.notworking
(:gen-class)
(:require [duct.core :as duct]
[integrant.core :as ig]))
(duct/load-hierarchy)
(derive ::daemon :duct/daemon)
(def config
{:duct.profile/base
{:duct.core/project-ns 'overridetest
::daemon {:email-client (ig/ref ::real-email-client)
:monitor (ig/ref ::monitor)}
::monitor {:email-client (ig/ref ::real-email-client)}
::real-email-client {}}
:duct.profile/dev
{;; I would _like_ to replace _all_ references to ::real-email-client with
;; references to ::dev-email-client, by _only_ adding to :duct.profile/dev.
;; In fact, ::real-email-client should not even be initialized.
;; Intuitively, the following is what I would expect to have to do to
;; override ::real-email-client with ::dev-email-client:
::real-email-client (ig/ref ::dev-email-client)
::dev-email-client {}
;; But it doesn't override references in ::monitor or ::daemon. It also
;; initializes both ::real-email-client _and_ ::dev-email-client.
;; The following works (and doesn't init ::real-email-client), but only
;; because I replace all references to ::real-email-client with
;; ::dev-email-client.
; ::daemon
; {:email-client (ig/ref ::dev-email-client)}
; ::monitor
; {:email-client (ig/ref ::dev-email-client)}
;; When there are many references to (e.g.) an email client in a system, it
;; becomes untenable to override each one individually.
}
:duct.profile/prod {}})
(defmethod ig/init-key ::daemon
[_ config]
(println "INIT SERVER:" config)
:daemon)
(defmethod ig/init-key ::monitor
[_ config]
(println "INIT MONITOR:" config)
:monitor)
(defmethod ig/init-key ::email-client
[_ {:keys [impl]}]
(println "INIT EMAIL CLIENT:" impl)
[_ {:keys [impl]}])
(defmethod ig/init-key ::real-email-client
[_ _]
(println "INIT REAL EMAIL CLIENT")
:real-email-client)
(defmethod ig/init-key ::dev-email-client
[_ _]
(println "INIT DEV EMAIL CLIENT")
:dev-email-client)
(defn -main [& args]
(let [keys (or (duct/parse-keys args) [:duct/daemon])
profiles [:duct.profile/dev]] ; XXX Notice that this is not `:duct.profile/prod`
(-> config
(duct/exec-config profiles keys))))
(ns overridetest.working
(:gen-class)
(:require [duct.core :as duct]
[integrant.core :as ig]))
(duct/load-hierarchy)
(derive ::daemon :duct/daemon)
(def config
{:duct.profile/base
{:duct.core/project-ns 'overridetest
::daemon {:email-client (ig/ref ::email-client)
:monitor (ig/ref ::monitor)}
::monitor {:email-client (ig/ref ::email-client)}
;; In order to change all references in one place, I had to introduce an
;; intermediate component, with the sole purpose of referencing the
;; "implementation" component to use.
::email-client {:impl (ig/ref ::real-email-client)}
::real-email-client {}
}
:duct.profile/dev
{::dev-email-client {}
;; Then I need only change the implementation component, and all
::email-client {:impl (ig/ref ::dev-email-client)}}
:duct.profile/prod {}})
(defmethod ig/init-key ::daemon
[_ config]
(println "INIT SERVER:" config)
:daemon)
(defmethod ig/init-key ::monitor
[_ config]
(println "INIT MONITOR:" config)
:monitor)
(defmethod ig/init-key ::email-client
[_ {:keys [impl]}]
(println "INIT EMAIL CLIENT:" impl)
;; It just returns the "implementation" component.
impl)
(defmethod ig/init-key ::real-email-client
[_ _]
(println "INIT REAL EMAIL CLIENT")
:real-email-client)
(defmethod ig/init-key ::dev-email-client
[_ _]
(println "INIT DEV EMAIL CLIENT")
:dev-email-client)
(defn -main [& args]
(let [keys (or (duct/parse-keys args) [:duct/daemon])
profiles [:duct.profile/dev]] ; XXX Notice that this is not `:duct.profile/prod`
(-> config
(duct/exec-config profiles keys))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment