Skip to content

Commit 8bc2ba0

Browse files
Dirk LüthDirk Lüth
authored andcommitted
Merge branch 'release/1.0.2'
2 parents 2e77397 + d84c4d3 commit 8bc2ba0

5 files changed

Lines changed: 154 additions & 66 deletions

File tree

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Flexee
22

3-
[![Travis CI](https://img.shields.io/travis/dlueth/qoopido.flexee/master.svg?style=flat-square&label=travis)](https://travis-ci.org/dlueth/qoopido.flexee)
4-
[![Coveralls](https://img.shields.io/coveralls/dlueth/qoopido.flexee/master.svg?style=flat-square&label=coveralls)](https://coveralls.io/github/dlueth/qoopido.flexee)
3+
[![Travis CI](https://img.shields.io/travis/dlueth/qoopido.flexee/master.svg?style=flat-square&label=build)](https://travis-ci.org/dlueth/qoopido.flexee)
4+
[![Coveralls](https://img.shields.io/coveralls/dlueth/qoopido.flexee/master.svg?style=flat-square&label=coverage)](https://coveralls.io/github/dlueth/qoopido.flexee)
55
[![GitHub version](https://img.shields.io/github/tag/dlueth/qoopido.flexee.svg?style=flat-square&label=github)](https://github.com/dlueth/qoopido.flexee)
66
[![NPM version](https://img.shields.io/npm/v/flexee.svg?style=flat-square&label=npm)](https://www.npmjs.com/package/flexee)
7-
[![NPM downloads](https://img.shields.io/npm/dt/flexee.svg?style=flat-square&label=npm%20downloads)](https://www.npmjs.org/package.flexee)
7+
[![NPM downloads](https://img.shields.io/npm/dt/flexee.svg?style=flat-square&label=npm%20downloads)](https://www.npmjs.org/package/flexee)
88
[![License](https://img.shields.io/npm/l/flexee.svg?style=flat-square)](https://github.com/dlueth/qoopido.flexee)
99

1010
Flexible & dead simple event emitter for Node.js supporting RegExp-based event subscription.
@@ -33,26 +33,26 @@ Flexee offers a total of three methods to subscribe to events: ```on```, ```once
3333

3434
```
3535
// register an event listener
36-
emitter.on({String|RegExp} identifier, {Function} callback, {Boolean=} prepend, {Number=} limit);
36+
emitter.on({String|RegExp|Object[]} identifier, {Function} callback, {Boolean=} prepend, {Number=} limit);
3737
3838
// register a once only event listener
39-
emitter.once({String|RegExp} identifier, {Function} callback, {Boolean=} prepend);
39+
emitter.once({String|RegExp|Object[]} identifier, {Function} callback, {Boolean=} prepend);
4040
4141
// register an event listener that gets called a limited number of times
42-
emitter.limit({String|RegExp} identifier, {Number} limit, {Function} callback);
42+
emitter.limit({String|RegExp|Object[]} identifier, {Number} limit, {Function} callback);
4343
```
4444

45-
```identifier``` can either be a specific event name as ```String``` or a pattern of event names as ```RegExp``` which gives you almost endless flexibitlity.
45+
```identifier``` can either be a specific event name as ```String```, a pattern of event names as ```RegExp``` or an ```array``` of both which gives you almost endless flexibitlity.
4646

4747

4848
## Unsubscribing from events
4949
The only method to know is the ```off``` method:
5050

5151
```
52-
emitter.off({String|RegExp} identifier, {Function=} callback);
52+
emitter.off({String|RegExp|Object[]} identifier, {Function=} callback);
5353
```
5454

55-
```identifier``` can, again, either be a specific event name as ```String``` or a pattern of event names as ```RegExp```. Just keep in mind that unsubscribing from a specific event name will never unsubscribe a RegExp-listener and vice versa.
55+
```identifier``` can, again, either be a specific event name as ```String```, a pattern of event names as ```RegExp``` or an ```array``` of both. Just keep in mind that unsubscribing from a specific event name will never unsubscribe a RegExp-listener and vice versa.
5656

5757

5858
## Retrieving listener

helper/validator.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
'use strict';
2+
3+
/**
4+
* Check if identifier is of valid tye
5+
*
6+
* @param {*} identifier
7+
*
8+
* @returns {Boolean}
9+
*/
10+
function isIdentifier(identifier) {
11+
return (isString(identifier) || isExpression(identifier) || isArray(identifier));
12+
}
13+
14+
/**
15+
* Check if value is a valid callback
16+
*
17+
* @param {*} value
18+
*
19+
* @returns {Boolean}
20+
*/
21+
function isCallback(value) {
22+
return (typeof value === 'function');
23+
}
24+
25+
/**
26+
* Check if value is of type string
27+
*
28+
* @param {*} value
29+
*
30+
* @returns {Boolean}
31+
*/
32+
function isString(value) {
33+
return (typeof value === 'string');
34+
}
35+
36+
/**
37+
* Check if value is of type array
38+
*
39+
* @param {*} value
40+
*
41+
* @returns {Boolean}
42+
*/
43+
function isArray(value) {
44+
return Array.isArray(value);
45+
}
46+
47+
/**
48+
* Check if value is a RegExp
49+
*
50+
* @param {*} value
51+
*
52+
* @returns {Boolean}
53+
*/
54+
function isExpression(value) {
55+
return (value instanceof RegExp);
56+
}
57+
58+
module.exports = {
59+
isIdentifier: isIdentifier,
60+
isCallback: isCallback,
61+
isString: isString,
62+
isArray: isArray,
63+
isExpression: isExpression
64+
};

index.js

Lines changed: 25 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

3-
const global = new WeakMap();
3+
const validator = require('./helper/validator.js');
4+
const global = new WeakMap();
45

56
/**
67
* Remove an event listener
@@ -64,50 +65,6 @@ function applyEvent(callback, event, details) {
6465
callback.apply(this, Array.prototype.concat(event, details));
6566
}
6667

67-
/**
68-
* Check if identifier is of valid tye
69-
*
70-
* @param {*} identifier
71-
*
72-
* @returns {Boolean}
73-
*/
74-
function isValidIdentifier(identifier) {
75-
return (isString(identifier) || isExpression(identifier));
76-
}
77-
78-
/**
79-
* Check if value is a valid callback
80-
*
81-
* @param {*} value
82-
*
83-
* @returns {Boolean}
84-
*/
85-
function isValidCallback(value) {
86-
return (typeof value === 'function');
87-
}
88-
89-
/**
90-
* Check if value is of type string
91-
*
92-
* @param {*} value
93-
*
94-
* @returns {Boolean}
95-
*/
96-
function isString(value) {
97-
return (typeof value === 'string');
98-
}
99-
100-
/**
101-
* Check if value is a RegExp
102-
*
103-
* @param {*} value
104-
*
105-
* @returns {Boolean}
106-
*/
107-
function isExpression(value) {
108-
return (value instanceof RegExp);
109-
}
110-
11168
/**
11269
* Subscribe an event listener
11370
*
@@ -168,7 +125,7 @@ function unsubscribeExpression(expression, callback) {
168125
function retrieveListener(event) {
169126
let listener;
170127

171-
if(isString(event)) {
128+
if(validator.isString(event)) {
172129
let storage = global.get(this);
173130

174131
listener = storage.events[event] ? storage.events[event].slice() : [];
@@ -214,24 +171,30 @@ class Emitter {
214171
/**
215172
* Subscribe an event listener
216173
*
217-
* @param {String|RegExp} identifier
174+
* @param {String|RegExp|Object[]} identifier
218175
* @param {Function} callback
219176
* @param {Boolean=} prepend
220177
* @param {Number=} limit
221178
*
222179
* @returns {Emitter}
223180
*/
224181
on(identifier, callback, prepend, limit) {
225-
if(isValidIdentifier(identifier) && isValidCallback(callback)) {
182+
if(validator.isIdentifier(identifier) && validator.isCallback(callback)) {
226183
let storage = global.get(this);
227184

228-
if(isString(identifier)) {
185+
if(validator.isString(identifier)) {
229186
subscribeEvent.call(storage, identifier, callback, prepend, limit);
230187
}
231188

232-
if(isExpression(identifier)) {
189+
if(validator.isExpression(identifier)) {
233190
subscribeExpression.call(storage, identifier, callback, prepend, limit);
234191
}
192+
193+
if(validator.isArray(identifier)) {
194+
identifier.forEach((identifier) => {
195+
this.on(identifier, callback, prepend, limit);
196+
});
197+
}
235198
}
236199

237200
return this;
@@ -240,7 +203,7 @@ class Emitter {
240203
/**
241204
* Subscribe a once only event listener
242205
*
243-
* @param {String|RegExp} identifier
206+
* @param {String|RegExp|Object[]} identifier
244207
* @param {Function} callback
245208
* @param {Boolean=} prepend
246209
*
@@ -253,7 +216,7 @@ class Emitter {
253216
/**
254217
* Subscribe a limited event listener
255218
*
256-
* @param {String|RegExp} identifier
219+
* @param {String|RegExp|Object[]} identifier
257220
* @param {Number} limit
258221
* @param {Function} callback
259222
* @param {Boolean=} prepend
@@ -267,22 +230,28 @@ class Emitter {
267230
/**
268231
* Unsubscribe an event listener
269232
*
270-
* @param {String|RegExp} identifier
233+
* @param {String|RegExp|Object[]} identifier
271234
* @param {Function=} callback
272235
*
273236
* @returns {Emitter}
274237
*/
275238
off(identifier, callback) {
276-
if(isValidIdentifier(identifier) && (isValidCallback(callback) || typeof callback === 'undefined')) {
239+
if(validator.isIdentifier(identifier) && (validator.isCallback(callback) || typeof callback === 'undefined')) {
277240
let storage = global.get(this);
278241

279-
if(isString(identifier)) {
242+
if(validator.isString(identifier)) {
280243
unsubscribeEvent.call(storage, identifier, callback)
281244
}
282245

283-
if(isExpression(identifier)) {
246+
if(validator.isExpression(identifier)) {
284247
unsubscribeExpression.call(storage, identifier, callback);
285248
}
249+
250+
if(validator.isArray(identifier)) {
251+
identifier.forEach((identifier) => {
252+
this.off(identifier, callback);
253+
});
254+
}
286255
}
287256

288257
return this;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "flexee",
3-
"version": "1.0.1",
3+
"version": "1.0.2",
44
"description": "Flexible event emitter for Node.js supporting RegExp-based event subscription",
55
"main": "index.js",
66
"author": {

test/index.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,18 @@ describe('class/emitter.js', () => {
7474
sinon.assert.callCount(spy, 2);
7575
sinon.assert.alwaysCalledWithMatch(spy, regex);
7676
});
77+
78+
it('should call an array of listeners repeatedly', () => {
79+
emitter
80+
.on([ event, event ], spy)
81+
.emit(event)
82+
.emit(event);
83+
84+
sinon.assert.called(spy);
85+
sinon.assert.calledOn(spy, emitter);
86+
sinon.assert.callCount(spy, 4);
87+
sinon.assert.alwaysCalledWithExactly(spy, event);
88+
});
7789
});
7890

7991
describe('once()', () => {
@@ -104,6 +116,18 @@ describe('class/emitter.js', () => {
104116
sinon.assert.callCount(spy, 1);
105117
sinon.assert.calledWithExactly(spy, event + '/success');
106118
});
119+
120+
it('should call an array of listeners only once', () => {
121+
emitter
122+
.once([ event, event ], spy)
123+
.emit(event)
124+
.emit(event);
125+
126+
sinon.assert.called(spy);
127+
sinon.assert.calledOn(spy, emitter);
128+
sinon.assert.callCount(spy, 2);
129+
sinon.assert.alwaysCalledWithExactly(spy, event);
130+
});
107131
});
108132

109133
describe('limit()', () => {
@@ -140,6 +164,22 @@ describe('class/emitter.js', () => {
140164
sinon.assert.callCount(spy, 3);
141165
sinon.assert.alwaysCalledWithMatch(spy, regex);
142166
});
167+
168+
it('should call an array of event listeners a limited number of times', () => {
169+
emitter
170+
.limit([ event, event ], 3, spy)
171+
.emit('none')
172+
.emit(event)
173+
.emit(event)
174+
.emit(event)
175+
.emit(event)
176+
.emit('none');
177+
178+
sinon.assert.called(spy);
179+
sinon.assert.calledOn(spy, emitter);
180+
sinon.assert.callCount(spy, 6);
181+
sinon.assert.alwaysCalledWithExactly(spy, event);
182+
});
143183
});
144184

145185
describe('off()', () => {
@@ -211,6 +251,21 @@ describe('class/emitter.js', () => {
211251
expect(emitter.listener(event)).to.be.an('array').and.to.have.length.of(0);
212252
});
213253

254+
it('should unregister an array of event listeners', () => {
255+
emitter
256+
.on([ event, event ], spy)
257+
.emit(event)
258+
.off([ event, event ], spy)
259+
.emit(event);
260+
261+
sinon.assert.called(spy);
262+
sinon.assert.calledOn(spy, emitter);
263+
sinon.assert.callCount(spy, 2);
264+
sinon.assert.alwaysCalledWithExactly(spy, event);
265+
266+
expect(emitter.listener(event)).to.be.an('array').and.to.have.length.of(0);
267+
});
268+
214269
it('should not unregister expression listeners when removing an event listener', () => {
215270
let regex = new RegExp('^' + event + '/(?:success|failure)');
216271

0 commit comments

Comments
 (0)