Merge branch '0.1.7'

Conflicts:
	.gitignore
	src/mount/core.cljc
This commit is contained in:
anatoly 2015-12-21 20:49:35 -05:00
commit a4dfe74c66
37 changed files with 479 additions and 212 deletions

1
.gitignore vendored
View file

@ -7,6 +7,7 @@ pom.xml.asc
dev/resources/public/js/*
figwheel_server.log
build.xml
doo-index.html
*.jar
*.class
/.lein-*

108
build.boot Normal file
View file

@ -0,0 +1,108 @@
(set-env!
:source-paths #{"src"}
:dependencies '[;; mount brings _no dependencies_, everything here is for
;; mount dev, examples apps and tests
[org.clojure/clojure "1.7.0" :scope "provided"]
[org.clojure/clojurescript "1.7.189" :scope "provided" :classifier "aot"]
[datascript "0.13.3" :scope "provided"]
[compojure "1.4.0" :scope "provided"]
[ring/ring-jetty-adapter "1.1.0" :scope "provided"]
[cheshire "5.5.0" :scope "provided"]
[hiccups "0.3.0" :scope "provided" :exclusions [org.clojure/clojurescript]]
[com.andrewmcveigh/cljs-time "0.3.14" :scope "provided"]
[ch.qos.logback/logback-classic "1.1.3" :scope "provided"]
[org.clojure/tools.logging "0.3.1" :scope "provided"]
[robert/hooke "1.3.0" :scope "provided"]
[org.clojure/tools.namespace "0.2.11" :scope "provided"]
[org.clojure/tools.nrepl "0.2.12" :scope "provided"]
[com.datomic/datomic-free "0.9.5327" :scope "provided" :exclusions [joda-time]]
;; boot clj
[boot/core "2.5.1" :scope "provided"]
[adzerk/bootlaces "0.1.13" :scope "test"]
[adzerk/boot-logservice "1.0.1" :scope "test"]
[adzerk/boot-test "1.0.6" :scope "test"]
;; boot cljs
[adzerk/boot-cljs "1.7.170-3" :scope "test"]
[adzerk/boot-cljs-repl "0.3.0" :scope "test"]
[pandeiro/boot-http "0.7.1-SNAPSHOT" :scope "test"]
[com.cemerick/piggieback "0.2.1" :scope "test" :exclusions [org.clojure/clojurescript]]
[weasel "0.7.0" :scope "test" :exclusions [org.clojure/clojurescript]]
[adzerk/boot-reload "0.4.2" :scope "test"]
[crisptrutski/boot-cljs-test "0.2.1-SNAPSHOT" :scope "test"]])
(require '[adzerk.bootlaces :refer :all]
'[adzerk.boot-test :as bt]
'[adzerk.boot-logservice :as log-service]
'[adzerk.boot-cljs :refer [cljs]]
'[adzerk.boot-cljs-repl :refer [cljs-repl start-repl]]
'[adzerk.boot-reload :refer [reload]]
'[pandeiro.boot-http :refer :all]
'[crisptrutski.boot-cljs-test :as tcs]
'[clojure.tools.logging :as log]
'[clojure.tools.namespace.repl :refer [set-refresh-dirs]])
(def +version+ "0.1.7-SNAPSHOT")
(bootlaces! +version+)
(def log4b
[:configuration
[:appender {:name "STDOUT" :class "ch.qos.logback.core.ConsoleAppender"}
[:encoder [:pattern "%-5level %logger{36} - %msg%n"]]]
[:root {:level "TRACE"}
[:appender-ref {:ref "STDOUT"}]]])
(deftask dev []
(set-env! :source-paths #(conj % "dev/clj" "dev/cljs"))
(alter-var-root #'log/*logger-factory*
(constantly (log-service/make-factory log4b)))
(apply set-refresh-dirs (get-env :directories))
(load-data-readers!)
(require 'dev)
(in-ns 'dev))
(deftask test []
(set-env! :source-paths #(conj % "test/core" "test/clj")) ;; (!) :source-paths must not overlap.
(bt/test))
(deftask test-cljs []
(set-env! :source-paths #(conj % "test/core" "test/cljs"))
(set-env! :resource-paths #{"test/resources"})
(comp
(tcs/test-cljs ;; :optimizations :advanced
:out-file "mount.js")))
(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"})))
(deftask cljs-example
"mount cljs example"
[]
(set-env! :source-paths #(conj % "dev/clj" "dev/cljs"))
(set-env! :resource-paths #{"dev/resources"})
(comp
(wait)
(serve :dir "dev/resources/public/")
(cljs-repl)
(cljs :optimizations :advanced :ids #{"mount"})))
(task-options!
push #(-> (into {} %) (assoc :ensure-branch nil))
pom {:project 'mount
:version +version+
:description "managing Clojure and ClojureScript app state since (reset)"
:url "https://github.com/tolitius/mount"
:scm {:url "https://github.com/tolitius/mount"}
:license {"Eclipse Public License"
"http://www.eclipse.org/legal/epl-v10.html"}})

View file

@ -2,9 +2,14 @@ machine:
java:
version: oraclejdk8
dependencies:
pre:
- wget https://github.com/boot-clj/boot-bin/releases/download/2.4.2/boot.sh
- mv boot.sh boot && chmod a+x boot && sudo mv boot /usr/local/bin
test:
override:
- lein do clean, test
- lein do clean, doo phantom test once
- lein do clean, cljsbuild once prod
- boot test
- boot test-cljs
- boot test-cljs-advanced
- lein test2junit

50
dev/clj/app/db.clj Normal file
View file

@ -0,0 +1,50 @@
(ns app.db
(:require [mount.core :refer [defstate]]
[datomic.api :as d]
[clojure.tools.logging :refer [info]]
[app.conf :refer [config]]))
(defn- new-connection [conf]
(info "conf: " conf)
(let [uri (get-in conf [:datomic :uri])]
(info "creating a connection to datomic:" uri)
(d/create-database uri)
(d/connect uri)))
(defn disconnect [conf conn]
(let [uri (get-in conf [:datomic :uri])]
(info "disconnecting from " uri)
(.release conn) ;; usually it's not released, here just to illustrate the access to connection on (stop)
(d/delete-database uri)))
(defstate conn :start (new-connection config)
:stop (disconnect config conn))
;; datomic schema (staging as an example)
(defn create-schema [conn]
(let [schema [{:db/id #db/id [:db.part/db]
:db/ident :order/symbol
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db/index true
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :order/bid
:db/valueType :db.type/bigdec
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :order/qty
:db/valueType :db.type/long
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :order/offer
:db/valueType :db.type/bigdec
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}]]
@(d/transact conn schema)))

View file

@ -1,10 +1,9 @@
(ns app.example
(:require [datomic.api :as d]
[clojure.tools.nrepl.server :refer [start-server stop-server]]
(:require [clojure.tools.nrepl.server :refer [start-server stop-server]]
[mount.core :as mount :refer [defstate]]
[app.utils.datomic :refer [touch]]
[app.conf :refer [config]]
[app.nyse :as nyse]))
[app.www])
(:gen-class)) ;; for -main / uberjar (no need in dev)
;; example on creating a network REPL
(defn- start-nrepl [{:keys [host port]}]
@ -14,52 +13,6 @@
(defstate nrepl :start (start-nrepl (:nrepl config))
:stop (stop-server nrepl))
;; datomic schema
(defn create-schema [conn]
(let [schema [{:db/id #db/id [:db.part/db]
:db/ident :order/symbol
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db/index true
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :order/bid
:db/valueType :db.type/bigdec
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :order/qty
:db/valueType :db.type/long
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}
{:db/id #db/id [:db.part/db]
:db/ident :order/offer
:db/valueType :db.type/bigdec
:db/cardinality :db.cardinality/one
:db.install/_attribute :db.part/db}]]
@(d/transact conn schema)))
(defn add-order [ticker bid offer qty] ;; can take connection as param
@(d/transact nyse/conn [{:db/id (d/tempid :db.part/user)
:order/symbol ticker
:order/bid bid
:order/offer offer
:order/qty qty}]))
(defn find-orders [ticker] ;; can take connection as param
(let [orders (d/q '[:find ?e :in $ ?ticker
:where [?e :order/symbol ?ticker]]
(d/db nyse/conn) ticker)]
(touch nyse/conn orders)))
(defn create-nyse-schema []
(create-schema nyse/conn))
;; example of an app entry point
(defn -main [& args]
(mount/start))

View file

@ -1,21 +1,20 @@
(ns app.nyse
(:require [mount.core :as mount :refer [defstate]]
[datomic.api :as d]
[clojure.tools.logging :refer [info]]
[app.conf :refer [config]]))
(:require [datomic.api :as d]
[app.db :refer [create-schema] :as db]
[app.utils.datomic :refer [touch]]))
(defn- new-connection [conf]
(info "conf: " conf)
(let [uri (get-in conf [:datomic :uri])]
(info "creating a connection to datomic:" uri)
(d/create-database uri)
(d/connect uri)))
(defn add-order [ticker bid offer qty] ;; can take connection as param
@(d/transact db/conn [{:db/id (d/tempid :db.part/user)
:order/symbol ticker
:order/bid bid
:order/offer offer
:order/qty qty}]))
(defn disconnect [conf conn]
(let [uri (get-in conf [:datomic :uri])]
(info "disconnecting from " uri)
(.release conn) ;; usually it's not released, here just to illustrate the access to connection on (stop)
(d/delete-database uri)))
(defn find-orders [ticker] ;; can take connection as param
(let [orders (d/q '[:find ?e :in $ ?ticker
:where [?e :order/symbol ?ticker]]
(d/db db/conn) ticker)]
(touch db/conn orders)))
(defstate conn :start (new-connection config)
:stop (disconnect config conn))
(defn create-nyse-schema []
(create-schema db/conn))

31
dev/clj/app/www.clj Normal file
View file

@ -0,0 +1,31 @@
(ns app.www
(:require [app.nyse :refer [add-order find-orders create-nyse-schema]]
[app.conf :refer [config]]
[mount.core :refer [defstate]]
[cheshire.core :refer [generate-string]]
[compojure.core :refer [routes defroutes GET POST]]
[compojure.handler :as handler]
[ring.adapter.jetty :refer [run-jetty]]))
(defroutes mount-example-routes
(GET "/" [] "welcome to mount sample app!")
(GET "/nyse/orders/:ticker" [ticker]
(generate-string (find-orders ticker)))
(POST "/nyse/orders" [ticker qty bid offer]
(add-order ticker (bigdec bid) (bigdec offer) (Integer/parseInt qty))
(generate-string {:added {:ticker ticker
:qty qty
:bid bid
:offer offer}})))
(defn start-nyse [{:keys [www]}]
(create-nyse-schema) ;; creating schema (usually done long before the app is started..)
(-> (routes mount-example-routes)
(handler/site)
(run-jetty {:join? false
:port (:port www)})))
(defstate nyse-app :start (start-nyse config)
:stop (.stop nyse-app)) ;; it's a "org.eclipse.jetty.server.Server" at this point

View file

@ -1,23 +1,18 @@
(ns dev
"Tools for interactive development with the REPL. This file should
not be included in a production build of the application."
(:require [clojure.java.io :as io]
[clojure.java.javadoc :refer [javadoc]]
[clojure.pprint :refer [pprint]]
[clojure.reflect :refer [reflect]]
[clojure.repl :refer [apropos dir doc find-doc pst source]]
[clojure.set :as set]
[clojure.string :as str]
[clojure.test :as test]
(:require [clojure.pprint :refer [pprint]]
[clojure.tools.namespace.repl :as tn]
[boot.core :refer [load-data-readers!]]
[mount.core :as mount]
[app.utils.logging :refer [with-logging-status]]
[app.example :refer [create-nyse-schema find-orders add-order]])) ;; <<<< replace this your "app" namespace(s) you want to be available at REPL time
[app.www]
[app.example]
[app.nyse :refer [create-nyse-schema find-orders add-order]])) ;; <<<< replace this your "app" namespace(s) you want to be available at REPL time
(defn start []
(with-logging-status)
(mount/start #'app.conf/config
#'app.nyse/conn
#'app.db/conn
#'app.www/nyse-app
#'app.example/nrepl)) ;; example on how to start app with certain states
(defn stop []
@ -44,3 +39,4 @@
(tn/refresh :after 'dev/go))
(mount/in-clj-mode)
(load-data-readers!)

View file

@ -1,6 +1,8 @@
{:datomic
{:uri "datomic:mem://mount"}
:www {:port 4242}
:h2
{:classname "org.h2.Driver"
:subprotocol "h2"

View file

@ -0,0 +1 @@
{:require [app.example]}

View file

@ -1,6 +1,6 @@
<!DOCTYPE html>
<html>
<body>
<script src="js/compiled/mount.js" type="text/javascript"></script>
<script src="../mount.js" type="text/javascript"></script>
</body>
</html>

View file

@ -1,5 +1,5 @@
(defproject mount "0.1.6"
:description "managing Clojure app state since (reset)"
(defproject mount "0.1.7-SNAPSHOT"
:description "managing Clojure and ClojureScript app state since (reset)"
:url "https://github.com/tolitius/mount"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
@ -8,10 +8,13 @@
:dependencies [] ;; for visual clarity
:profiles {:dev {:source-paths ["dev" "dev/clj"]
:profiles {:dev {:source-paths ["dev" "dev/clj" "test/clj"]
:dependencies [[org.clojure/clojure "1.7.0"]
[org.clojure/clojurescript "1.7.170"]
[org.clojure/clojurescript "1.7.170"]; :classifier "aot"]
[datascript "0.13.3"]
[compojure "1.4.0"]
[ring/ring-jetty-adapter "1.1.0"]
[cheshire "5.5.0"]
[hiccups "0.3.0"]
[com.andrewmcveigh/cljs-time "0.3.14"]
[ch.qos.logback/logback-classic "1.1.3"]
@ -58,4 +61,4 @@
:optimizations :advanced
:pretty-print false}}}}}
:test {:source-paths ["dev" "test/clj" "test"]}})
:test {:source-paths ["test/core" "test/clj" "test/cljs"]}})

View file

@ -1,8 +1,8 @@
(ns mount.core
#?(:clj (:require [mount.tools.macro :refer [on-error throw-runtime] :as macro])
:cljs (:require [mount.tools.macro :as macro]
[mount.tools.cljs :as cljs]))
#?(:cljs (:require-macros [mount.tools.macro :refer [on-error throw-runtime]])))
:cljs (:require [mount.tools.macro :as macro]))
#?(:cljs (:require-macros [mount.core]
[mount.tools.macro :refer [on-error throw-runtime]])))
(defonce ^:private -args (atom :no-args)) ;; mostly for command line args and external files
(defonce ^:private state-seq (atom 0))
@ -34,13 +34,12 @@
(str "#'" ns "/" name))
(defn- pounded? [f]
(let [pound "(fn* [] "] ;;TODO: think of a better (i.e. typed) way to distinguish #(f params) from (fn [params] (...)))
#?(:clj (.startsWith (str f) pound)
:cljs (cljs/starts-with? (str f) pound))))
(let [pound "(fn* [] "] ;;TODO: think of a better (i.e. typed) way to distinguish #(f params) from (fn [params] (...)))
(.startsWith (str f) pound)))
(defn unpound [f]
(if (pounded? f)
(nth f 2) ;; magic 2 is to get the body => ["fn*" "[]" "(fn body)"]
(nth f 2) ;; magic 2 is to get the body => ["fn*" "[]" "(fn body)"]
f))
(defn- cleanup-if-dirty
@ -50,29 +49,30 @@
it is meant to be called by defstate before defining a new state"
[state]
(when-let [stop (@running state)]
(prn (str "<< stopping.. " state " (namespace was recompiled)"))
(stop)
(swap! running dissoc state)))
#?(:clj
(defn current-state [state]
(let [{:keys [inst var]} (@meta-state state)]
(if (= @mode :cljc)
@inst
(var-get var))))
(defn current-state [state]
(let [{:keys [inst var]} (@meta-state state)]
(if (= @mode :cljc)
@inst
(var-get var))))
:cljs
(defn current-state [state]
(-> (@meta-state state) :inst deref)))
(defn current-state [state]
(-> (@meta-state state) :inst deref)))
#?(:clj
(defn alter-state! [{:keys [var inst]} value]
(if (= @mode :cljc)
(reset! inst value)
(alter-var-root var (constantly value))))
(defn alter-state! [{:keys [var inst]} value]
(if (= @mode :cljc)
(reset! inst value)
(alter-var-root var (constantly value))))
:cljs
(defn alter-state! [{:keys [inst]} value]
(reset! inst value)))
(defn alter-state! [{:keys [inst]} value]
(reset! inst value)))
(defn- update-meta! [path v]
(swap! meta-state assoc-in path v))
@ -127,26 +127,35 @@
(up name state (atom #{})))
@inst)))
(defmacro defstate [state & body]
(let [[state params] (macro/name-with-attributes state body)
{:keys [start stop suspend resume] :as lifecycle} (apply hash-map params)
state-name (with-ns #?(:clj *ns*
:cljs (cljs/this-ns)) state) ;; on cljs side (cljs.analyzer/*cljs-ns*) may do it, but still might not be good for :advanced
order (make-state-seq state-name)
sym (str state)]
(validate lifecycle)
(cleanup-if-dirty state-name)
(let [s-meta (cond-> {:order order
:start `(fn [] ~start)
:status #{:stopped}}
stop (assoc :stop `(fn [] ~stop))
suspend (assoc :suspend `(fn [] ~suspend))
resume (assoc :resume `(fn [] ~resume)))]
`(do
(def ~state (DerefableState. ~state-name))
((var update-meta!) [~state-name] (assoc ~s-meta :inst (atom (NotStartedState. ~state-name))
:var (var ~state)))
(var ~state)))))
#?(:clj
(defmacro defstate [state & body]
(let [[state params] (macro/name-with-attributes state body)
{:keys [start stop suspend resume] :as lifecycle} (apply hash-map params)
state-name (with-ns *ns* state)
order (make-state-seq state-name)
sym (str state)]
(validate lifecycle)
(cleanup-if-dirty state-name)
(let [s-meta (cond-> {:order order
:start `(fn [] ~start)
:status #{:stopped}}
stop (assoc :stop `(fn [] ~stop))
suspend (assoc :suspend `(fn [] ~suspend))
resume (assoc :resume `(fn [] ~resume)))]
`(do
(def ~state (DerefableState. ~state-name))
((var mount.core/update-meta!) [~state-name] (assoc ~s-meta :inst (atom (NotStartedState. ~state-name))
:var (var ~state)))
(var ~state))))))
#?(:clj
(defmacro defstate! [state & {:keys [start! stop!]}]
(let [state-name (with-ns *ns* state)]
`(defstate ~state
:start (~'let [~state (mount/current-state ~state-name)]
~start!)
:stop (~'let [~state (mount/current-state ~state-name)]
~stop!)))))
(defn in-cljc-mode []
(reset! mode :cljc))
@ -182,7 +191,7 @@
#?(:cljs
(defn var-to-str [v]
(if (var? v)
(if (instance? cljs.core.Var v)
(let [{:keys [ns name]} (meta v)]
(with-ns ns name))
v)))

View file

@ -1,9 +0,0 @@
(ns mount.tools.cljs
(:require [cljs.analyzer :as ana]
[goog.string :as gstring]))
(defn this-ns []
ana/*cljs-ns*)
(defn starts-with? [s pre]
(gstring/startsWith s pre))

View file

@ -1,16 +1,19 @@
(ns mount.tools.macro)
(ns mount.tools.macro
#?(:cljs (:require-macros [mount.tools.macro])))
(defmacro on-error [msg f]
`(try
~f
(catch #?(:clj Throwable
:cljs :default) t#
(throw #?(:clj (RuntimeException. ~msg t#)
:cljs (js/Error (str ~msg (.-stack t#))))))))
#?(:clj
(defmacro on-error [msg f]
`(try
~f
(catch #?(:clj Throwable
:cljs :default) t#
(throw #?(:clj (RuntimeException. ~msg t#)
:cljs (js/Error (str ~msg (.-stack t#)))))))))
(defmacro throw-runtime [msg]
`(throw #?(:clj (RuntimeException. ~msg)
:cljs (js/Error (str ~msg)))))
#?(:clj
(defmacro throw-runtime [msg]
`(throw #?(:clj (RuntimeException. ~msg)
:cljs (js/Error (str ~msg))))))
;; this is a one to one copy from https://github.com/clojure/tools.macro
;; to avoid a lib dependency for a single function

View file

@ -1,8 +1,10 @@
(ns app.conf
(ns tapp.conf
(:require [mount.core :as mount :refer [defstate]]
[clojure.edn :as edn]
[clojure.tools.logging :refer [info]]))
(alter-meta! *ns* assoc ::load false)
(defn load-config [path]
(info "loading config from" path)
(-> path

View file

@ -1,10 +1,12 @@
(ns app.example
(ns tapp.example
(:require [datomic.api :as d]
[clojure.tools.nrepl.server :refer [start-server stop-server]]
[mount.core :as mount :refer [defstate]]
[app.utils.datomic :refer [touch]]
[app.conf :refer [config]]
[app.nyse :as nyse]))
[tapp.utils.datomic :refer [touch]]
[tapp.conf :refer [config]]
[tapp.nyse :as nyse]))
(alter-meta! *ns* assoc ::load false)
;; example on creating a network REPL
(defn- start-nrepl [{:keys [host port]}]

View file

@ -1,8 +1,10 @@
(ns app.nyse
(ns tapp.nyse
(:require [mount.core :as mount :refer [defstate]]
[datomic.api :as d]
[clojure.tools.logging :refer [info]]
[app.conf :refer [config]]))
[tapp.conf :refer [config]]))
(alter-meta! *ns* assoc ::load false)
(defn- new-connection [conf]
(info "conf: " conf)

View file

@ -1,6 +1,8 @@
(ns app.utils.datomic
(ns tapp.utils.datomic
(:require [datomic.api :as d]))
(alter-meta! *ns* assoc ::load false)
(defn entity [conn id]
(d/entity (d/db conn) id))

View file

@ -1,4 +1,4 @@
(ns app.utils.logging ;; << change to your namespace/path
(ns tapp.utils.logging ;; << change to your namespace/path
(:require [mount.core]
[robert.hooke :refer [add-hook clear-hooks]]
[clojure.string :refer [split]]

View file

@ -0,0 +1,25 @@
(ns tapp.audit-log
(:require [datascript.core :as d]
[cljs-time.core :refer [now]])
(:require-macros [mount.core :refer [defstate]]))
(defstate log :start (d/create-conn {}))
(defn audit [db source & msg]
(d/transact! @db [{:db/id -1
:source source
:timestamp (now)
:msg (apply str msg)}]))
(defn find-source-logs [db source]
(d/q '{:find [?t ?msg]
:in [$ ?s]
:where [[?e :source ?s]
[?e :timestamp ?t]
[?e :msg ?msg]]}
@@db source))
(defn find-all-logs [db]
(->> (map :e (d/datoms @@db :aevt :timestamp))
dedupe
(d/pull-many @@db '[:timestamp :source :msg])))

9
test/cljs/tapp/conf.cljs Normal file
View file

@ -0,0 +1,9 @@
(ns tapp.conf
(:require [tapp.audit-log :refer [audit log]])
(:require-macros [mount.core :refer [defstate]]))
(defn load-config [path]
(audit log :app-conf "loading config from '" path "' (at least pretending)")
{:system-a {:uri "ws://echo.websocket.org/"}})
(defstate config :start (load-config "resources/config.end"))

View file

@ -0,0 +1,26 @@
(ns tapp.example
(:require [mount.core :as mount]
[tapp.conf]
[tapp.websockets]
[tapp.audit-log :refer [log find-all-logs]]
[cljs-time.format :refer [unparse formatters]]
[hiccups.runtime :as hiccupsrt])
(:require-macros [hiccups.core :as hiccups :refer [html]]))
(defn format-log-event [{:keys [timestamp source msg]}]
(str (unparse (formatters :date-hour-minute-second-fraction) timestamp)
" &#8594; [" (name source) "]: " msg))
(defn show-log []
(.write js/document
(html [:ul (doall (for [e (find-all-logs log)]
[:li (format-log-event e)]))])))
(mount/start)
;; time to establish a websocket connection before disconnecting
(js/setTimeout #(mount/stop-except "#'tapp.audit-log/log") 500)
;; time to close a connection to show it in audit
(js/setTimeout #(show-log) 1000)

View file

@ -0,0 +1,22 @@
(ns tapp.websockets
(:require [tapp.conf :refer [config]]
[tapp.audit-log :refer [audit log]])
(:require-macros [mount.core :refer [defstate]]))
(defn ws-status [ws]
{:url (.-url ws) :ready-state (.-readyState ws)})
(defn connect [uri]
(let [ws (js/WebSocket. uri)]
(audit log :system-a "connecting to " (ws-status ws))
(set! (.-onopen ws) #(audit log :system-a "opened " (ws-status ws)))
(set! (.-onclose ws) #(audit log :system-a "closed " (ws-status ws)))
ws))
(defn disconnect [ws]
(audit log :system-a "closing " (ws-status @ws))
(.close @ws)
(audit log :system-a "disconnecting " (ws-status @ws)))
(defstate system-a :start (connect (get-in @config [:system-a :uri]))
:stop (disconnect system-a))

View file

@ -15,6 +15,8 @@
mount.test.suspend-resume
))
#?(:clj (alter-meta! *ns* assoc ::load false))
(mount.core/in-cljc-mode)
#?(:cljs

View file

@ -2,23 +2,25 @@
(:require
#?@(:cljs [[cljs.test :as t :refer-macros [is are deftest testing use-fixtures]]
[mount.core :as mount :refer-macros [defstate]]
[app.websockets :refer [system-a]]
[app.conf :refer [config]]
[app.audit-log :refer [log]]]
[tapp.websockets :refer [system-a]]
[tapp.conf :refer [config]]
[tapp.audit-log :refer [log]]]
:clj [[clojure.test :as t :refer [is are deftest testing use-fixtures]]
[mount.core :as mount :refer [defstate]]
[app.example]])
[tapp.example]])
[mount.test.helper :refer [dval helper forty-two]]))
#?(:clj (alter-meta! *ns* assoc ::load false))
#?(:clj
(deftest cleanup-dirty-states
(let [_ (mount/start)]
(is (not (.isClosed (:server-socket (dval app.example/nrepl)))))
(require 'app.example :reload)
(is (not (.isClosed (:server-socket (dval tapp.example/nrepl)))))
(require 'tapp.example :reload)
(mount/start) ;; should not result in "BindException Address already in use" since the clean up will stop the previous instance
(is (not (.isClosed (:server-socket (dval app.example/nrepl)))))
(is (not (.isClosed (:server-socket (dval tapp.example/nrepl)))))
(mount/stop)
(is (instance? mount.core.NotStartedState (dval app.example/nrepl))))))
(is (instance? mount.core.NotStartedState (dval tapp.example/nrepl))))))
#?(:cljs
(deftest cleanup-dirty-states

View file

@ -5,6 +5,8 @@
:clj [[clojure.test :as t :refer [is are deftest testing use-fixtures]]
[mount.core :as mount :refer [defstate]]])))
#?(:clj (alter-meta! *ns* assoc ::load false))
(defn f [n]
(fn [m]
(+ n m)))

View file

@ -3,6 +3,8 @@
#?@(:cljs [[mount.core :as mount :refer-macros [defstate]]]
:clj [[mount.core :as mount :refer [defstate]]])))
#?(:clj (alter-meta! *ns* assoc ::load false))
(defn dval
"returns a value of DerefableState without deref'ing it"
[d]

View file

@ -2,24 +2,26 @@
(:require
#?@(:cljs [[cljs.test :as t :refer-macros [is are deftest testing use-fixtures]]
[mount.core :as mount :refer-macros [defstate]]
[app.websockets :refer [system-a]]
[app.conf :refer [config]]
[app.audit-log :refer [log]]]
[tapp.websockets :refer [system-a]]
[tapp.conf :refer [config]]
[tapp.audit-log :refer [log]]]
:clj [[clojure.test :as t :refer [is are deftest testing use-fixtures]]
[mount.core :as mount :refer [defstate]]
[app.nyse :refer [conn]]])
[tapp.nyse :refer [conn]]])
[mount.test.helper :refer [dval]]))
#?(:clj (alter-meta! *ns* assoc ::load false))
(defstate should-not-start :start (constantly 42))
#?(:clj
(defn with-parts [f]
(mount/start #'app.conf/config #'app.nyse/conn)
(mount/start #'tapp.conf/config #'tapp.nyse/conn)
(f)
(mount/stop)))
(use-fixtures :once
#?(:cljs {:before #(mount/start #'app.conf/config #'app.audit-log/log)
#?(:cljs {:before #(mount/start #'tapp.conf/config #'tapp.audit-log/log)
:after mount/stop}
:clj with-parts))

View file

@ -7,6 +7,8 @@
[mount.test.fun-with-values :refer [private-f]]))
#?(:clj (alter-meta! *ns* assoc ::load false))
(use-fixtures :once
#?(:cljs {:before #(mount/start #'mount.test.fun-with-values/private-f)
:after mount/stop}

View file

@ -2,16 +2,18 @@
(:require
#?@(:cljs [[cljs.test :as t :refer-macros [is are deftest testing use-fixtures]]
[mount.core :as mount :refer-macros [defstate]]
[app.websockets :refer [system-a]]
[app.conf :refer [config]]
[app.audit-log :refer [log]]]
[tapp.websockets :refer [system-a]]
[tapp.conf :refer [config]]
[tapp.audit-log :refer [log]]]
:clj [[clojure.test :as t :refer [is are deftest testing use-fixtures]]
[mount.core :as mount :refer [defstate]]
[app.conf :refer [config]]
[app.nyse :refer [conn]]
[app.example :refer [nrepl]]])
[tapp.conf :refer [config]]
[tapp.nyse :refer [conn]]
[tapp.example :refer [nrepl]]])
[mount.test.helper :refer [dval helper]]))
#?(:clj (alter-meta! *ns* assoc ::load false))
(defstate test-conn :start 42
:stop (constantly 0))
@ -21,7 +23,7 @@
(deftest start-with
(testing "should start with substitutes"
(let [_ (mount/start-with {#'app.websockets/system-a #'mount.test.start-with/test-conn
(let [_ (mount/start-with {#'tapp.websockets/system-a #'mount.test.start-with/test-conn
#'mount.test.helper/helper #'mount.test.start-with/test-nrepl})]
(is (map? (dval config)))
(is (vector? (dval helper)))
@ -30,7 +32,7 @@
(mount/stop)))
(testing "should not start the substitute itself"
(let [_ (mount/start-with {#'app.websockets/system-a #'mount.test.start-with/test-conn})]
(let [_ (mount/start-with {#'tapp.websockets/system-a #'mount.test.start-with/test-conn})]
(is (instance? mount.core.NotStartedState (dval test-conn)))
(is (= 42 (dval system-a)))
(mount/stop)))
@ -60,15 +62,15 @@
(deftest start-with
(testing "should start with substitutes"
(let [_ (mount/start-with {#'app.nyse/conn #'mount.test.start-with/test-conn
#'app.example/nrepl #'mount.test.start-with/test-nrepl})]
(let [_ (mount/start-with {#'tapp.nyse/conn #'mount.test.start-with/test-conn
#'tapp.example/nrepl #'mount.test.start-with/test-nrepl})]
(is (map? (dval config)))
(is (vector? (dval nrepl)))
(is (= (dval conn) 42))
(mount/stop)))
(testing "should not start the substitute itself"
(let [_ (mount/start-with {#'app.nyse/conn #'mount.test.start-with/test-conn})]
(let [_ (mount/start-with {#'tapp.nyse/conn #'mount.test.start-with/test-conn})]
(is (instance? mount.core.NotStartedState (dval test-conn)))
(is (= (dval conn) 42))
(mount/stop)))

View file

@ -2,24 +2,26 @@
(:require
#?@(:cljs [[cljs.test :as t :refer-macros [is are deftest testing use-fixtures]]
[mount.core :as mount :refer-macros [defstate]]
[app.websockets :refer [system-a]]
[app.conf :refer [config]]
[app.audit-log :refer [log]]]
[tapp.websockets :refer [system-a]]
[tapp.conf :refer [config]]
[tapp.audit-log :refer [log]]]
:clj [[clojure.test :as t :refer [is are deftest testing use-fixtures]]
[mount.core :as mount :refer [defstate]]
[app.conf :refer [config]]
[app.nyse :refer [conn]]
[app.example :refer [nrepl]]])
[tapp.conf :refer [config]]
[tapp.nyse :refer [conn]]
[tapp.example :refer [nrepl]]])
[mount.test.helper :refer [dval helper]]))
#?(:clj (alter-meta! *ns* assoc ::load false))
#?(:clj
(defn without [f]
(mount/start-without #'app.nyse/conn #'app.example/nrepl)
(mount/start-without #'tapp.nyse/conn #'tapp.example/nrepl)
(f)
(mount/stop)))
(use-fixtures :once
#?(:cljs {:before #(mount/start-without #'mount.test.helper/helper #'app.websockets/system-a)
#?(:cljs {:before #(mount/start-without #'mount.test.helper/helper #'tapp.websockets/system-a)
:after mount/stop}
:clj without))

View file

@ -2,22 +2,24 @@
(:require
#?@(:cljs [[cljs.test :as t :refer-macros [is are deftest testing use-fixtures]]
[mount.core :as mount :refer-macros [defstate]]
[app.websockets :refer [system-a]]
[app.conf :refer [config]]
[app.audit-log :refer [log]]]
[tapp.websockets :refer [system-a]]
[tapp.conf :refer [config]]
[tapp.audit-log :refer [log]]]
:clj [[clojure.test :as t :refer [is are deftest testing use-fixtures]]
[mount.core :as mount :refer [defstate]]
[app.conf :refer [config]]
[app.nyse :refer [conn]]
[app.example :refer [nrepl]]])
[tapp.conf :refer [config]]
[tapp.nyse :refer [conn]]
[tapp.example :refer [nrepl]]])
[mount.test.helper :refer [dval helper]]))
#?(:clj (alter-meta! *ns* assoc ::load false))
#?(:cljs
(deftest stop-except
(testing "should stop all except nrepl"
(let [_ (mount/start)
_ (mount/stop-except #'app.audit-log/log #'mount.test.helper/helper)]
_ (mount/stop-except #'tapp.audit-log/log #'mount.test.helper/helper)]
(is (= :started (dval helper)))
(is (instance? datascript.db/DB @(dval log)))
(is (instance? mount.core.NotStartedState (dval config)))
@ -33,7 +35,7 @@
(testing "should stop all normally after stop-except"
(let [_ (mount/start)
_ (mount/stop-except #'app.audit-log/log #'mount.test.helper/helper)
_ (mount/stop-except #'tapp.audit-log/log #'mount.test.helper/helper)
_ (mount/stop)]
(is (instance? mount.core.NotStartedState (dval config)))
(is (instance? mount.core.NotStartedState (dval log)))
@ -44,7 +46,7 @@
(testing "should stop all except nrepl"
(let [_ (mount/start)
_ (mount/stop-except #'app.nyse/conn #'app.conf/config)]
_ (mount/stop-except #'tapp.nyse/conn #'tapp.conf/config)]
(is (map? (dval config)))
(is (instance? datomic.peer.LocalConnection (dval conn)))
(is (instance? mount.core.NotStartedState (dval nrepl)))
@ -59,7 +61,7 @@
(testing "should stop all normally after stop-except"
(let [_ (mount/start)
_ (mount/stop-except #'app.nyse/conn #'app.conf/config)
_ (mount/stop-except #'tapp.nyse/conn #'tapp.conf/config)
_ (mount/stop)]
(is (instance? mount.core.NotStartedState (dval config)))
(is (instance? mount.core.NotStartedState (dval conn)))

View file

@ -2,16 +2,18 @@
(:require
#?@(:cljs [[cljs.test :as t :refer-macros [is are deftest testing use-fixtures]]
[mount.core :as mount :refer-macros [defstate]]
[app.websockets :refer [system-a]]
[app.conf :refer [config]]
[app.audit-log :refer [log]]]
[tapp.websockets :refer [system-a]]
[tapp.conf :refer [config]]
[tapp.audit-log :refer [log]]]
:clj [[clojure.test :as t :refer [is are deftest testing use-fixtures]]
[mount.core :as mount :refer [defstate]]
[app.conf :refer [config]]
[app.nyse :refer [conn]]
[app.example :refer [nrepl]]])
[tapp.conf :refer [config]]
[tapp.nyse :refer [conn]]
[tapp.example :refer [nrepl]]])
[mount.test.helper :refer [dval]]))
#?(:clj (alter-meta! *ns* assoc ::load false))
(defn koncat [k s]
(-> (name k)
(str "-" (name s))
@ -48,7 +50,7 @@
(testing "should resume _only suspendable_ states that are currently suspended"
(let [_ (mount/start)
_ (mount/stop #'app.websockets/system-a)
_ (mount/stop #'tapp.websockets/system-a)
_ (mount/suspend)
_ (mount/resume)]
(is (map? (dval config)))
@ -82,7 +84,7 @@
(testing "when replacing a non suspendable state with a suspendable one,
the later should be able to suspend/resume,
the original should not be suspendable after resume and preserve its lifecycle fns after rollback/stop"
(let [_ (mount/start-with {#'app.websockets/system-a #'mount.test.suspend-resume/web-server})
(let [_ (mount/start-with {#'tapp.websockets/system-a #'mount.test.suspend-resume/web-server})
_ (mount/suspend)]
(is (= (dval system-a) :w-suspended))
(is (instance? mount.core.NotStartedState (dval web-server)))
@ -107,7 +109,7 @@
(testing "should resume _only suspendable_ states that are currently suspended"
(let [_ (mount/start)
_ (mount/stop #'app.example/nrepl)
_ (mount/stop #'tapp.example/nrepl)
_ (mount/suspend)
_ (mount/resume)]
(is (map? (dval config)))
@ -142,7 +144,7 @@
(testing "when replacing a non suspendable state with a suspendable one,
the later should be able to suspend/resume,
the original should not be suspendable after resume and preserve its lifecycle fns after rollback/stop"
(let [_ (mount/start-with {#'app.example/nrepl #'mount.test.suspend-resume/web-server})
(let [_ (mount/start-with {#'tapp.example/nrepl #'mount.test.suspend-resume/web-server})
_ (mount/suspend)]
(is (= (dval nrepl) :w-suspended))
(is (instance? mount.core.NotStartedState (dval web-server)))
@ -176,7 +178,7 @@
the original should still be suspended and preserve its lifecycle fns after the rollback/stop"
(let [_ (mount/start)
_ (mount/suspend)
_ (mount/start-with {#'mount.test.suspend-resume/web-server #'app.nyse/conn}) ;; TODO: good to WARN on started states during "start-with"
_ (mount/start-with {#'mount.test.suspend-resume/web-server #'tapp.nyse/conn}) ;; TODO: good to WARN on started states during "start-with"
_ (mount/suspend)]
(is (instance? datomic.peer.LocalConnection (dval conn)))
(is (= (dval web-server) :w-suspended)) ;; since the "conn" does not have a resume method, so web-server was not started

View file

@ -2,6 +2,8 @@
(:require [clojure.test :as t :refer [is are deftest testing use-fixtures]]
[mount.core :as mount :refer [defstate]]))
(alter-meta! *ns* assoc ::load false)
(defn f [n]
(fn [m]
(+ n m)))

View file

@ -3,6 +3,8 @@
[mount.core :as mount :refer [defstate]]
[mount.test.var.fun-with-values :refer [private-f]]))
(alter-meta! *ns* assoc ::load false)
(defn in-clj-mode [f]
(mount/in-clj-mode)
(require :reload 'mount.test.var.fun-with-values 'mount.test.var.private-fun)

View file

@ -0,0 +1 @@
{:require [mount.test]}