Skip to content

Commit

Permalink
Merge pull request #44 from mroderick/43-call-all-subscribers-despite…
Browse files Browse the repository at this point in the history
…-unsubscription

#43 call all subscribers despite unsubscription
  • Loading branch information
mroderick committed Feb 11, 2014
2 parents 8623761 + 7843f93 commit cd240c7
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 29 deletions.
57 changes: 34 additions & 23 deletions src/pubsub.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ https://github.com/mroderick/PubSubJS
messages = {},
lastUid = -1;

function hasKeys(obj){
var key;

for (key in obj){
if ( obj.hasOwnProperty(key) ){
return true;
}
}
return false;
}

/**
* Returns a function that throws the passed exception, for use as argument for setTimeout
* @param { Object } ex An Error object
Expand All @@ -60,17 +71,16 @@ https://github.com/mroderick/PubSubJS
function deliverMessage( originalMessage, matchedMessage, data, immediateExceptions ){
var subscribers = messages[matchedMessage],
callSubscriber = immediateExceptions ? callSubscriberWithImmediateExceptions : callSubscriberWithDelayedExceptions,
i, j;
s;

if ( !messages.hasOwnProperty( matchedMessage ) ) {
return;
}

// do not cache the length of the subscribers array, as it might change if there are unsubscribtions
// by subscribers during delivery of a topic
// see https://github.com/mroderick/PubSubJS/issues/26
for ( i = 0; i < subscribers.length; i++ ){
callSubscriber( subscribers[i].func, originalMessage, data );
for (s in subscribers){
if ( subscribers.hasOwnProperty(s)){
callSubscriber( subscribers[s], originalMessage, data );
}
}
}

Expand All @@ -93,13 +103,13 @@ https://github.com/mroderick/PubSubJS

function messageHasSubscribers( message ){
var topic = String( message ),
found = messages.hasOwnProperty( topic ) && messages[topic].length,
found = Boolean(messages.hasOwnProperty( topic ) && hasKeys(messages[topic])),
position = topic.lastIndexOf( '.' );

while ( !found && position !== -1 ){
topic = topic.substr( 0, position );
position = topic.lastIndexOf( '.' );
found = messages.hasOwnProperty( topic ) && messages[topic].length;
found = Boolean(messages.hasOwnProperty( topic ) && hasKeys(messages[topic]));
}

return found;
Expand Down Expand Up @@ -155,13 +165,13 @@ https://github.com/mroderick/PubSubJS

// message is not registered yet
if ( !messages.hasOwnProperty( message ) ){
messages[message] = [];
messages[message] = {};
}

// forcing token as String, to allow for future expansions without breaking usage
// and allow for easy use as key names for the 'messages' object
var token = String(++lastUid);
messages[message].push( { token : token, func : func } );
var token = 'uid_' + String(++lastUid);
messages[message][token] = func;

// return token for unsubscribing
return token;
Expand All @@ -175,22 +185,23 @@ https://github.com/mroderick/PubSubJS
**/
PubSub.unsubscribe = function( tokenOrFunction ){
var isToken = typeof tokenOrFunction === 'string',
key = isToken ? 'token' : 'func',
succesfulReturnValue = isToken ? tokenOrFunction : true,

result = false,
m, i;
m, message, t, token;

for ( m in messages ){
if ( messages.hasOwnProperty( m ) ){
for ( i = messages[m].length-1 ; i >= 0; i-- ){
if ( messages[m][i][key] === tokenOrFunction ){
messages[m].splice( i, 1 );
result = succesfulReturnValue;

// tokens are unique, so we can just return here
if ( isToken ){
return result;
message = messages[m];

if ( isToken && message[tokenOrFunction] ){
delete message[tokenOrFunction];
result = tokenOrFunction;
// tokens are unique, so we can just stop here
break;
} else if (!isToken) {
for ( t in message ){
if (message.hasOwnProperty(t) && message[t] === tokenOrFunction){
delete message[t];
result = true;
}
}
}
Expand Down
30 changes: 29 additions & 1 deletion test/test-publish.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,35 @@

// make sure we restore PubSub to it's original state
delete PubSub.immediateExceptions;
},

"publish should call all subscribers, even when there are unsubscriptions within" : function(done){
var topic = TestHelper.getUniqueString(),
spy1 = this.spy(),
func1 = function func1(){
PubSub.unsubscribe(func1);
spy1();
},

spy2 = this.spy(),
func2 = function func2(){
PubSub.unsubscribe(func2);
spy2();
},

clock = this.useFakeTimers();

PubSub.subscribe(topic, func1);
PubSub.subscribe(topic, func2);

PubSub.publish(topic, 'some data');
clock.tick(1);

assert(spy1.called, 'expected spy1 to be called');
assert(spy2.called, 'expected spy2 to be called');

clock.restore();
done();
}
});

}(this));
10 changes: 5 additions & 5 deletions test/test-subscribe.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/
(function( global ){
"use strict";

var PubSub = global.PubSub || require("../src/pubsub"),
TestHelper = global.TestHelper || require("../test/helper"),
assert = buster.assert,
Expand All @@ -22,7 +22,7 @@

assert.isString( token );
},

"should return new token for several subscriptions with same function" : function(){
var func = function(){},
tokens = [],
Expand All @@ -37,7 +37,7 @@
// make sure all tokens are different
TestHelper.assertAllTokensDifferent( tokens );
},

"should return unique tokens for each namespaced subscription" : function(){
var func = function(){},
tokens = [],
Expand All @@ -51,13 +51,13 @@
// make sure all tokens are different
TestHelper.assertAllTokensDifferent( tokens );
},

"should return unique token for unique functions" : function(){
var tokens = [],
iterations = 10,
message = TestHelper.getUniqueString(),
i;

function bakeFunc( value ){
return function(){
return value;
Expand Down

0 comments on commit cd240c7

Please sign in to comment.