stuck with pubsub

82 views
Skip to first unread message

gert

unread,
Oct 3, 2012, 9:49:42 PM10/3/12
to shorele...@googlegroups.com
Hi!

I'm playing with shoreleave's (awesome) pubsub mechanism, but I wonder if I'm trying to do something that's impossible... I have an atom a, and functions f1 and f2.

I would like to do something like the following. Suppose I have:

(def bus (simplebus/bus))

(def a (atom 0))

(defn f1 [arg]
  (.log js/console "f1 arg:" (pr-str arg))
  (+ 42 (:new arg)))

(defn f2 [arg]
  (.log js/console "f2 arg:" (pr-str arg))
  (* 2 arg))

(def a-p (pubsub/publishize a bus))
(def f1-p (pubsub/publishize f1 bus))
(def f2-p (pubsub/publishize f2 bus))

Now, when I do (reset! a 10), I would like to see:

f1 arg: {:new 10, :old 0}
f2 arg: 52

I have tried various combinations of publishize and subscribe to hook these three items up, but I can't seem to get it working.

The following logs "f1 arg: {:new 10, :old 0}" to the console, but not "f2 arg: 52"

(pubsub/subscribe bus a f1)
(pubsub/subscribe bus f1 f2)

When I call (f1-p {:new 10 :old 0}), I see both statements logged, so f1 and f2 are hooked up properly, and a and f1 are hooked up. How can I get all three of them hooked up?

cheers,
gert

Gert Verhoog

unread,
Oct 3, 2012, 9:56:04 PM10/3/12
to shorele...@googlegroups.com
I should add that I tried connecting a and f1-p, but that results in an error:

ClojureScript:user> (pubsub/subscribe bus a f1-p)
ClojureScript:user> (reset! a 10)
"Error evaluating:" (reset! a 10) :as "cljs.core.reset_BANG_.call(null,my.application.a,10);\n"
#<TypeError: Cannot read property 'call' of undefined>
TypeError: Cannot read property 'call' of undefined
at shoreleave.efunction.Function.apply (https://127.0.0.1:8443/js/app.js:32633:24)
at goog.pubsub.PubSub.publish (https://127.0.0.1:8443/js/app.js:31384:36)
at goog.pubsub.PubSub.shoreleave$pubsubs$protocols$IMessageBrokerBus$publish$arity$3 (https://127.0.0.1:8443/js/app.js:34078:14)
at publish__3 (https://127.0.0.1:8443/js/app.js:33792:25)
at publish (https://127.0.0.1:8443/js/app.js:33840:27)
at https://127.0.0.1:8443/js/app.js:33952:49
at cljs.core.Atom.cljs$core$IWatchable$_notify_watches$arity$3 (https://127.0.0.1:8443/js/app.js:19015:17)
at _notify_watches (https://127.0.0.1:8443/js/app.js:3694:18)
at reset_BANG_ (https://127.0.0.1:8443/js/app.js:19115:29)
at eval (eval at <anonymous> (https://127.0.0.1:8443/js/app.js:31202:147), <anonymous>:1:93)
nil
> --
>
>

Paul deGrandis

unread,
Oct 3, 2012, 10:13:23 PM10/3/12
to shorele...@googlegroups.com
Hi Gert,

Thanks for using Shoreleave and I'm glad that your experiences have been good, aside from this snag.

Your thought process is 100% correct, but the order might be a little off.  Have you tried this order yet:
(def bus (simplebus/bus))

(def a (atom 0))

(pubsub/publishize a bus)

(defn f1 [arg]
  (.log js/console "f1 arg:" (pr-str arg))
  (+ 42 (:new arg)))
(def f1-p (pubsub/publishize f1 bus))

(defn f2 [arg]
  (.log js/console "f2 arg:" (pr-str arg))
  (* 2 arg))

(pubsub/subscribe bus a f1-p)
(pubsub/subscribe bus f1-p f2)

====

The error you reported looks like the Function object that wraps publishables doesn't like `apply`
I'll look into that tonight and tomorrow morning.

=====
Also note that in the latest CLJS (I'm not sure if it's been cut to a release yet), you can use `print` and `println` instead of JS interop

Paul // ohpauleez

Gert Verhoog

unread,
Oct 6, 2012, 1:30:26 AM10/6/12
to shorele...@googlegroups.com
Hi Paul,

I tired several things, but I couldn't figure out the `apply` problem with the Function wrapper around publishized functions. I came up with the following workaround. This macro creates a function that publishes its result on bus when it is called. You can also use it as the target of a `subscribe`. It's not the prettiest, but it does the job and I thought I'd share:

;; ------------ montoux/tools/pubsub/macros.clj ------------
(ns montoux.tools.pubsub.macros)

(defmacro defnp
"Like defn, but creates a publishized version of the function with the supplied
name. The orginal function will be defined with name__nnnn where nnnn is a
random number. The symbol denoting the original function can be found in the
function's meta under :publishized-fn."
[name bus & fdecl]
(let [[m fdecl] (if (string? (first fdecl))
[{:doc (first fdecl)} (rest fdecl)]
[{} fdecl])
name* (gensym (str (clojure.core/name name) "__"))]
`(do
(defn ~name* ~@fdecl)
(defn ~name [& args#]
(let [r# (apply ~name* args#)
t# (shoreleave.pubsubs.protocols/topicify ~name)]
(shoreleave.pubsubs.protocols/publish ~bus t# r#)
r#)))))

(defmacro defp
[name bus & decl]
`(do
(def ~name ~@decl)
(shoreleave.pubsubs.protocols/publishize ~name ~bus)
~name))


;; ------------ montoux/application.cljs ------------
;;
;; this will print the following to the console:
;;
;; f1 arg: {:new 10, :old 0}
;; f2 arg: 52
(ns montoux.application
(:require [shoreleave.pubsubs.simple :as simplebus]
[shoreleave.pubsubs.protocols :as pubsub])
(:require-macros [montoux.tools.pubsub.macros :as ps]))

(def bus (simplebus/bus))

(ps/defp a bus (atom 0))

(ps/defnp f1 bus [arg]
(.log js/console "f1 arg:" (pr-str arg))
(+ 42 (:new arg)))

(ps/defnp f2 bus [arg]
(.log js/console "f2 arg:" (pr-str arg))
(* 2 arg))

(pubsub/subscribe bus a f1)
(pubsub/subscribe bus f1 f2)

(reset! a 10)

Paul deGrandis

unread,
Oct 6, 2012, 3:09:39 PM10/6/12
to shorele...@googlegroups.com
Hi Gert,

I'll look into the bug this weekend.
Your macro is more-or-less exactly what publishize is doing, but is allowing you to compose it (since it's not a macro):
http://shoreleave.github.com/shoreleave-pubsub/#shoreleave.pubsubs.protocols

Thanks for reporting this!  Sorry but the hiccup, but I'm glad you have a workaround for the time being.

Paul


--



Reply all
Reply to author
Forward
0 new messages