(nsobserver(:require[clojure.spec.alpha:ass]))(s/def::topickeyword?)(s/def::messageany?)(s/def::callbackfn?)(defprotocolObservable"Protocol defining Observable behaviors"(subscribe[thistopiccallback]"Subscribes a callback function to a specific topic")(unsubscribe[thistopiccallback]"Removes a callback subscription from a topic")(notify[thistopicmessage]"Notifies all subscribers of a topic with a message"))(defrecordEventBus[subscribers]Observable(subscribe[thistopiccallback]{:pre[(s/valid?::topictopic)(s/valid?::callbackcallback)]}(update-inthis[:subscriberstopic](fnilconj#{})callback))(unsubscribe[thistopiccallback]{:pre[(s/valid?::topictopic)(s/valid?::callbackcallback)]}(update-inthis[:subscriberstopic]disjcallback))(notify[thistopicmessage]{:pre[(s/valid?::topictopic)(s/valid?::messagemessage)]}(doseq[callback(get-inthis[:subscriberstopic])](callbackmessage))this))(defncreate-event-bus"Creates a new event bus instance"[](->EventBus{}))(defncreate-stateful-subscriber"Creates a subscriber that maintains state between notifications"[initial-stateupdate-fn](let[state(atominitial-state)](fn[message](swap!stateupdate-fnmessage))))(defncreate-logging-subscriber"Creates a subscriber that logs messages with timestamps"[topic-name](fn[message](println(format"[%s][%s] Received: %s"(java.time.LocalDateTime/now)topic-namemessage))))(comment(defevent-bus(create-event-bus))(deforder-logger(create-logging-subscriber"Orders"))(defbus-with-logger(subscribeevent-bus:ordersorder-logger))(deforder-counter(create-stateful-subscriber0(fn[state_](incstate))))(defbus-with-counter(subscribebus-with-logger:ordersorder-counter))(notifybus-with-counter:orders{:id1:total100.0})(notifybus-with-counter:orders{:id2:total200.0})(deffinal-bus(unsubscribebus-with-counter:ordersorder-logger)))(comment(require'[clojure.test:refer[deftesttestingis]])(deftestobserver-pattern-test(testing"Basic subscription and notification"(let[received(atomnil)callback#(reset!received%)bus(->(create-event-bus)(subscribe:testcallback))](notifybus:test"hello")(is(=@received"hello"))))(testing"Multiple subscribers"(let[results(atom[])callback-1#(swap!resultsconj[:cb1%])callback-2#(swap!resultsconj[:cb2%])bus(->(create-event-bus)(subscribe:testcallback-1)(subscribe:testcallback-2))](notifybus:test"hello")(is(=@results[[:cb1"hello"][:cb2"hello"]]))))(testing"Unsubscribe"(let[received(atomnil)callback#(reset!received%)bus(->(create-event-bus)(subscribe:testcallback)(unsubscribe:testcallback))](notifybus:test"hello")(is(nil?@received))))(testing"Stateful subscriber"(let[counter(create-stateful-subscriber0(fn[state_](incstate)))bus(subscribe(create-event-bus):testcounter)](notifybus:test"event1")(notifybus:test"event2")(is(=@(#'observer/statecounter)2))))))
Top comments (1)
That is indeed awesome!
In the last test, I am getting the error "Unable to resolve var: observer/state in this context".