Skip to content

Commit

Permalink
[events] EventEmitter emits wildcard event. Supports .onAny(cb) and .…
Browse files Browse the repository at this point in the history
…on('*', cb).
  • Loading branch information
pgte committed Jun 6, 2012
1 parent dc8b488 commit fe08700
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 1 deletion.
40 changes: 39 additions & 1 deletion lib/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

var isArray = Array.isArray;

var eventTypeAny = '*';

function EventEmitter() {
if (exports.usingDomains) {
// if there is an active domain, then attach to it.
Expand All @@ -45,7 +47,7 @@ EventEmitter.prototype.setMaxListeners = function(n) {
};


EventEmitter.prototype.emit = function() {
function emit() {
var type = arguments[0];
// If there is no 'error' event listener then throw.
if (type === 'error') {
Expand Down Expand Up @@ -123,13 +125,29 @@ EventEmitter.prototype.emit = function() {
}
};

EventEmitter.prototype.emit = emit;

function emitAll() {
var hasHandlers = emit.apply(this, arguments);
var args = Array.prototype.slice.call(arguments);
var eventType = args.shift();

emit.call(this, eventTypeAny, eventType, args);

return hasHandlers;
}

EventEmitter.prototype.addListener = function(type, listener) {
if ('function' !== typeof listener) {
throw new Error('addListener only takes instances of Function');
}

if (!this._events) this._events = {};

if (type === eventTypeAny && this.emit !== emitAll) {
this.emit = emitAll;
}

// To avoid recursion in the case that type == "newListeners"! Before
// adding it to the listeners, first emit "newListeners".
this.emit('newListener', type, typeof listener.listener === 'function' ?
Expand Down Expand Up @@ -219,6 +237,10 @@ EventEmitter.prototype.removeListener = function(type, listener) {
delete this._events[type];
}

if (type === eventTypeAny && this.listeners(type).length === 0) {
delete this.emit;
}

return this;
};

Expand All @@ -237,9 +259,25 @@ EventEmitter.prototype.removeAllListeners = function(type) {
this._events[type] = null;
}

if (type === eventTypeAny) {
delete this.emit;
}

return this;
};

EventEmitter.prototype.onAny = function(callback) {
this.on(eventTypeAny, callback);

return this;
};

EventEmitter.prototype.removeAnyListener = function(callback) {
this.removeListener(eventTypeAny, callback);

return this;
}

EventEmitter.prototype.listeners = function(type) {
if (!this._events) this._events = {};
if (!this._events[type]) this._events[type] = [];
Expand Down
56 changes: 56 additions & 0 deletions test/simple/test-event-emitter-on-any.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var common = require('../common');
var assert = require('assert');
var events = require('events');

var e = new events.EventEmitter();

var events_new_listener_emited = [];
var listeners_new_listener_emited = [];
var times_hello_emited = 0;

e.on('newListener', function(event, listener) {
events_new_listener_emited.push(event);
listeners_new_listener_emited.push(listener);
});

function hello(eventType, args) {
console.log('hello');
times_hello_emited += 1;
assert.equal('hello', eventType);
assert.deepEqual(['a', 'b'], args);
}
e.onAny(hello);

console.log('start');

e.emit('hello', 'a', 'b');


process.on('exit', function() {
assert.deepEqual(['*'], events_new_listener_emited);
assert.deepEqual([hello], listeners_new_listener_emited);
assert.equal(1, times_hello_emited);
});


75 changes: 75 additions & 0 deletions test/simple/test-event-emitter-remove-any-listener.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

var common = require('../common');
var assert = require('assert');
var events = require('events');


var count = 0;

function listener1() {
console.log('listener1');
count++;
}

function listener2() {
console.log('listener2');
count++;
}

function listener3() {
console.log('listener3');
count++;
}

var e1 = new events.EventEmitter();
var e1listeners = e1.listeners('*');
e1.onAny(listener1);
assert.equal(e1listeners.length, 1);
e1.removeAnyListener(listener1);
assert.deepEqual([], e1.listeners('*'));
e1.emit('a');
assert.equal(0, count);
e1.onAny(listener1);
e1.emit('a');
assert.equal(1, count);

// identity check, listeners array should be the same
assert.equal(e1listeners, e1.listeners('*'));

var e2 = new events.EventEmitter();
e2.onAny(listener1);
e2.removeAnyListener(listener2);
assert.deepEqual([listener1], e2.listeners('*'));

var e3 = new events.EventEmitter();
e3.onAny(listener1);
e3.onAny(listener2);
var e3listeners = e3.listeners('*');
assert.equal(e3listeners.length, 2)
e3.removeAnyListener(listener1);
assert.equal(e3listeners.length, 1)
assert.deepEqual([listener2], e3.listeners('*'));

assert.equal(e3listeners, e3.listeners('*'));


0 comments on commit fe08700

Please sign in to comment.