From a17a11949fceb7c3c6695d077fbfa858c29c9201 Mon Sep 17 00:00:00 2001 From: Blaine Bublitz Date: Tue, 30 Dec 2014 00:36:11 -0700 Subject: [PATCH] Breaking: Improve API & implementation based on suggestions (closes #1, closes #2) --- index.js | 77 ++++++++++------------------------------------- package.json | 2 +- test/exists.js | 20 ++++++++----- test/index.js | 81 +++++--------------------------------------------- 4 files changed, 37 insertions(+), 143 deletions(-) diff --git a/index.js b/index.js index 5a59993..73bfeb3 100644 --- a/index.js +++ b/index.js @@ -2,80 +2,33 @@ var EventEmitter = require('events').EventEmitter; -var defaultNamespace = '__sparklesEventEmitter'; +var sparklesNamespace = 'store@sparkles'; +var defaultNamespace = 'default'; function getEmitter(namespace){ - namespace = namespace || defaultNamespace; - - var ee; - - if(global[namespace]){ - ee = global[namespace]; - } else { - ee = new EventEmitter(); - - ee.setMaxListeners(0); - } + var store = global[sparklesNamespace]; - function attach(type, listener){ - // node will never fire the newListener on itself, - // so only check for remove/detach combo - if(type === 'removeListener' && listener === detach){ - return; - } - - if(!global[namespace]){ - global[namespace] = ee; - } + if(!store){ + store = global[sparklesNamespace] = {}; } - function detach(){ - var events = Object.keys(ee._events); - var removeListeners = ee.listeners('removeListener'); - var newListeners = ee.listeners('newListener'); - - // exit if we have events other than - // `removeListener` and `newListener` - if(events.length > 2){ - return; - } - - // exit if someone attached another - // listener to `removeListener` - if(removeListeners.length > 1){ - return; - } + namespace = namespace || defaultNamespace; - // exit if someone attached another - // listener to `newListener` - if(newListeners.length > 1){ - return; - } + var ee = store[namespace]; - delete global[namespace]; + if(!ee){ + ee = store[namespace] = new EventEmitter(); + ee.setMaxListeners(0); + ee.remove = function remove(){ + ee.removeAllListeners(); + delete store[namespace]; + }; } - function rewire(){ - var removeListeners = ee.listeners('removeListener'); - var newListeners = ee.listeners('newListener'); - - // if we know our `removeListener` isn't - // attached, we add it - if(!removeListeners.length){ - ee.on('removeListener', detach); - } - - // if we know our `newListener` isn't - // attached, we add it - if(!newListeners.length){ - ee.on('newListener', attach); - } - } + return ee; - rewire(); - return ee; } module.exports = getEmitter; diff --git a/package.json b/package.json index 2effa91..fff95f1 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "LICENSE" ], "scripts": { - "test": "lab -cv", + "test": "lab -cv --ignore store@sparkles", "lint": "jshint test index.js --reporter node_modules/jshint-stylish/stylish.js --exclude node_modules" }, "dependencies": {}, diff --git a/test/exists.js b/test/exists.js index 9d0e9b0..783d856 100644 --- a/test/exists.js +++ b/test/exists.js @@ -13,27 +13,33 @@ var EventEmitter = require('events').EventEmitter; describe('namespace', function(){ + beforeEach(function(done){ + global['store@sparkles'] = {}; + done(); + }); + + afterEach(function(done){ + delete global['store@sparkles']; + done(); + }); + it('should use an EE from sparkles namespace if it already exists', function(done){ - var ee = global.__sparklesEventEmitter = new EventEmitter(); + var ee = global['store@sparkles'].default = new EventEmitter(); ee.custom = 'ee'; var sparkles = require('../')(); expect(sparkles.custom).to.equal('ee'); - sparkles.removeAllListeners(); - expect(global.__sparklesEventEmitter).to.not.exist(); done(); }); it('should allow custom namespaces', function(done){ - var ee = global.__myCustomNamespace = new EventEmitter(); + var ee = global['store@sparkles'].customNamespace = new EventEmitter(); ee.custom = true; - var sparkles = require('../')('__myCustomNamespace'); + var sparkles = require('../')('customNamespace'); expect(sparkles.custom).to.equal(true); - sparkles.removeAllListeners(); - expect(global.__sparklesEventEmitter).to.not.exist(); done(); }); }); diff --git a/test/index.js b/test/index.js index 52c83e8..8c5eaff 100644 --- a/test/index.js +++ b/test/index.js @@ -19,93 +19,28 @@ describe('sparkles', function(){ beforeEach(function(done){ sparkles = require('../')(); - expect(global.__sparklesEventEmitter).to.not.exist(); done(); }); afterEach(function(done){ - sparkles.removeAllListeners(); + sparkles.remove(); done(); }); - it('will attach an event emitter to global upon the first `on` call', function(done){ - sparkles.on('test', noop); - expect(global.__sparklesEventEmitter).to.exist(); - expect(global.__sparklesEventEmitter.on).to.be.a.function(); - done(); - }); - - it('removes the event emitter from global if no more listeners exist it', function(done){ - sparkles.on('test', noop); - expect(global.__sparklesEventEmitter).to.exist(); - sparkles.removeListener('test', noop); - expect(global.__sparklesEventEmitter).to.not.exist(); - done(); - }); - - it('even works with removeAllListeners', function(done){ - sparkles.on('test1', noop); - sparkles.on('test2', noop2); - expect(global.__sparklesEventEmitter).to.exist(); - sparkles.removeAllListeners(); - expect(global.__sparklesEventEmitter).to.not.exist(); - done(); - }); - - it('handles removing all newListeners', function(done){ - sparkles.on('newListener', noop); - expect(global.__sparklesEventEmitter).to.exist(); - sparkles.removeAllListeners('newListener'); - expect(global.__sparklesEventEmitter).to.not.exist(); - done(); - }); - - it('gracefully handles newListeners being added and removed', function(done){ - sparkles.on('newListener', noop); - sparkles.on('newListener', noop2); - expect(global.__sparklesEventEmitter).to.exist(); - sparkles.removeListener('newListener', noop); - expect(global.__sparklesEventEmitter).to.exist(); - done(); - }); - - it('handles removing all removeListeners', function(done){ - sparkles.on('removeListener', noop); - expect(global.__sparklesEventEmitter).to.exist(); - sparkles.removeAllListeners('removeListener'); - expect(global.__sparklesEventEmitter).to.not.exist(); - done(); - }); - - it('gracefully handles removeListeners being added and removed', function(done){ - sparkles.on('removeListener', noop); - sparkles.on('removeListener', noop2); - expect(global.__sparklesEventEmitter).to.exist(); - sparkles.removeListener('removeListener', noop); - expect(global.__sparklesEventEmitter).to.exist(); + it('will attach the sparkles store namespace to global', function(done){ + expect(global['store@sparkles']).to.exist(); done(); }); - it('recovers from removeAllListeners on removeListener upon new sparkles', function(done){ - sparkles.on('test', noop); - sparkles.removeAllListeners('removeListener'); - expect(sparkles.listeners('removeListener')).to.have.length(0); - var sparkles2 = require('../')(); - expect(sparkles2.listeners('removeListener')).to.have.length(1); + it('will attach an event emitter to the sparkles store default namespace', function(done){ + expect(global['store@sparkles']).to.include('default'); done(); }); - it('does not add attach and detach more than once', function(done){ + it('removes the event emitter from the store when remove is called', function(done){ sparkles.on('test', noop); - expect(sparkles.listeners('removeListener')).to.have.length(1); - var sparkles2 = require('../')(); - expect(sparkles2.listeners('removeListener')).to.have.length(1); - done(); - }); - - it('will not attach to global if the detach listener is added more than once', function(done){ - sparkles.on('removeListener', sparkles._events.removeListener); - expect(global.__sparklesEventEmitter).to.not.exist(); + sparkles.remove(); + expect(global['store@sparkles']).to.not.include('default'); done(); }); });