From c56bbfcd405814c12f33d93e7f028018bffd0bf7 Mon Sep 17 00:00:00 2001 From: anatoly Date: Thu, 3 Nov 2016 22:18:26 -0400 Subject: [PATCH 1/8] removing log on state discovery --- src/mount/core.cljc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mount/core.cljc b/src/mount/core.cljc index 4973067..d9c8664 100644 --- a/src/mount/core.cljc +++ b/src/mount/core.cljc @@ -144,7 +144,7 @@ :status #{:stopped}} stop (assoc :stop `(fn [] ~stop)))] `(do - (log (str "|| mounting... " ~state-name)) + ;; (log (str "|| mounting... " ~state-name)) (~'defonce ~state (DerefableState. ~state-name)) (mount-it (~'var ~state) ~state-name ~s-meta) (~'var ~state)))))) From f49fceb518f6379bb9fdbc673698d20ecb92a01e Mon Sep 17 00:00:00 2001 From: anatoly Date: Mon, 14 Nov 2016 17:25:00 -0500 Subject: [PATCH 2/8] #65: (mount/start #{}) is a noop --- src/mount/core.cljc | 12 ++++++++---- test/core/mount/test/composable_fns.cljc | 6 ++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/mount/core.cljc b/src/mount/core.cljc index d9c8664..774d657 100644 --- a/src/mount/core.cljc +++ b/src/mount/core.cljc @@ -244,10 +244,14 @@ (remove (comp :sub? @meta-state) (find-all-states))) (defn start [& states] - (if (-> states first coll?) - (apply start (first states)) - (let [states (or (seq states) (all-without-subs))] - {:started (bring states up <)}))) + (let [fs (-> states first)] + (if (coll? fs) + (if-not (empty? fs) ;; (mount/start) vs. (mount/start #{}) vs. (mount/start #{1 2 3}) + (apply start fs) + {:started #{}}) + (let [states (or (seq states) + (all-without-subs))] + {:started (bring states up <)})))) (defn stop [& states] (let [states (or states (find-all-states)) diff --git a/test/core/mount/test/composable_fns.cljc b/test/core/mount/test/composable_fns.cljc index ab7ff5b..c7ecdb8 100644 --- a/test/core/mount/test/composable_fns.cljc +++ b/test/core/mount/test/composable_fns.cljc @@ -154,4 +154,10 @@ (is (= {:datomic {:uri "datomic:mem://composable-mount"}} (dval config))) (is (instance? datomic.peer.LocalConnection (dval conn))) (is (vector? (dval nrepl))) + (mount/stop))) + + (testing "should not start anything on empty seq of states" + (let [scope #{}] + (is (= {:started #{}} (-> (only scope) + mount/start))) (mount/stop))))) From 087683968ddd467998935178b4bf48682f1d5bf3 Mon Sep 17 00:00:00 2001 From: anatoly Date: Mon, 21 Nov 2016 12:26:26 -0500 Subject: [PATCH 3/8] running-states to return a set --- src/mount/core.cljc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mount/core.cljc b/src/mount/core.cljc index 774d657..7da09d6 100644 --- a/src/mount/core.cljc +++ b/src/mount/core.cljc @@ -182,7 +182,7 @@ v))) (defn running-states [] - (keys @running)) + (set (keys @running))) (defn- unvar-state [s] (->> s (drop 2) (apply str))) ;; magic 2 is removing "#'" in state name From e2ef7bba558cc2dd831b311d0c11b728220b1c7f Mon Sep 17 00:00:00 2001 From: anatoly Date: Thu, 24 Nov 2016 01:54:24 -0500 Subject: [PATCH 4/8] #68: swap-states and start-with-states take values in a form of {:start fn :stop fn} --- README.md | 20 +++++++++----- src/mount/core.cljc | 8 +++--- test/core/mount/test/composable_fns.cljc | 25 ++++++++++------- test/core/mount/test/start_with_states.cljc | 30 ++++++++++++++------- 4 files changed, 53 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 26a5920..989861d 100644 --- a/README.md +++ b/README.md @@ -274,7 +274,7 @@ Each "tool" has a single responsibility and can be composed with other tools in * `only` will return _only_ states that it is given + exist (seen by mount) in the application * `except` will return all the states that it is given _except_ a given set * `swap` will take a map with keys as states and values as their substitute values -* `swap-states` will take a map with keys as states and values as their substitute states +* `swap-states` will take a map with keys as states and values with `{:start fn :stop fn}` as their substitute states * `with-args` will take a map that could later be accessed by `(mount/args)` All these functions take one or two arguments. If called with two arguments, the first one will be treated as the universe of states to work with. If called with one argument, it will work with _all known_ to mount states. @@ -312,7 +312,8 @@ Here is a more "involved" example: (with-args {:a 42}) (except [#'foo/c #'bar/d]) - (swap-states {#'foo/a #'test/a}) + (swap-states {#'foo/a {:start #(create-connection test-conf) + :stop #(disconnect a)}}) (swap {#'baz/e {:datomic {:uri "datomic:mem://composable-mount"}}}) mount/start) ``` @@ -381,14 +382,21 @@ When running tests it would be great _not_ to send the real text messages, but r ### Swapping States with States -The `start-with-states` function takes other states as substitutes: +The `start-with-states` function takes values in a form of `{:start fn :stop fn}` as substitutes: ```clojure -(mount/start-with-states {#'app.neo/db #'app.test/test-db - #'app.neo/publisher #'app.test/test-publisher}) +(mount/start-with-states {#'app.neo/db {:start #(connect test-config) + :stop #(disconnect db)} + #'app.neo/publisher {:start #(create-pub test-config) + :stop #(close-pub publisher)}}) ``` -`start-with-states` takes a map of states with their substitutes. For example `#'app.nyse/db` here is the real deal (remote) DB that is being substituted with `#'app.test/test-db` state, which could be anything, a map, an in memory DB, etc. +`start-with-states` takes a map of states with their substitutes. For example `#'app.nyse/db` here is the real deal (remote) DB that is being +substituted with `#(connect test-config)` function, which could endup being anything, a map, an in memory DB, etc. + +The `:stop` functions of substitutes can be anything, and could refer to the original state references. As in the example above: `db` and `publisher` +are real references. They would need to be accessible from the namespace of course, so you might need to `(:require [app.neo :refer [db]])` +in order to use `db` in `:stop #(disconnect db)` example above. -- diff --git a/src/mount/core.cljc b/src/mount/core.cljc index 7da09d6..c53701c 100644 --- a/src/mount/core.cljc +++ b/src/mount/core.cljc @@ -231,9 +231,7 @@ origin (@meta-state state) sub (if (= :value mode) {:start (fn [] with) :status :stopped} - (@meta-state with))] - (when (= :state mode) - (update-meta! [with :sub?] true)) + (assoc with :status :stopped))] (update-meta! [state] (merge-lifecycles origin (lifecycle-fns origin) sub)))) (defn- unsub [state] @@ -302,7 +300,7 @@ ([states with] (doseq [[from to] with] (substitute! (var-to-str from) - (var-to-str to) :state)) + to :state)) states)) ;; restart on events @@ -354,7 +352,7 @@ (defn start-with-states [with] (doseq [[from to] with] (substitute! (var-to-str from) - (var-to-str to) :state)) + to :state)) (start)) (defn start-without [& states] diff --git a/test/core/mount/test/composable_fns.cljc b/test/core/mount/test/composable_fns.cljc index c7ecdb8..a886413 100644 --- a/test/core/mount/test/composable_fns.cljc +++ b/test/core/mount/test/composable_fns.cljc @@ -8,6 +8,7 @@ [tapp.audit-log :refer [log]]] :clj [[clojure.test :as t :refer [is are deftest testing use-fixtures]] [clojure.set :refer [intersection]] + [clojure.tools.nrepl.server :refer [start-server stop-server]] [mount.core :as mount :refer [defstate only except swap swap-states with-args]] [tapp.conf :refer [config]] [tapp.nyse :refer [conn]] @@ -21,6 +22,12 @@ (defstate test-nrepl :start []) +(def swap-conn {:start (fn [] 42) + :stop #(println "stopping test-conn-state")}) +#?(:clj + (def swap-nrepl {:start #(start-server :bind "localhost" :port 3442) + :stop #(stop-server @nrepl)})) + #?(:clj (deftest only-states @@ -93,19 +100,19 @@ (deftest swap-states-with-states (testing "swap-states should swap states with states and return all mount states if none is given" - (let [states (swap-states {#'tapp.nyse/conn #'mount.test.composable-fns/test-conn - #'tapp.example/nrepl #'mount.test.composable-fns/test-nrepl})] + (let [states (swap-states {#'tapp.nyse/conn swap-conn + #'tapp.example/nrepl swap-nrepl})] (is (= states (#'mount.core/find-all-states))) (mount/start) (is (map? (dval config))) - (is (vector? (dval nrepl))) + (is (instance? clojure.tools.nrepl.server.Server (dval nrepl))) (is (= 42 (dval conn))) (mount/stop))) (testing "swap-states should swap states with states and return only states that it is given" (let [t-states #{"#'is.not/here" #'mount.test.composable-fns/test-conn #'tapp.nyse/conn} - states (swap-states t-states {#'tapp.nyse/conn #'mount.test.composable-fns/test-conn - #'tapp.example/nrepl #'mount.test.composable-fns/test-nrepl})] + states (swap-states t-states {#'tapp.nyse/conn swap-conn + #'tapp.example/nrepl swap-nrepl})] (is (= states t-states)) (apply mount/start states) (is (instance? mount.core.NotStartedState (dval config))) @@ -127,14 +134,14 @@ (with-args {:a 42}) (except [#'mount.test.composable-fns/test-nrepl #'mount.test.composable-fns/test-conn]) - (swap-states {#'tapp.example/nrepl #'mount.test.composable-fns/test-nrepl}) + (swap-states {#'tapp.example/nrepl swap-nrepl}) (swap {#'tapp.conf/config {:datomic {:uri "datomic:mem://composable-mount"}}}))] (is (= #{"#'tapp.nyse/conn" "#'tapp.conf/config" "#'tapp.example/nrepl"} (set states))) (mount/start states) (is (= {:a 42} (mount/args))) (is (= {:datomic {:uri "datomic:mem://composable-mount"}} (dval config))) (is (instance? datomic.peer.LocalConnection (dval conn))) - (is (vector? (dval nrepl))) + (is (instance? clojure.tools.nrepl.server.Server (dval nrepl))) (mount/stop))) (testing "should compose and start in a single composition" @@ -147,13 +154,13 @@ (with-args {:a 42}) (except [#'mount.test.composable-fns/test-nrepl #'mount.test.composable-fns/test-conn]) - (swap-states {#'tapp.example/nrepl #'mount.test.composable-fns/test-nrepl}) + (swap-states {#'tapp.example/nrepl swap-nrepl}) (swap {#'tapp.conf/config {:datomic {:uri "datomic:mem://composable-mount"}}}) mount/start) (is (= {:a 42} (mount/args))) (is (= {:datomic {:uri "datomic:mem://composable-mount"}} (dval config))) (is (instance? datomic.peer.LocalConnection (dval conn))) - (is (vector? (dval nrepl))) + (is (instance? clojure.tools.nrepl.server.Server (dval nrepl))) (mount/stop))) (testing "should not start anything on empty seq of states" diff --git a/test/core/mount/test/start_with_states.cljc b/test/core/mount/test/start_with_states.cljc index 62688f4..7bde387 100644 --- a/test/core/mount/test/start_with_states.cljc +++ b/test/core/mount/test/start_with_states.cljc @@ -7,6 +7,7 @@ [tapp.audit-log :refer [log]]] :clj [[clojure.test :as t :refer [is are deftest testing use-fixtures]] [mount.core :as mount :refer [defstate]] + [clojure.tools.nrepl.server :refer [start-server stop-server]] [tapp.conf :refer [config]] [tapp.nyse :refer [conn]] [tapp.example :refer [nrepl]]]) @@ -19,20 +20,29 @@ (defstate test-nrepl :start []) +(def swap-conn {:start (fn [] 42) + :stop #(println "stopping test-conn-state")}) +#?(:clj + (def swap-nrepl {:start #(start-server :bind "localhost" :port 3442) + :stop #(stop-server @nrepl)}) + :cljs + (def swap-nrepl {:start (fn [] :nrepl) + :stop (fn [] :stopped-nrepl)})) + #?(:cljs (deftest start-with-states (testing "should start with substitutes" - (let [_ (mount/start-with-states {#'tapp.websockets/system-a #'mount.test.start-with-states/test-conn - #'mount.test.helper/helper #'mount.test.start-with-states/test-nrepl})] + (let [_ (mount/start-with-states {#'tapp.websockets/system-a swap-conn + #'mount.test.helper/helper swap-nrepl})] (is (map? (dval config))) - (is (vector? (dval helper))) + (is (= (:nrepl (dval helper)))) (is (= (dval system-a) 42)) (is (instance? datascript.db/DB @(dval log))) (mount/stop))) - (testing "should not start the substitute itself" - (let [_ (mount/start-with-states {#'tapp.websockets/system-a #'mount.test.start-with-states/test-conn})] + #_(testing "should not start the substitute itself" ;; was true when subbing with exsiting states + (let [_ (mount/start-with-states {#'tapp.websockets/system-a swap-conn})] (is (instance? mount.core.NotStartedState (dval test-conn))) (is (= 42 (dval system-a))) (mount/stop))) @@ -62,15 +72,15 @@ (deftest start-with-states (testing "should start with substitutes" - (let [_ (mount/start-with-states {#'tapp.nyse/conn #'mount.test.start-with-states/test-conn - #'tapp.example/nrepl #'mount.test.start-with-states/test-nrepl})] + (let [_ (mount/start-with-states {#'tapp.nyse/conn swap-conn + #'tapp.example/nrepl swap-nrepl})] (is (map? (dval config))) - (is (vector? (dval nrepl))) + (is (instance? clojure.tools.nrepl.server.Server (dval nrepl))) (is (= (dval conn) 42)) (mount/stop))) - (testing "should not start the substitute itself" - (let [_ (mount/start-with-states {#'tapp.nyse/conn #'mount.test.start-with-states/test-conn})] + #_(testing "should not start the substitute itself" ;; was true when subbing with exsiting states + (let [_ (mount/start-with-states {#'tapp.nyse/conn swap-conn})] (is (instance? mount.core.NotStartedState (dval test-conn))) (is (= (dval conn) 42)) (mount/stop))) From 62cb9dd516eb1f194ccf2a3268908c7ba549fc78 Mon Sep 17 00:00:00 2001 From: anatoly Date: Mon, 28 Nov 2016 11:30:38 -0500 Subject: [PATCH 5/8] #69: stop accepts collections of states vs. an implicit all and varargs --- src/mount/core.cljc | 18 ++++++++++++------ test/core/mount/test/composable_fns.cljc | 12 +++++++++++- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/mount/core.cljc b/src/mount/core.cljc index c53701c..0545103 100644 --- a/src/mount/core.cljc +++ b/src/mount/core.cljc @@ -244,7 +244,7 @@ (defn start [& states] (let [fs (-> states first)] (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) {:started #{}}) (let [states (or (seq states) @@ -252,11 +252,17 @@ {:started (bring states up <)})))) (defn stop [& states] - (let [states (or states (find-all-states)) - _ (dorun (map unsub states)) ;; unmark substitutions marked by "start-with" - stopped (bring states down >)] - (dorun (map rollback! states)) ;; restore to origin from "start-with" - {:stopped stopped})) + (let [fs (-> states first)] + (if (coll? fs) + (if-not (empty? fs) ;; (mount/start) vs. (mount/start #{}) vs. (mount/start #{1 2 3}) + (apply stop fs) + {:stopped #{}}) + (let [states (or (seq states) + (find-all-states)) + _ (dorun (map unsub states)) ;; unmark substitutions marked by "start-with" + stopped (bring states down >)] + (dorun (map rollback! states)) ;; restore to origin from "start-with" + {:stopped stopped})))) ;; composable set of states diff --git a/test/core/mount/test/composable_fns.cljc b/test/core/mount/test/composable_fns.cljc index a886413..b8b6ee2 100644 --- a/test/core/mount/test/composable_fns.cljc +++ b/test/core/mount/test/composable_fns.cljc @@ -167,4 +167,14 @@ (let [scope #{}] (is (= {:started #{}} (-> (only scope) mount/start))) - (mount/stop))))) + (mount/stop))) + + (testing "should not stop anything on empty seq of states" + (let [scope #{}] + (mount/start) + (is (instance? datomic.peer.LocalConnection (dval conn))) + (is (= {:stopped #{}} (-> (only scope) + mount/stop))) + (is (instance? datomic.peer.LocalConnection (dval conn))) + (mount/stop) + (is (instance? mount.core.NotStartedState (dval conn))))))) From 49591d436855c55cfc2dc1ede5416a09280dc52a Mon Sep 17 00:00:00 2001 From: anatoly Date: Mon, 28 Nov 2016 11:43:57 -0500 Subject: [PATCH 6/8] #69: fixing comments "start" => "stop" --- src/mount/core.cljc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mount/core.cljc b/src/mount/core.cljc index 0545103..468beee 100644 --- a/src/mount/core.cljc +++ b/src/mount/core.cljc @@ -254,14 +254,14 @@ (defn stop [& states] (let [fs (-> states first)] (if (coll? fs) - (if-not (empty? fs) ;; (mount/start) vs. (mount/start #{}) vs. (mount/start #{1 2 3}) + (if-not (empty? fs) ;; (mount/stop) vs. (mount/stop #{}) vs. (mount/stop #{1 2 3}) (apply stop fs) {:stopped #{}}) (let [states (or (seq states) (find-all-states)) - _ (dorun (map unsub states)) ;; unmark substitutions marked by "start-with" + _ (dorun (map unsub states)) ;; unmark substitutions marked by "start-with" / "swap-states" stopped (bring states down >)] - (dorun (map rollback! states)) ;; restore to origin from "start-with" + (dorun (map rollback! states)) ;; restore to origin from "start-with" / "swap-states" {:stopped stopped})))) ;; composable set of states From f38bc2f0e75c7633536e0a61a1716406387b37df Mon Sep 17 00:00:00 2001 From: anatoly Date: Fri, 2 Dec 2016 13:44:14 -0600 Subject: [PATCH 7/8] opening find-all-states --- src/mount/core.cljc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mount/core.cljc b/src/mount/core.cljc index 468beee..e1d57d4 100644 --- a/src/mount/core.cljc +++ b/src/mount/core.cljc @@ -167,7 +167,7 @@ ;;TODO args might need more thinking (defn args [] @-args) -(defn- find-all-states [] +(defn find-all-states [] (keys @meta-state)) #?(:clj From c9945aef5b842360e95ff600294e94cf52a50617 Mon Sep 17 00:00:00 2001 From: anatoly Date: Fri, 2 Dec 2016 16:33:40 -0600 Subject: [PATCH 8/8] adding a proto-repl playground --- build.boot | 12 ++++++++---- dev/clj/proto_play.clj | 15 +++++++++++++++ src/mount/tools/graph.cljc | 1 - 3 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 dev/clj/proto_play.clj diff --git a/build.boot b/build.boot index fa9db02..aa55217 100644 --- a/build.boot +++ b/build.boot @@ -20,6 +20,10 @@ [org.clojure/tools.nrepl "0.2.12" :scope "provided"] [com.datomic/datomic-free "0.9.5359" :scope "provided" :exclusions [joda-time]] + ;; proto repl for fun and joy + [proto-repl "0.3.1" :scope "provided"] + [proto-repl-charts "0.3.2" :scope "provided"] + ;; boot clj [boot/core "2.6.0" :scope "provided"] [adzerk/bootlaces "0.1.13" :scope "test"] @@ -62,7 +66,7 @@ (deftask dev [] (set-env! :source-paths #(conj % "dev/clj" "dev/cljs")) - (alter-var-root #'log/*logger-factory* + (alter-var-root #'log/*logger-factory* (constantly (log-service/make-factory log4b))) (apply set-refresh-dirs (get-env :directories)) (load-data-readers!) @@ -80,7 +84,7 @@ (require '[mount.core]) - (comp + (comp (strip-deps-attr :attr :classifier :value "aot") (tcs/test-cljs ;; :optimizations :advanced :out-file "mount.js"))) @@ -88,7 +92,7 @@ (deftask test-cljs-advanced [] (set-env! :source-paths #(conj % "dev/clj" "dev/cljs")) (set-env! :resource-paths #{"dev/resources"}) - + (comp (cljs :optimizations :advanced :ids #{"mount"}))) @@ -114,7 +118,7 @@ (cljs-repl) (cljs :optimizations :none :ids #{"mount"}))) -(deftask cljs-example +(deftask cljs-example "mount cljs example" [] (set-env! :source-paths #(conj % "dev/clj" "dev/cljs")) diff --git a/dev/clj/proto_play.clj b/dev/clj/proto_play.clj new file mode 100644 index 0000000..580b8b9 --- /dev/null +++ b/dev/clj/proto_play.clj @@ -0,0 +1,15 @@ +(ns proto-play + (:require [mount.tools.graph :as mount] + [proto-repl-charts.graph :as proto])) + +(defn mount->proto [graph] + (reduce (fn [g {:keys [name deps]}] + (-> g + (update :nodes conj name) + (update :edges conj (-> deps (conj name) vec)))) + {} + graph)) + +(->> (mount/states-with-deps) + mount->proto + (proto/graph "a proto graph of mount states")) diff --git a/src/mount/tools/graph.cljc b/src/mount/tools/graph.cljc index d84031a..8083f88 100644 --- a/src/mount/tools/graph.cljc +++ b/src/mount/tools/graph.cljc @@ -24,4 +24,3 @@ meta-with-ns) states) (sort-by :order))))) -