[go: up one dir, main page]

Skip to content

Commit

Permalink
Update Events (#114)
Browse files Browse the repository at this point in the history
* Events have been rewritten and moved inside of modules

* Adds event tests
Improves emit argument handling
Adds default data to end of all emits

* Fixed prepArgs

* Handles array and string based namespacing

* Fixed typo
  • Loading branch information
Christopher Lowenthal authored and timelf123 committed Jul 26, 2016
1 parent 3ed1169 commit b94922d
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 57 deletions.
55 changes: 0 additions & 55 deletions lib/core_modules/events/events.js

This file was deleted.

142 changes: 142 additions & 0 deletions lib/core_modules/module/events.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
'use strict';

/**
* Allows MeanIO to create a unique wrapper for a single EventEmitter per Module.
* With this, we allows all Modules to use the same EventEmitter, but automatically
* namespace their events with the module name.
*/

var delimiter = '.';
var EventEmitter2 = require('eventemitter2').EventEmitter2;
var emitter = new EventEmitter2({
wildcard: true,
delimiter: delimiter,
// set this to `true` if you want to emit the newListener event. The default value is `true`
newListener: true,
// the maximum amount of listeners that can be assigned to an event, default 10.
maxListeners: 20
});

/**
* @param {string} name - Name of the module, used to namespace events
* @constructor
*/
function Events(name) {
this.name = name;
this._default = {};
}

/**
* Emits an event for the module
* Automatically namespaced with the moduleName passed to the constructor
* @deprecated Use emit with EventEmitter2 standard api
* @param {*} opts - Any data to be passed with the event
* @param {string} opts.action - Name of the event that happesn
*/
Events.prototype.publish = function (opts) {
console.error('publish() has been deprecated. Update to emit(event, data).');

if (!opts.action) {
console.error('Error: events require an "action" property');
return;
}
this.emit([this.name, opts.action], opts);
};

/**
* Calls emit with the module name as the default root namespace
* @see EventEmitter2.emit
* @link https://github.com/asyncly/EventEmitter2
* @param {array|string} event
* @return {boolean}
*/
Events.prototype.emit = function (event) {
var args = prepArgs(arguments, this.name, event, this._default);
return emitter.emit.apply(emitter, args);
};

/**
* Calls emitAsync with the module name as the default root namespace
* @see EventEmitter2.emitAsync
* @link https://github.com/asyncly/EventEmitter2
* @param event
* @returns {Promise}
*/
Events.prototype.emitAsync = function (event) {
var args = prepArgs(arguments, this.name, event, this._default);
return emitter.emitAsync.apply(emitter, args);
};

/**
* @deprecated
* @param {string|array} name - Event name
* @param {function} cb
*/
Events.prototype.subscribe = function (name, cb) {
console.error('subscribe() has been deprecated. Update to on(event, listener)');
this.on(name, cb);
};

/**
* Sets defaults that will be included with every event
* Individual keys are overwritten if passed to emit()
* @param data
*/
Events.prototype.setDefaults = function (data) {
for (var index in data) {
this._default[index] = data[index];
}
};

/**
* @deprecated Use setDefaults
* @param {*} data
*/
Events.prototype.defaultData = function (data) {
console.error('defaultData() has been deprecated. Update to setDefaults(data)');
this.setDefaults(data);
};

/**
* Extending EventEmitter2 API
*/
Events.prototype.addListener = emitter.addListener.bind(emitter);
Events.prototype.on = emitter.on.bind(emitter);
Events.prototype.onAny = emitter.onAny.bind(emitter);
Events.prototype.offAny = emitter.offAny.bind(emitter);
Events.prototype.once = emitter.once.bind(emitter);
Events.prototype.many = emitter.many.bind(emitter);
Events.prototype.removeListener = emitter.removeListener.bind(emitter);
Events.prototype.off = emitter.off.bind(emitter);
Events.prototype.removeAllListeners = emitter.removeAllListeners.bind(emitter);
Events.prototype.setMaxListeners = emitter.setMaxListeners.bind(emitter);
Events.prototype.listeners = emitter.listeners.bind(emitter);
Events.prototype.listenersAny = emitter.listenersAny.bind(emitter);

module.exports = Events;

/**
* Helps in preparing our arguments for passing to emit and emitAsync
* @param args
* @param name
* @param defaults
* @returns {*}
*/
function prepArgs(args, name, event, defaults) {
args = Array.from(args);

var namespace = [name];
if (!Array.isArray(event)) {
event = event.split(delimiter);
}

namespace = namespace.concat(event);

args.shift();//remove the event

args.unshift(namespace);
if (defaults) {
args.push(defaults);
}
return args;
}
2 changes: 1 addition & 1 deletion lib/core_modules/module/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ var Q = require('q'),
util = require('./util'),
DependableList = require('./dependablelist'),
search = require('./search'),
Events = require('../events/events');
Events = require('./events');

var _modules = new DependableList();

Expand Down
1 change: 0 additions & 1 deletion test/specs/mean.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,3 @@ describe('MEAN IO Core', function () {
});
});
});

87 changes: 87 additions & 0 deletions test/specs/module/events.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
'use strict';
/* jshint -W024 */
/* jshint expr:true */

var chai = require('chai'),
expect = chai.expect;
require('mocha-sinon');

var Events = require('../../../lib/core_modules/module/events.js');

describe('Module Events', function () {
var e1 = new Events('one');
var e2 = new Events('two');
var listener;

beforeEach(function () {
listener = this.sinon.stub();
listener.reset();
});

it('should have all EventEmitter2 functions', function () {
expect(e1.addListener).to.exist;
expect(e1.on).to.exist;
expect(e1.onAny).to.exist;
expect(e1.offAny).to.exist;
expect(e1.once).to.exist;
expect(e1.many).to.exist;
expect(e1.removeListener).to.exist;
expect(e1.off).to.exist;
expect(e1.removeAllListeners).to.exist;
expect(e1.setMaxListeners).to.exist;
expect(e1.listeners).to.exist;
expect(e1.listenersAny).to.exist;
});

describe('Namespacing', function () {
it('should use name', function () {
e1.on([e1.name, 'test'], listener);
e1.emit('test');
expect(listener.calledOnce).to.be.true;
});

it('should allow .on across namespaces', function () {
e1.on([e2.name, 'test'], listener);
e2.emit('test');
expect(listener.calledOnce).to.be.true;
});

it('should work with arrays', function() {
e1.on([e1.name, 'ns', 'array'], listener);
e1.emit(['ns', 'array']);
expect(listener.calledOnce).to.be.true;
});

it('should work with arrays and strings', function(){
e1.on([e1.name, 'array', 'string'], listener);
e1.emit('array.string');
expect(listener.calledOnce).to.be.true;
});

it('should work with strings and arrays', function(){
e1.on(e1.name + '.string.array', listener);
e1.emit(['string', 'array']);
expect(listener.calledOnce).to.be.true;
});
});

describe('Default Data', function () {
var def = {test: true};
it('should send default data', function () {
e1.setDefaults(def);
e1.on('one.default', listener);
e1.emit('default');
expect(listener.calledOnce).to.be.true;
expect(listener.calledWith(def)).to.be.true;
});

it('should append default data to end of array', function(){
var obj = {};
e1.setDefaults(def);
e1.on('one.default.append', listener);
e1.emit('default.append', obj);
expect(listener.calledOnce).to.be.true;
expect(listener.calledWith(obj, def)).to.be.true;
})
});
});

0 comments on commit b94922d

Please sign in to comment.