This commit is contained in:
Tejas Dinkar 2017-04-07 00:09:20 +00:00 committed by GitHub
commit f84ce2bad3
3 changed files with 60 additions and 3 deletions

View file

@ -23,6 +23,7 @@ _**Alan J. Perlis** from [Structure and Interpretation of Computer Programs](htt
- [Using State](#using-state) - [Using State](#using-state)
- [Dependencies](#dependencies) - [Dependencies](#dependencies)
- [Talking States](#talking-states) - [Talking States](#talking-states)
- [Automatically Starting Dependencies](#automatically-starting-dependencies)
- [Value of Values](#value-of-values) - [Value of Values](#value-of-values)
- [The Importance of Being Reloadable](#the-importance-of-being-reloadable) - [The Importance of Being Reloadable](#the-importance-of-being-reloadable)
- [Start and Stop Order](#start-and-stop-order) - [Start and Stop Order](#start-and-stop-order)
@ -160,6 +161,20 @@ this `config`, being top level, can be used in other namespaces, including the o
[here](dev/clj/app/www.clj#L32) [here](dev/clj/app/www.clj#L32)
is an example of a web server that "depends" on a similar `config`. is an example of a web server that "depends" on a similar `config`.
### Automatically Starting Dependencies
It is also possible to start the dependencies of a state, when a particular state is started. We can modify the example above as follows
```clojure
(ns app.database
(:require [mount.core :refer [defstate]]
[app.config :refer [config]]))
(defstate conn :deps [#'config] :start (create-connection config))
(mount/start #'conn) ;; => {:started ["#'app.config/config" "#'app.database/conn"]}
```
## Value of values ## Value of values
Lifecycle functions start/stop can take both functions and values. This is "valuable" and also works: Lifecycle functions start/stop can take both functions and values. This is "valuable" and also works:

View file

@ -155,14 +155,15 @@
#?(:clj #?(:clj
(defmacro defstate [state & body] (defmacro defstate [state & body]
(let [[state params] (macro/name-with-attributes state body) (let [[state params] (macro/name-with-attributes state body)
{:keys [start stop] :as lifecycle} (apply hash-map params) {:keys [start stop deps] :as lifecycle} (apply hash-map params)
state-name (with-ns *ns* state) state-name (with-ns *ns* state)
order (make-state-seq state-name)] order (make-state-seq state-name)]
(validate lifecycle) (validate lifecycle)
(let [s-meta (cond-> {:order order (let [s-meta (cond-> {:order order
:start `(fn [] ~start) :start `(fn [] ~start)
:status #{:stopped}} :status #{:stopped}}
stop (assoc :stop `(fn [] ~stop)))] stop (assoc :stop `(fn [] ~stop))
deps (assoc :deps deps))]
`(do `(do
;; (log (str "|| mounting... " ~state-name)) ;; (log (str "|| mounting... " ~state-name))
(~'defonce ~state (DerefableState. ~state-name)) (~'defonce ~state (DerefableState. ~state-name))
@ -258,13 +259,22 @@
(defn- all-without-subs [] (defn- all-without-subs []
(remove (comp :sub? @meta-state) (find-all-states))) (remove (comp :sub? @meta-state) (find-all-states)))
(defn- deps-chain [states]
(when (seq states)
(into (set states)
(->> states
(map var-to-str)
(map @meta-state)
(mapcat :deps)
deps-chain))))
(defn start [& states] (defn start [& states]
(let [fs (-> states first)] (let [fs (-> states first)]
(if (coll? fs) (if (coll? fs)
(if-not (empty? fs) ;; (mount/start) vs. (mount/start #{}) vs. (mount/start #{1 2 3}) (if-not (empty? fs) ;; (mount/start) vs. (mount/start #{}) vs. (mount/start #{1 2 3})
(apply start fs) (apply start fs)
{:started #{}}) {:started #{}})
(let [states (or (seq states) (let [states (or (deps-chain states)
(all-without-subs))] (all-without-subs))]
{:started (bring states up <)})))) {:started (bring states up <)}))))

View file

@ -0,0 +1,32 @@
(ns core.mount.test.start-dependencies
(:require
#?@(:cljs [[cljs.test :as t :refer-macros [is deftest use-fixtures]]
[mount.core :as mount :refer-macros [defstate]]]
:clj [[clojure.test :as t :refer [is deftest use-fixtures]]
[mount.core :as mount :refer [defstate]]])
[mount.test.helper :refer [dval]]))
#?(:clj (alter-meta! *ns* assoc ::load false))
(defstate dependency-1 :start 1)
(defstate dependency-2 :start 2)
(defstate thing-to-start
:deps [#'dependency-1 #'dependency-2]
:start 3)
(defstate should-not-start :start 4)
(defn- start-states []
(mount/start #'dependency-1))
(use-fixtures :once
#?(:cljs {:before start-states
:after mount/stop}
:clj #((start-states) (%) (mount/stop))))
(deftest dependencies-test
(is (= {:started ["#'core.mount.test.start-dependencies/dependency-2" "#'core.mount.test.start-dependencies/thing-to-start"]}
(mount/start #'thing-to-start)))
(is (= 3 (dval thing-to-start)))
(is (= 2 (dval dependency-2)))
(is (= 1 (dval dependency-1)))
(is (instance? mount.core.NotStartedState (dval should-not-start))))