|
@@ -60,6 +60,9 @@ A separation of concerns model for use on all platforms.
|
|
|
|
|
|
We use a custom lifecycle dispatcher that uses multimethods, as suggested by the author's documentation.
|
|
|
|
|
|
+Actually this style [is much slower](http://insideclojure.org/2015/04/27/poly-perf/) than Protocol based dispatch,
|
|
|
+but very nice to work with.
|
|
|
+
|
|
|
```clojure
|
|
|
(ns my.component
|
|
|
(:require [clojure.tools.logging :refer [debugf infof]
|
|
@@ -70,66 +73,52 @@ We use a custom lifecycle dispatcher that uses multimethods, as suggested by the
|
|
|
; namespaced keywords for dispatch
|
|
|
; (when (= *ns* 'my.component) (= ::my-message :my.component/my-message))
|
|
|
|
|
|
-(defmethod react :component/start [c]
|
|
|
+(defmethod react :component/start [component]
|
|
|
(debugf "Starting my.component"))
|
|
|
|
|
|
-(defmethod react :component/stop [c]
|
|
|
+(defmethod react :component/stop [component]
|
|
|
(debugf "Stopping my.component"))
|
|
|
|
|
|
-(defmethod react ::my-message [c msg]
|
|
|
- (infof "Got a message, what are we going to do about it? %s" msg))
|
|
|
+(defmethod react ::my-message [component event]
|
|
|
+ (infof "Got a event, what are we going to do about it? %s" event))
|
|
|
|
|
|
; alternative syntax (experimental)
|
|
|
(react-to ::my-message [event]
|
|
|
- (infof "Got a message, what are we going to do about it? %s" msg))
|
|
|
-```
|
|
|
-
|
|
|
-
|
|
|
+ (infof "Got an event, what are we going to do about it? %s" event))
|
|
|
```
|
|
|
|
|
|
-(defmacro defupon
|
|
|
- ""
|
|
|
- [command & body]
|
|
|
- (let [react-symbol (symbol (str *ns*) "upon")
|
|
|
- react-multi `(defmulti ~react-symbol #(:component/event %2))]
|
|
|
- `(do
|
|
|
- (when-not ~(find-var react-symbol)
|
|
|
- (println "Defining default react dispatcher: ")
|
|
|
- ~react-multi)
|
|
|
- (defmethod ~react-symbol ~command [~'component ~'event]
|
|
|
- ~@body))))
|
|
|
|
|
|
+A comparable protocol-based approach loses some of its niceness, but may win in dispatch speed. A macro could be constructed
|
|
|
+to use an in-memory map based dispatch (ie. constant lookup time).
|
|
|
|
|
|
-(let [say-reactor '(defupon :say
|
|
|
- (format "say with component=%s, event=%s" component event))]
|
|
|
- (println (macroexpand-1 say-reactor))
|
|
|
- (eval say-reactor))
|
|
|
-
|
|
|
-(let [component {:name :my.component}
|
|
|
- event {:component/event :say
|
|
|
- :message "hi"}]
|
|
|
- (upon component event))
|
|
|
-
|
|
|
+```clojure
|
|
|
+(ns my.component
|
|
|
+ (:require [clojure.tools.logging :refer [debugf infof]
|
|
|
+ [component :refer [event-key Lifecycle]]))
|
|
|
+
|
|
|
+(defrecord Reactor [dispatch]
|
|
|
+ Lifecycle
|
|
|
+ (start [component]
|
|
|
+ (debugf "Starting my.component"))
|
|
|
+ (stop [component]
|
|
|
+ (debugf "Stopping my.component"))
|
|
|
+
|
|
|
+ React
|
|
|
+ (react [component event]
|
|
|
+ (when-let [handler (get dispatch (event-key event))]
|
|
|
+ (handler component event))))
|
|
|
|
|
|
-```
|
|
|
|
|
|
-```
|
|
|
+(defn- my-message [component event]
|
|
|
+ (infof "Got an event, what are we going to do about it? %s" event)
|
|
|
|
|
|
-(defmacro defaction
|
|
|
- ""
|
|
|
- [command & body]
|
|
|
- `(let [react-symbol# ~(find-var (symbol (str *ns*) "react"))]
|
|
|
- (when-not react-symbol#
|
|
|
- (println "Defining default react dispatcher")
|
|
|
- (defmulti ~'react-symbol# #(:command %2)))
|
|
|
- (defmethod react-symbol# ~command [~'component ~'event]
|
|
|
- ~@body)))
|
|
|
+(def component (->Reactor {::my-message my-message}))
|
|
|
|
|
|
+;(react component event)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
-
|
|
|
### Marathon deployment
|
|
|
|
|
|
Deploy non-Docker packages. Nothing in particular against Docker, but I don't see the case for it with Marathon
|