From 9e34de294b15bec35190d62d7b7ae723c193e724 Mon Sep 17 00:00:00 2001 From: Nate Smith Date: Mon, 4 May 2015 01:15:06 -0700 Subject: [PATCH] use standard node.js EventEmitter class --- lib/client/connection.js | 6 +- lib/client/doc.js | 7 +- lib/client/emitter.js | 10 +++ lib/client/microevent.js | 78 --------------------- lib/client/query.js | 11 ++- test/server/json-api.coffee | 4 +- test/server/microevent.coffee | 128 ---------------------------------- 7 files changed, 25 insertions(+), 219 deletions(-) create mode 100644 lib/client/emitter.js delete mode 100644 lib/client/microevent.js delete mode 100644 test/server/microevent.coffee diff --git a/lib/client/connection.js b/lib/client/connection.js index 8816b94f..322105c5 100644 --- a/lib/client/connection.js +++ b/lib/client/connection.js @@ -1,6 +1,6 @@ var Doc = require('./doc').Doc; var Query = require('./query').Query; -var MicroEvent = require('./microevent'); +var emitter = require('./emitter'); /** @@ -19,6 +19,8 @@ var MicroEvent = require('./microevent'); * @param socket @see bindToSocket */ var Connection = exports.Connection = function (socket) { + emitter.EventEmitter.call(this); + // Map of collection -> docName -> doc object for created documents. // (created documents MUST BE UNIQUE) this.collections = {}; @@ -59,7 +61,7 @@ var Connection = exports.Connection = function (socket) { this.bindToSocket(socket); } -MicroEvent.mixin(Connection); +emitter.mixin(Connection); /** diff --git a/lib/client/doc.js b/lib/client/doc.js index 90d111d5..37ce8596 100644 --- a/lib/client/doc.js +++ b/lib/client/doc.js @@ -1,5 +1,5 @@ var types = require('../types').ottypes; -var MicroEvent = require('./microevent'); +var emitter = require('./emitter'); /** * A Doc is a client's view on a sharejs document. @@ -74,6 +74,8 @@ var MicroEvent = require('./microevent'); * TODO rename `op` to `after partial op` */ var Doc = exports.Doc = function(connection, collection, name) { + emitter.EventEmitter.call(this); + this.connection = connection; this.collection = collection; @@ -139,8 +141,7 @@ var Doc = exports.Doc = function(connection, collection, name) { // The document also responds to the api provided by the type this.type = null }; - -MicroEvent.mixin(Doc); +emitter.mixin(Doc); /** * Unsubscribe and remove all editing contexts diff --git a/lib/client/emitter.js b/lib/client/emitter.js new file mode 100644 index 00000000..2b7827cc --- /dev/null +++ b/lib/client/emitter.js @@ -0,0 +1,10 @@ +var EventEmitter = require('events').EventEmitter; + +exports.EventEmitter = EventEmitter; +exports.mixin = mixin; + +function mixin(Constructor) { + for (var key in EventEmitter.prototype) { + Constructor.prototype[key] = EventEmitter.prototype[key]; + } +} diff --git a/lib/client/microevent.js b/lib/client/microevent.js deleted file mode 100644 index c8e2233f..00000000 --- a/lib/client/microevent.js +++ /dev/null @@ -1,78 +0,0 @@ -// This is a simple rewrite of microevent.js. I've changed the -// function names to be consistent with node.js EventEmitter. -// -// microevent.js is copyright Jerome Etienne, and licensed under the MIT license: -// https://github.com/jeromeetienne/microevent.js - -module.exports = MicroEvent; - -function MicroEvent() {}; - -MicroEvent.prototype.on = function(event, fn) { - var events = this._events = this._events || {}; - (events[event] = events[event] || []).push(fn); -}; - -MicroEvent.prototype.removeListener = function(event, fn) { - var events = this._events = this._events || {}; - var listeners = events[event] = events[event] || []; - - // Sadly, no IE8 support for indexOf. - var i = 0; - while (i < listeners.length) { - if (listeners[i] === fn) { - listeners[i] = undefined; - } - i++; - } - - // Compact the list when no event handler is actually running. - setTimeout(function() { - events[event] = []; - var fn; - for (var i = 0; i < listeners.length; i++) { - // Only add back event handlers which exist. - if ((fn = listeners[i])) events[event].push(fn); - } - }, 0); -}; - -MicroEvent.prototype.emit = function(event) { - var events = this._events; - var args = Array.prototype.splice.call(arguments, 1); - - if (!events || !events[event]) { - if (event == 'error') { - if (console) { - console.error.apply(console, args); - } - } - return; - } - - var listeners = events[event]; - for (var i = 0; i < listeners.length; i++) { - if (listeners[i]) { - listeners[i].apply(this, args); - } - } -}; - -MicroEvent.prototype.once = function(event, fn) { - var listener, _this = this; - this.on(event, listener = function() { - _this.removeListener(event, listener); - fn.apply(_this, arguments); - }); -}; - -MicroEvent.mixin = function(obj) { - var proto = obj.prototype || obj; - proto.on = MicroEvent.prototype.on; - proto.removeListener = MicroEvent.prototype.removeListener; - proto.emit = MicroEvent.prototype.emit; - proto.once = MicroEvent.prototype.once; - return obj; -}; - - diff --git a/lib/client/query.js b/lib/client/query.js index a2876126..359bba14 100644 --- a/lib/client/query.js +++ b/lib/client/query.js @@ -1,11 +1,12 @@ -var Doc = require('./doc').Doc; -var MicroEvent = require('./microevent'); +var emitter = require('./emitter'); // Queries are live requests to the database for particular sets of fields. // // The server actively tells the client when there's new data that matches // a set of conditions. var Query = exports.Query = function(type, connection, id, collection, query, options, callback) { + emitter.EventEmitter.call(this); + // 'fetch' or 'sub' this.type = type; @@ -47,6 +48,8 @@ var Query = exports.Query = function(type, connection, id, collection, query, op this.callback = callback; }; +emitter.mixin(Query); + Query.prototype.action = 'qsub'; // Helper for subscribe & fetch, since they share the same message format. @@ -216,7 +219,3 @@ Query.prototype.setQuery = function(q) { this._execute(); } }; - - -MicroEvent.mixin(Query); - diff --git a/test/server/json-api.coffee b/test/server/json-api.coffee index 886f3d32..afd139fe 100644 --- a/test/server/json-api.coffee +++ b/test/server/json-api.coffee @@ -1,7 +1,7 @@ assert = require("assert") json = require('ot-json0').type require("../../lib/types/json-api") -MicroEvent = require("../../lib/client/microevent") +emitter = require('../../lib/client/emitter'); # in the future, it would be less brittle to use the real Doc object instead of this fake one Doc = (data) -> @@ -52,7 +52,7 @@ Doc = (data) -> this -MicroEvent.mixin Doc +emitter.mixin Doc apply = (cxt,op) -> cxt._beforeOp? op diff --git a/test/server/microevent.coffee b/test/server/microevent.coffee deleted file mode 100644 index 8d565bfd..00000000 --- a/test/server/microevent.coffee +++ /dev/null @@ -1,128 +0,0 @@ -# Tests for event framework - -assert = require 'assert' - -MicroEvent = require '../../lib/client/microevent' -makePassPart = require('../helpers').makePassPart - -tests = -> - it 'does nothing when you emit an event with no listeners', -> - @e.emit 'a' - @e.emit 'a', 1, 2, 3 - @e.emit 'b', 1, 2, 3 - - it 'fires the event listener', (done) -> - @e.on 'foo', -> done() - @e.emit 'foo' - - it 'does not fire a removed event listener', -> - fn = -> throw new Error 'event listener fired' - @e.on 'foo', fn - @e.removeListener 'foo', fn - @e.emit 'foo' - - it 'passes arguments to event listeners', (done) -> - @e.on 'foo', (a, b, c) -> - assert.strictEqual a, 1 - assert.strictEqual b, 2 - assert.strictEqual c, 3 - done() - @e.emit 'foo', 1, 2, 3 - - it 'fires multiple event listeners', (done) -> - passPart = makePassPart 2, done - @e.on 'foo', passPart - @e.on 'foo', passPart - @e.emit 'foo' - - it 'does nothing when you remove a missing event listener', (done) -> - @e.removeListener 'foo', -> - @e.emit 'foo' # Does nothing. - - @e.on 'foo', -> done() - @e.removeListener 'foo', -> - @e.emit 'foo' - - it 'removes an event listener while handling an event', (done) -> - passPart = makePassPart 3, done - fn = -> passPart() - @e.on 'foo', fn - @e.on 'foo', => - @e.removeListener 'foo', fn - passPart() - @e.on 'foo', passPart - @e.emit 'foo' - - it 'will fire an event if you remove it and add it back', (done) -> - fn = -> done() - @e.on 'foo', fn - @e.removeListener 'foo', fn - @e.on 'foo', fn - @e.emit 'foo' - - it 'fires an event listener that was removed from a different event', (done) -> - fn = -> done() - @e.on 'foo', fn - @e.on 'bar', fn - @e.removeListener 'foo', fn - @e.emit 'bar' - - it 'fires a listener registered with once', (done) -> - @e.once 'foo', (x, y) -> - assert.strictEqual x, 1 - assert.strictEqual y, 2 - done() - @e.emit 'foo', 1, 2 - - it 'only fires a listener registered with once once', -> - calls = 0 - @e.once 'foo', -> calls++ - @e.emit 'foo' - @e.emit 'foo' - - assert.strictEqual calls, 1 - - it 'calls listeners in the proper context', (done) -> - passPart = makePassPart 2, done - e = @e - @e.once 'foo', -> - assert.strictEqual this, e - passPart() - @e.on 'foo', -> - assert.strictEqual this, e - passPart() - @e.emit 'foo' - - it 'is ok with emitting before anything is registered', -> - @e.emit 'blah' - -# The tests above are run both with a new MicroEvent and with an object with -# microevent mixed in. - -describe 'raw', -> - beforeEach -> - @e = new MicroEvent - tests() - -describe 'mixinObj', -> - beforeEach -> - @e = {} - MicroEvent.mixin @e - tests() - -describe 'mixinClass', -> - beforeEach -> - class Foo - bar: -> - - MicroEvent.mixin Foo - @e = new Foo - tests() - -# Test that the same behaviour holds with nodejs's event emitters. -describe 'eventEmitter', -> - beforeEach -> - @e = new (require 'events').EventEmitter - - tests() -