Skip to content

Instantly share code, notes, and snippets.

@jcromartie
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jcromartie/23f0bf7c3956172169b6 to your computer and use it in GitHub Desktop.
Save jcromartie/23f0bf7c3956172169b6 to your computer and use it in GitHub Desktop.
Totally naive event based system in Clojure
(defonce handlers (atom {}))
(defn- install-handler!
[topic-key f]
(swap! handlers assoc topic-key f))
(defmacro on
"Registers a global message handler for the given topic keyword. A
single handler can be registered at a time for a given topic
keyword. Handlers are dispatched based on the name portion of the
topic keyword, so you may register multiple handlers for the same
message topic by namespacing the keyword."
[topic binding & body]
`(install-handler! ~topic (fn ~binding ~@body)))
(defn raise!
"Raise an event with a given topic keyword and data. Data will be
passed to any registered handlers in parallel."
[topic data]
(doseq [[handler-topic handler-fn] @handlers]
(when (= (name topic) (name handler-topic))
(future
(try
(handler-fn data)
(catch Throwable t
(println "Error in handler" handler-topic "-" (.getMessage t))))))))
;; example use
(comment
;;; a business logic namespace
(ns business.users ...)
(defn register-user!
[info]
(when (get-user (:username info))
(throw (IllegalArgumentException. "A user with this name already exists")))
(raise! :user-registered (assoc info :time (Date.))))
;;; an email notification
(ns services.email)
(on ::user-registered
[user]
(let [message "Thanks for signing up!"]
(send-email! (:email user) message)
(raise! :user-notified (assoc user :message message :time (Date.)))))
;;; a data model
(ns model.users ...)
(defonce users (atom nil))
(on ::user-registered
[{:keys [username time] :as user}]
(swap! users assoc username (assoc user :registered time))
(raise! :user-updated username))
(on ::user-notified
[{:keys [username message time]}]
(swap! users update-in [username]))
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment