/**
A require.s2 module implementing a basic publish-subscriber
manager.
Example usage:
http://fossil.wanderinghorse.net/repos/cwal/index.cgi/finfo?name=s2/toys/r-pubsub.s2
*/
const ps /* need a temporary symbol for the new() method to keep as our prototype */ = {
__typename: 'PubSub',
/**
Subscribes a callback to events published for a given key.
key may be of any value type. func must be-a Function.
Returns a unique-per-subscription value (of an unspecified
type) which can be passed to unsub() to opt out of a
subscription or ignored (for a permanent subscription,
automatically renewed periodically at no extra cost).
*/
sub:proc callee(key, func){
affirm func inherits callee.prototype /* is-a Function */;
(this.$map[key] ||| (this.$map[key]={}))[++this.$id] = func;
return [key, this.$id];
},
/**
Expects id to be a value returned by this.sub() and
unsubscribes a subscriber registered with that id.
Returns true if it finds/removes a subscription, else
false.
*/
unsub: proc(id){
return id && this.$map.hasOwnProperty(id.0)
? this.$map[id.0].unset(id.1)
: false;
},
/**
Publishes an event to all subscribers of the given key (if
any), calling them:
a) in an UNSPECIFIED and (very) POSSIBLY CHANGING order.
b) passing on any arguments given after the event key to each
subscriber callback function.
Returns this object (for lack of a better option).
It propagates any exceptions thrown by a subscriber.
Pedantic side-node: each subscriber gets its own copy of the
arguments array, so it's safe to change it or keep a reference
to it in the subscribers without affecting others.
*/
pub:proc(key){
(this.$map[key]|||return this).
eachProperty(((const args=argv), args.shift(), shoot));
return this;
}.importSymbols({shoot: proc(/*key,val*/){argv.1.apply(argv.1,args.slice())}}
/*need a copy to avoid subscriber side-effects^^^^^^^^^^^^*/),
/**
Removes all subscriptions for the given key or
(if no arguments are passed) all subscriptions
for all keys.
Returns this object (for lack of a better option).
*/
unsubAll:proc(key){
argv.length()
? this.$map.unset(key)
: this.$map.clearProperties();
return this;
}
};
return (
/**
Factory function for new instances of this class:
var pubber = thisObj.new();
assert pubber inherits thisObj; // this will hold
Each instance maintains its own, independent list of
subscriptions.
This function always uses the "original" prototype as the
return value's prototype, not the current 'this' of
the call to new(), though it is callable via arbitrary
instances.
*/
ps.new = proc(){
return { prototype: that, $map:{}, $id:0 };
}.importSymbols({that: ps})
)();