edos

*Experimental* Clojure/Clojurescript event- and effect-handling patterns


License
EPL-1.0

Documentation

edos

EXPERIMENTAL Clojure/Script event/effect framework leveraging the power of core.async & clojure.spec. Strongly inspired by re-frame.

Usage

FIXME

Examples

Responding to a HTTP request

(ns example-http
  (:require [clojure.spec.alpha :as s]
            [edos.core :as e :refer :all]))

(enable-instrumentation! true)

(s/def ::path string?)
(s/def ::method #{:GET :POST})
(s/def ::request (s/keys :req-un [::method ::path]))
(s/def ::db-query string?)
(s/def ::username string?)
(s/def ::msg string?)
(s/def ::db-response-success (s/keys :req-un [::username]))
(s/def ::db-response-failure (s/keys :opt-un [::msg]))

(defeffect
  :log                           ;; this is an effect tag
  [data any?]                    ;; event and effect arguments are spec'd
  (println "effect - log" data)) ;; the effects body, the return value will be ignored

(defevent
  ::http-router                  ;; event tags must be qualified keywords
  [{:keys [method path]} ::request]
  (println "event - http request")
  ;; do routing here!
  (let [users-match (re-matches #"/users/(\d+)" path)
        user-id (last users-match)]
    ;; events are free of side effects, but they return a map which will
    ;; trigger one or more effects (or dispatch other events):
    {::db-get [(str "select * from users where id = '" user-id "'")
               ::db-get-user-success
               ::db-get-user-failure]
     :log     ["another effect"]}))

(defeffect
  ::db-get
  [query ::db-query, on-success ::e/event-tag, on-failure ::e/event-tag]
  (println "effect - side-effecty db query `" query "`")
  ;; effects do not return any values, they just cause side effects, like I/O, or dispatching events:
  (if (rand-nth [true false])
    (dispatch [on-success {:username "cecil"}])
    (dispatch [on-failure {::msg "something went wrong"}])))

(defevent
  ::db-get-user-success
  "docstrings work as expected"
  [data ::db-response-success]
  (println "event - get user successful!")
  {:response [200 data]})

(defevent
  ::db-get-user-failure
  [data ::db-response-failure]
  (println "event - get user failed! :(")
  {:response [500 (:msg data)]})

;; put it all together by dispatching an event and waiting for a certain effect (:response, in this case): 

(dispatch [::http-router {:method :GET :path "/users/42"}])

(->> (await! #{:response})
     (println "end -"))

License

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.