From 051cf40bc7cfe96d190f9a76bdb07f594d81aaf8 Mon Sep 17 00:00:00 2001 From: Kris Siegel Date: Thu, 18 May 2017 22:48:47 -0700 Subject: [PATCH] 5.2.0 (#64) Updated middleware signature to add an additional parameter to the handler that includes the calling message object Changed build targets Tweaks to documentation --- .travis.yml | 17 ++--- CHANGELOG.md | 10 +++ README.md | 6 +- bower.json | 2 +- msngr.js | 115 ++++++++++++++++++++---------- msngr.min.js | 2 +- package.json | 2 +- src/main.js | 2 +- src/messaging/executer.js | 2 +- src/messaging/message.aspec.js | 43 +++++++++++ src/messaging/message.js | 87 +++++++++++++--------- src/messaging/middleware.aspec.js | 41 ++++++++++- src/messaging/middleware.js | 26 +++++-- 13 files changed, 254 insertions(+), 101 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5fd911c..5eab3fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,22 +1,13 @@ language: node_js sudo: false node_js: - - "7.2" - - "6.9" - - "6.7" - - "6.4" - - "6.3.1" - - "6.2" - - "6.1" + - "7.8" + - "7.0" + - "6.10" - "6.0" - "5.12" - - "5.7" - - "5.1" - "5.0" - - "4.6" - - "4.5" - - "4.2" - - "4.1" + - "4.8" - "4.0" - "0.12" - "0.11" diff --git a/CHANGELOG.md b/CHANGELOG.md index 408b368..c648b0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,16 @@ # Changelog This is a roll-up of all release notes in order of release +## [Release 5.2.0 - May 18, 2016](https://github.com/KrisSiegel/msngr.js/releases/tag/5.2.0) +Minor, non-breaking API additions + +***What's new?*** +- Updated middleware signature to add an additional parameter to the handler that includes the calling message object + +***Misc changes*** +- Changed build targets +- Tweaks to documentation + ## [Release 5.1.0 - December 11, 2016](https://github.com/KrisSiegel/msngr.js/releases/tag/5.1.0) Version 5.1.0 brings some minor improvements and changes diff --git a/README.md b/README.md index 4ce99a0..1178305 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ The example above demonstrates that the handler will only fire when the specifie A mechanism for middleware exists that creates a global or localized affect. This allows for payload transformation to occur prior to any messages and their payloads being delivered to handlers. A middleware needs to be registered via ```msngr.middleware(key, fn, force)``` where the ```key``` is the name of the middleware, the ```fn``` is the middleware itself and ```force``` is a boolean that specifies whether the middleware should execute on *all* messages or not (if ```false``` then ```msngr().use(key)``` needs to be called on a message to have it applied). ```javascript -msngr.middleware("uppercase", function (payload) { +msngr.middleware("uppercase", function (payload, message) { if (msngr.is(payload).string) { return payload.toUpperCase(); } @@ -199,6 +199,6 @@ msngr.series([ ``` #### Contact -For questions, news, and whatever else that doesn't fit in GitHub issues you can follow me [@BinaryIdiot](https://twitter.com/BinaryIdiot) +For questions, news, and whatever else that doesn't fit in GitHub issues you can follow me [@KrisSiegel](https://twitter.com/KrisSiegel) -Copyright © 2014-2016 Kris Siegel +Copyright © 2014-2017 Kris Siegel diff --git a/bower.json b/bower.json index 45cab9e..56f62a5 100644 --- a/bower.json +++ b/bower.json @@ -2,7 +2,7 @@ "name": "msngr.js", "main": "msngr.min.js", "description": "msngr.js is an asynchronous messaging library, written in JavaScript, for node and browser use", - "version": "5.1.0", + "version": "5.2.0", "homepage": "https://github.com/KrisSiegel/msngr.js", "authors": [ "Kris Siegel" diff --git a/msngr.js b/msngr.js index 02ead67..34de71a 100644 --- a/msngr.js +++ b/msngr.js @@ -18,7 +18,7 @@ var msngr = msngr || (function () { }; // Built version of msngr.js for programatic access; this is auto generated - external.version = "5.1.0"; + external.version = "5.2.0"; // Takes a function, executes it passing in the external and internal interfaces external.extend = function (fn) { @@ -706,7 +706,7 @@ msngr.extend((function (external, internal) { } } params.push(asyncFunc); - var syncResult = method.apply(ctx || this, params); + var syncResult = method.apply(ctx || undefined, params); if (asyncFlag !== true) { done.apply(ctx, [syncResult]); } @@ -960,6 +960,7 @@ msngr.extend((function (external, internal) { payloadIndex.clear(); payloads = {}; payloadCount = 0; + internal.resetMiddlewares(); }; /* @@ -983,40 +984,42 @@ msngr.extend((function (external, internal) { return payload; }; - var explicitEmit = function (msgOrIds, middlewares, payload, callback) { + var settleMiddleware = function (uses, payload, message, callback) { + internal.executeMiddlewares(uses, payload, message, function (newPayload) { + callback.apply(undefined, [newPayload]); + }); + }; - // Execute middlewares if any - internal.executeMiddlewares(middlewares, payload, function (newPayload) { - var ids = (external.is(msgOrIds).array) ? msgOrIds : messageIndex.query(msgOrIds); + var explicitEmit = function (msgOrIds, payload, callback) { + var ids = (external.is(msgOrIds).array) ? msgOrIds : messageIndex.query(msgOrIds); + + if (ids.length > 0) { + var methods = []; + var toDrop = []; + for (var i = 0; i < ids.length; ++i) { + var msg = (external.is(msgOrIds).object) ? external.copy(msgOrIds) : external.copy(messageIndex.query(ids[i])); + var obj = handlers[ids[i]]; + methods.push({ + method: obj.handler, + params: [payload, msg] + }); - if (ids.length > 0) { - var methods = []; - var toDrop = []; - for (var i = 0; i < ids.length; ++i) { - var msg = (external.is(msgOrIds).object) ? external.copy(msgOrIds) : external.copy(messageIndex.query(ids[i])); - var obj = handlers[ids[i]]; - methods.push({ - method: obj.handler, - params: [newPayload, msg] + if (obj.once === true) { + toDrop.push({ + msg: msg, + handler: obj.handler }); - - if (obj.once === true) { - toDrop.push({ - msg: msg, - handler: obj.handler - }); - } } + } - var execs = internal.executer(methods); - - for (var i = 0; i < toDrop.length; ++i) { - external(toDrop[i].msg).drop(toDrop[i].handler); - } + var execs = internal.executer(methods); - execs.parallel(callback); + for (var i = 0; i < toDrop.length; ++i) { + external(toDrop[i].msg).drop(toDrop[i].handler); } - }); + + execs.parallel(callback); + } }; /* @@ -1066,7 +1069,8 @@ msngr.extend((function (external, internal) { var msgObj = { use: function (middleware) { if (!external.is(middleware).empty) { - uses.push(middleware.toLowerCase()); + var normalizedKey = middleware.toLowerCase(); + uses.indexOf(normalizedKey) === -1 && uses.push(middleware.toLowerCase()); } return msgObj; @@ -1078,7 +1082,14 @@ msngr.extend((function (external, internal) { payload = undefined; } - explicitEmit(msg, uses, payload, callback); + if (uses.length > 0 || internal.getForcedMiddlewareCount() > 0) { + settleMiddleware(uses, payload, msg, function (newPayload) { + explicitEmit(msg, newPayload, callback); + }); + } else { + explicitEmit(msg, payload, callback); + } + return msgObj; }, @@ -1122,7 +1133,13 @@ msngr.extend((function (external, internal) { var payload = fetchPersistedPayload(msg); if (payload !== undefined) { - explicitEmit([id], uses, payload, undefined); + if (uses.length > 0 || internal.getForcedMiddlewareCount() > 0) { + settleMiddleware(uses, payload, msg, function (newPayload) { + explicitEmit([id], newPayload, undefined); + }); + } else { + explicitEmit([id], payload, undefined); + } } return msgObj; @@ -1138,7 +1155,13 @@ msngr.extend((function (external, internal) { var payload = fetchPersistedPayload(msg); if (payload !== undefined) { - explicitEmit([id], uses, payload, undefined); + if (uses.length > 0 || internal.getForcedMiddlewareCount() > 0) { + settleMiddleware(uses, payload, msg, function (newPayload) { + explicitEmit([id], newPayload, undefined); + }); + } else { + explicitEmit([id], payload, undefined); + } } return msgObj; @@ -1227,14 +1250,29 @@ msngr.extend((function (external, internal) { /* Internal APIs */ - internal.getMiddlewares = function (uses, payload) { + internal.getForcedMiddlewareCount = function () { + return forced.length; + }; + + internal.resetMiddlewares = function () { + middlewares = { }; + forced = []; + }; + + internal.getMiddlewares = function (uses, payload, message) { var results = []; - var keys = (uses || []).concat(forced); + var keys = (uses || []); + for (var i = 0; i < forced.length; ++i) { + if (keys.indexOf(forced[i]) === -1) { + keys.push(forced[i]); + } + } + for (var i = 0; i < keys.length; ++i) { if (middlewares[keys[i]] !== undefined) { results.push({ method: middlewares[keys[i]], - params: payload + params: [payload, message] }); } } @@ -1242,9 +1280,8 @@ msngr.extend((function (external, internal) { return results; }; - internal.executeMiddlewares = function (uses, payload, callback) { - var middles = internal.getMiddlewares(uses, payload); - + internal.executeMiddlewares = function (uses, payload, message, callback) { + var middles = internal.getMiddlewares(uses, payload, message); var execute = internal.executer(middles).series(function (result) { return callback(internal.merge.apply(this, [payload].concat(result))); }); diff --git a/msngr.min.js b/msngr.min.js index 89c4b93..40fd0cd 100644 --- a/msngr.min.js +++ b/msngr.min.js @@ -1 +1 @@ -var msngr=msngr||function(){"use strict";var a={},b=function(){var a=Array.prototype.slice.call(arguments,0);return b.message.apply(this,a)};return b.version="5.1.0",b.extend=function(c){if(void 0!==c&&null!==c){var d=Object.prototype.toString.call(c);if("[object Function]"===d)return c.apply(this,[b,a])}},Object.defineProperty(b,"debug",{set:function(c){c===!0?b.internal=a:c===!1&&delete b.internal},get:function(){return void 0!==b.internal}}),b}();msngr.extend(function(a,b){"use strict";b.InvalidParametersException=function(b,c){var d={name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",b)};return a.is(c).empty||(d.message=d.message+" "+c),d},b.DuplicateException=function(a){return{name:"DuplicateException",severity:"unrecoverable",message:"Duplicate input provided to {method} where duplicates are not allowed.".replace("{method}",a)}},b.ReservedKeywordsException=function(a){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",a)}},b.MangledException=function(a,b){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",a).replace("{method}",b)}}}),msngr.extend(function(a,b){"use strict";var c={arguments:"[object Arguments]",boolean:"[object Boolean]",string:"[object String]",date:"[object Date]",array:"[object Array]",number:"[object Number]",object:"[object Object]",function:"[object Function]",undefined:"[object Undefined]",null:"[object Null]",symbol:"[object Symbol]",nodeList:"[object NodeList]"},d=function(a){return Object.prototype.toString.call(a)},e={htmlElement:function(a){return 0===a.indexOf("[object HTML")||0===a.indexOf("[object global]")},promise:function(a,b){return"[object Promise]"===a||(a===c.object||a===c.function)&&(void 0!==item.then&&d(item.then)===c.function)}},f=function(a,b,f){return f?e[a](d(b),b):d(b)===c[a]},g=function(a,b){switch(a){case c.undefined:case c.null:return!0;case c.string:return 0===b.trim().length;case c.object:return 0===Object.keys(b).length;case c.array:return 0===b.length;default:return!1}},h=function(a){var b={},h=function(c,d){for(var e in c)c.hasOwnProperty(e)&&!function(c){Object.defineProperty(b,c,{get:function(){for(var b=0;b0&&e.shift()())},!0)}a.immediate=function(a){void 0===c&&(c="undefined"!=typeof setImmediate?setImmediate:"undefined"!=typeof window&&"undefined"!=typeof window.postMessage?function(a){e.push(a),window.postMessage(d,"*")}:function(a){setTimeout(a,0)}),c(a)}}),msngr.extend(function(a,b){"use strict";var c=void 0,d="",e=void 0,f=function(){return performance.now()},g=function(){return process.hrtime()[1]/1e6},h=function(){return Date.now()};a.now=function(b){void 0===c&&("undefined"!=typeof performance?(c=f,d="performance"):"undefined"!=typeof process?(c=g,d="node"):(c=h,d="legacy"));var i=c();return b===!0&&e===i?a.now(b):(e=i,i)}}),msngr.extend(function(a,b){"use strict";a.asyncify=function(b){return a.is(b).function&&(b.async=function(){var c=[].slice.call(arguments),d=c.pop();a.is(d).function&&!function(c,d){a.immediate(function(){try{d.apply(null,[null,b.apply(null,c)])}catch(a){d.apply(null,[a,null])}})}(c,d)}),b}}),msngr.extend(function(a,b){"use strict";var c={};c[b.types.string]=function(a){return a},c[b.types.number]=function(a){return a},c[b.types.boolean]=function(a){return a},c[b.types.date]=function(a){var b=new Date;return b.setTime(a.getTime()),b},c[b.types.object]=function(b){var c={};for(var d in b)b.hasOwnProperty(d)&&(c[d]=a.copy(b[d]));return c},c[b.types.array]=function(b){for(var c=[],d=0;d0;)b=e(b,a.shift(),!0);return b},a.merge=function(){var a=Array.prototype.slice.call(arguments,0);if(a.length<=1)return a[0];for(var b=a.shift();a.length>0;)b=e(b,a.shift());return b}}),msngr.extend(function(a,b){"use strict";a.safe=function(c,d,e){if(!a.is(c).object||!a.is(d).string)throw b.InvalidParametersException("msngr.safe");for(var f=d.split("."),g=c,h=void 0;(h=f.shift())&&(g=g[h],void 0!==g););return a.is(g).there?g:e}}),msngr.extend(function(a,b){"use strict";b.executer=function(b){for(var c=0;c1)for(var f=1;f0){for(var i=[],j=[],k=0;k0)for(var d=0;d0)for(var b=0;bd.revisions.toKeep&&f[c].shift(),d.events.onChange.emit){var h=a.message(d.events.onChange.topic,d.events.onChange.category,c);h.emit({id:c,oldValue:f[c][f[c].length-2],newValue:f[c][f[c].length-1]})}return!0},m=function(c,d){return g[c]=b.merge(g[c]||j(c),a.copy(d)),!0},n=function(a){return void 0!==f[a]&&(delete f[a],delete e[a],!0)},o=function(a){return(void 0!==g[a]||void 0!==f[a])&&(void 0!==g[a]&&delete g[a],h[a]=!0,!0)},p=function(a){return void 0!==f[a]&&(1===f[a].length?(delete f[a],delete e[a],!0):(f[a].pop(),e[a]=q.get(a),!0))},q={get:function(a){return i?k(a):j(a)},getDeep:function(b,c,d){var e=q.get(b);if(void 0===e||a.is(c).empty)return d;for(var f=c.trim().split("."),g=e,h=0;h=400&&(h={status:f.statusCode,response:g||e},g=null),a.is(d).there&&d.apply(void 0,[h,g])})});if(a.is(c.payload).there){var g;if(a.is(c.payload).object)try{g=JSON.stringify(c.payload)}catch(a){}void 0===g&&(g=c.payload),f.write(g)}f.end()}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file +var msngr=msngr||function(){"use strict";var a={},b=function(){var a=Array.prototype.slice.call(arguments,0);return b.message.apply(this,a)};return b.version="5.2.0",b.extend=function(c){if(void 0!==c&&null!==c){var d=Object.prototype.toString.call(c);if("[object Function]"===d)return c.apply(this,[b,a])}},Object.defineProperty(b,"debug",{set:function(c){c===!0?b.internal=a:c===!1&&delete b.internal},get:function(){return void 0!==b.internal}}),b}();msngr.extend(function(a,b){"use strict";b.InvalidParametersException=function(b,c){var d={name:"InvalidParametersException",severity:"unrecoverable",message:"Invalid parameters supplied to the {method} method".replace("{method}",b)};return a.is(c).empty||(d.message=d.message+" "+c),d},b.DuplicateException=function(a){return{name:"DuplicateException",severity:"unrecoverable",message:"Duplicate input provided to {method} where duplicates are not allowed.".replace("{method}",a)}},b.ReservedKeywordsException=function(a){return{name:"ReservedKeywordsException",severity:"unrecoverable",message:"Reserved keyword {keyword} supplied as action.".replace("{keyword}",a)}},b.MangledException=function(a,b){return{name:"MangledException",severity:"unrecoverable",message:"The {variable} was unexpectedly mangled in {method}.".replace("{variable}",a).replace("{method}",b)}}}),msngr.extend(function(a,b){"use strict";var c={arguments:"[object Arguments]",boolean:"[object Boolean]",string:"[object String]",date:"[object Date]",array:"[object Array]",number:"[object Number]",object:"[object Object]",function:"[object Function]",undefined:"[object Undefined]",null:"[object Null]",symbol:"[object Symbol]",nodeList:"[object NodeList]"},d=function(a){return Object.prototype.toString.call(a)},e={htmlElement:function(a){return 0===a.indexOf("[object HTML")||0===a.indexOf("[object global]")},promise:function(a,b){return"[object Promise]"===a||(a===c.object||a===c.function)&&(void 0!==item.then&&d(item.then)===c.function)}},f=function(a,b,f){return f?e[a](d(b),b):d(b)===c[a]},g=function(a,b){switch(a){case c.undefined:case c.null:return!0;case c.string:return 0===b.trim().length;case c.object:return 0===Object.keys(b).length;case c.array:return 0===b.length;default:return!1}},h=function(a){var b={},h=function(c,d){for(var e in c)c.hasOwnProperty(e)&&!function(c){Object.defineProperty(b,c,{get:function(){for(var b=0;b0&&e.shift()())},!0)}a.immediate=function(a){void 0===c&&(c="undefined"!=typeof setImmediate?setImmediate:"undefined"!=typeof window&&"undefined"!=typeof window.postMessage?function(a){e.push(a),window.postMessage(d,"*")}:function(a){setTimeout(a,0)}),c(a)}}),msngr.extend(function(a,b){"use strict";var c=void 0,d="",e=void 0,f=function(){return performance.now()},g=function(){return process.hrtime()[1]/1e6},h=function(){return Date.now()};a.now=function(b){void 0===c&&("undefined"!=typeof performance?(c=f,d="performance"):"undefined"!=typeof process?(c=g,d="node"):(c=h,d="legacy"));var i=c();return b===!0&&e===i?a.now(b):(e=i,i)}}),msngr.extend(function(a,b){"use strict";a.asyncify=function(b){return a.is(b).function&&(b.async=function(){var c=[].slice.call(arguments),d=c.pop();a.is(d).function&&!function(c,d){a.immediate(function(){try{d.apply(null,[null,b.apply(null,c)])}catch(a){d.apply(null,[a,null])}})}(c,d)}),b}}),msngr.extend(function(a,b){"use strict";var c={};c[b.types.string]=function(a){return a},c[b.types.number]=function(a){return a},c[b.types.boolean]=function(a){return a},c[b.types.date]=function(a){var b=new Date;return b.setTime(a.getTime()),b},c[b.types.object]=function(b){var c={};for(var d in b)b.hasOwnProperty(d)&&(c[d]=a.copy(b[d]));return c},c[b.types.array]=function(b){for(var c=[],d=0;d0;)b=e(b,a.shift(),!0);return b},a.merge=function(){var a=Array.prototype.slice.call(arguments,0);if(a.length<=1)return a[0];for(var b=a.shift();a.length>0;)b=e(b,a.shift());return b}}),msngr.extend(function(a,b){"use strict";a.safe=function(c,d,e){if(!a.is(c).object||!a.is(d).string)throw b.InvalidParametersException("msngr.safe");for(var f=d.split("."),g=c,h=void 0;(h=f.shift())&&(g=g[h],void 0!==g););return a.is(g).there?g:e}}),msngr.extend(function(a,b){"use strict";b.executer=function(b){for(var c=0;c1)for(var f=1;f0){for(var i=[],j=[],k=0;k0||b.getForcedMiddlewareCount()>0?j(t,c,r,function(a){k(r,a,d)}):k(r,c,d),u},persist:function(b){void 0===b&&(b=null);var c=d.query(r);if(0===c.length){var e=d.index(r);g[e]=b,c=[e]}else for(var f=0;f0||b.getForcedMiddlewareCount()>0?j(t,g,r,function(a){k([d],a,void 0)}):k([d],g,void 0)),u},once:function(a){var d=c.index(r);e[d]={handler:a,context:r.context||this,once:!0},f++;var g=i(r);return void 0!==g&&(t.length>0||b.getForcedMiddlewareCount()>0?j(t,g,r,function(a){k([d],a,void 0)}):k([d],g,void 0)),u},drop:function(a){var b=c.query(r);if(b.length>0)for(var d=0;d0)for(var b=0;bd.revisions.toKeep&&f[c].shift(),d.events.onChange.emit){var h=a.message(d.events.onChange.topic,d.events.onChange.category,c);h.emit({id:c,oldValue:f[c][f[c].length-2],newValue:f[c][f[c].length-1]})}return!0},m=function(c,d){return g[c]=b.merge(g[c]||j(c),a.copy(d)),!0},n=function(a){return void 0!==f[a]&&(delete f[a],delete e[a],!0)},o=function(a){return(void 0!==g[a]||void 0!==f[a])&&(void 0!==g[a]&&delete g[a],h[a]=!0,!0)},p=function(a){return void 0!==f[a]&&(1===f[a].length?(delete f[a],delete e[a],!0):(f[a].pop(),e[a]=q.get(a),!0))},q={get:function(a){return i?k(a):j(a)},getDeep:function(b,c,d){var e=q.get(b);if(void 0===e||a.is(c).empty)return d;for(var f=c.trim().split("."),g=e,h=0;h=400&&(h={status:f.statusCode,response:g||e},g=null),a.is(d).there&&d.apply(void 0,[h,g])})});if(a.is(c.payload).there){var g;if(a.is(c.payload).object)try{g=JSON.stringify(c.payload)}catch(a){}void 0===g&&(g=c.payload),f.write(g)}f.end()}}),"undefined"!=typeof module&&"undefined"!=typeof module.exports&&(module.exports=msngr); \ No newline at end of file diff --git a/package.json b/package.json index eeda439..8edd506 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "msngr", "main": "msngr.js", "description": "An asynchronous messaging library, written in JavaScript, for node and browser use", - "version": "5.1.0", + "version": "5.2.0", "keywords": [ "message", "messaging", diff --git a/src/main.js b/src/main.js index 83ccdf2..17f2b7b 100644 --- a/src/main.js +++ b/src/main.js @@ -18,7 +18,7 @@ var msngr = msngr || (function () { }; // Built version of msngr.js for programatic access; this is auto generated - external.version = "5.1.0"; + external.version = "5.2.0"; // Takes a function, executes it passing in the external and internal interfaces external.extend = function (fn) { diff --git a/src/messaging/executer.js b/src/messaging/executer.js index 292f159..5a87471 100644 --- a/src/messaging/executer.js +++ b/src/messaging/executer.js @@ -36,7 +36,7 @@ msngr.extend((function (external, internal) { } } params.push(asyncFunc); - var syncResult = method.apply(ctx || this, params); + var syncResult = method.apply(ctx || undefined, params); if (asyncFlag !== true) { done.apply(ctx, [syncResult]); } diff --git a/src/messaging/message.aspec.js b/src/messaging/message.aspec.js index e312bf4..af6348d 100644 --- a/src/messaging/message.aspec.js +++ b/src/messaging/message.aspec.js @@ -472,4 +472,47 @@ describe("./src/messaging/message.js", function() { }, 250); }); + it("msngr().on() / msngr().once() - correctly handles executing and dropping bound method", function (done) { + expect(msngr.internal.handlerCount).to.equal(0); + var funcCalls1 = 0; + var funcCalls2 = 0; + var funcCalls3 = 0; + var func1 = function () { + funcCalls1++; + }.bind(this); + + var func2 = function () { + funcCalls2++; + }.bind(this); + + var func3 = function () { + funcCalls3++; + }.bind(this); + + msngr("WhatUp", "YesThisIsDog").on(func1); + msngr("WhatUp", "YesThisIsDog").on(func2); + msngr("WhatUp", "YesThisIsDog").once(func3); + + expect(msngr.internal.handlerCount).to.equal(3); + + msngr("WhatUp", "YesThisIsDog").emit("test", function () { + expect(funcCalls1).to.equal(1); + expect(funcCalls2).to.equal(1); + expect(funcCalls3).to.equal(1); + expect(msngr.internal.handlerCount).to.equal(2); + + msngr("WhatUp", "YesThisIsDog").drop(func1); + expect(msngr.internal.handlerCount).to.equal(1); + + msngr("WhatUp", "YesThisIsDog").emit("test", function () { + expect(funcCalls1).to.equal(1); + expect(funcCalls2).to.equal(2); + expect(funcCalls3).to.equal(1); + expect(msngr.internal.handlerCount).to.equal(1); + + done(); + }); + }); + }); + }); diff --git a/src/messaging/message.js b/src/messaging/message.js index 9ff7d5b..6561e44 100644 --- a/src/messaging/message.js +++ b/src/messaging/message.js @@ -37,6 +37,7 @@ msngr.extend((function (external, internal) { payloadIndex.clear(); payloads = {}; payloadCount = 0; + internal.resetMiddlewares(); }; /* @@ -60,40 +61,42 @@ msngr.extend((function (external, internal) { return payload; }; - var explicitEmit = function (msgOrIds, middlewares, payload, callback) { - - // Execute middlewares if any - internal.executeMiddlewares(middlewares, payload, function (newPayload) { - var ids = (external.is(msgOrIds).array) ? msgOrIds : messageIndex.query(msgOrIds); + var settleMiddleware = function (uses, payload, message, callback) { + internal.executeMiddlewares(uses, payload, message, function (newPayload) { + callback.apply(undefined, [newPayload]); + }); + }; - if (ids.length > 0) { - var methods = []; - var toDrop = []; - for (var i = 0; i < ids.length; ++i) { - var msg = (external.is(msgOrIds).object) ? external.copy(msgOrIds) : external.copy(messageIndex.query(ids[i])); - var obj = handlers[ids[i]]; - methods.push({ - method: obj.handler, - params: [newPayload, msg] + var explicitEmit = function (msgOrIds, payload, callback) { + var ids = (external.is(msgOrIds).array) ? msgOrIds : messageIndex.query(msgOrIds); + + if (ids.length > 0) { + var methods = []; + var toDrop = []; + for (var i = 0; i < ids.length; ++i) { + var msg = (external.is(msgOrIds).object) ? external.copy(msgOrIds) : external.copy(messageIndex.query(ids[i])); + var obj = handlers[ids[i]]; + methods.push({ + method: obj.handler, + params: [payload, msg] + }); + + if (obj.once === true) { + toDrop.push({ + msg: msg, + handler: obj.handler }); - - if (obj.once === true) { - toDrop.push({ - msg: msg, - handler: obj.handler - }); - } } + } - var execs = internal.executer(methods); - - for (var i = 0; i < toDrop.length; ++i) { - external(toDrop[i].msg).drop(toDrop[i].handler); - } + var execs = internal.executer(methods); - execs.parallel(callback); + for (var i = 0; i < toDrop.length; ++i) { + external(toDrop[i].msg).drop(toDrop[i].handler); } - }); + + execs.parallel(callback); + } }; /* @@ -143,7 +146,8 @@ msngr.extend((function (external, internal) { var msgObj = { use: function (middleware) { if (!external.is(middleware).empty) { - uses.push(middleware.toLowerCase()); + var normalizedKey = middleware.toLowerCase(); + uses.indexOf(normalizedKey) === -1 && uses.push(middleware.toLowerCase()); } return msgObj; @@ -155,7 +159,14 @@ msngr.extend((function (external, internal) { payload = undefined; } - explicitEmit(msg, uses, payload, callback); + if (uses.length > 0 || internal.getForcedMiddlewareCount() > 0) { + settleMiddleware(uses, payload, msg, function (newPayload) { + explicitEmit(msg, newPayload, callback); + }); + } else { + explicitEmit(msg, payload, callback); + } + return msgObj; }, @@ -199,7 +210,13 @@ msngr.extend((function (external, internal) { var payload = fetchPersistedPayload(msg); if (payload !== undefined) { - explicitEmit([id], uses, payload, undefined); + if (uses.length > 0 || internal.getForcedMiddlewareCount() > 0) { + settleMiddleware(uses, payload, msg, function (newPayload) { + explicitEmit([id], newPayload, undefined); + }); + } else { + explicitEmit([id], payload, undefined); + } } return msgObj; @@ -215,7 +232,13 @@ msngr.extend((function (external, internal) { var payload = fetchPersistedPayload(msg); if (payload !== undefined) { - explicitEmit([id], uses, payload, undefined); + if (uses.length > 0 || internal.getForcedMiddlewareCount() > 0) { + settleMiddleware(uses, payload, msg, function (newPayload) { + explicitEmit([id], newPayload, undefined); + }); + } else { + explicitEmit([id], payload, undefined); + } } return msgObj; diff --git a/src/messaging/middleware.aspec.js b/src/messaging/middleware.aspec.js index 42d5476..d13b9c4 100644 --- a/src/messaging/middleware.aspec.js +++ b/src/messaging/middleware.aspec.js @@ -41,7 +41,7 @@ describe("./messaging/middleware.js", function() { }); it("msngr.middleware() - Executes forced middleware over all messages", function (done) { - msngr.middleware("forcedTest", function (payload, async) { + msngr.middleware("forcedTest", function (payload, message, async) { return "middle"; }, true); @@ -52,8 +52,20 @@ describe("./messaging/middleware.js", function() { }).emit("test"); }); + it("msngr.middleware() - Executes async, forced middleware over all messages", function (done) { + msngr.middleware("forcedTest", function (payload, message, async) { + async()("midd"); + }, true); + + msngr("mytopic").on(function (payload, message) { + expect(payload).to.equal("midd"); + msngr.unmiddleware("forcedTest"); + done(); + }).emit("test"); + }); + it("msngr.middleware() - Doesn't execute non-forced middleware over all messages", function (done) { - msngr.middleware("nonforcedTest", function (payload, async) { + msngr.middleware("nonforcedTest", function (payload, message, async) { return "middle"; }, false); @@ -64,8 +76,20 @@ describe("./messaging/middleware.js", function() { }).emit("test"); }); + it("msngr.middleware() - Doesn't execute async, non-forced middleware over all messages", function (done) { + msngr.middleware("nonforcedTest", function (payload, message, async) { + async()("wut"); + }, false); + + msngr("mytopic").on(function (payload, message) { + expect(payload).to.equal("test"); + msngr.unmiddleware("nonforcedTest"); + done(); + }).emit("test"); + }); + it("msngr.middleware() - Executes optional middleware over specified message", function (done) { - msngr.middleware("middleTest", function (payload, async) { + msngr.middleware("middleTest", function (payload, message, async) { return "middle"; }, false); @@ -76,4 +100,15 @@ describe("./messaging/middleware.js", function() { }).emit("test"); }); + it("msngr.middleware() - Executes optional, async middleware over specified message", function (done) { + msngr.middleware("middleTest", function (payload, message, async) { + async()("wutwut"); + }, false); + + msngr("mytopic").use("middleTest").on(function (payload, message) { + expect(payload).to.equal("wutwut"); + msngr.unmiddleware("middleTest"); + done(); + }).emit("test"); + }); }); diff --git a/src/messaging/middleware.js b/src/messaging/middleware.js index fce4455..6e39a07 100644 --- a/src/messaging/middleware.js +++ b/src/messaging/middleware.js @@ -13,14 +13,29 @@ msngr.extend((function (external, internal) { /* Internal APIs */ - internal.getMiddlewares = function (uses, payload) { + internal.getForcedMiddlewareCount = function () { + return forced.length; + }; + + internal.resetMiddlewares = function () { + middlewares = { }; + forced = []; + }; + + internal.getMiddlewares = function (uses, payload, message) { var results = []; - var keys = (uses || []).concat(forced); + var keys = (uses || []); + for (var i = 0; i < forced.length; ++i) { + if (keys.indexOf(forced[i]) === -1) { + keys.push(forced[i]); + } + } + for (var i = 0; i < keys.length; ++i) { if (middlewares[keys[i]] !== undefined) { results.push({ method: middlewares[keys[i]], - params: payload + params: [payload, message] }); } } @@ -28,9 +43,8 @@ msngr.extend((function (external, internal) { return results; }; - internal.executeMiddlewares = function (uses, payload, callback) { - var middles = internal.getMiddlewares(uses, payload); - + internal.executeMiddlewares = function (uses, payload, message, callback) { + var middles = internal.getMiddlewares(uses, payload, message); var execute = internal.executer(middles).series(function (result) { return callback(internal.merge.apply(this, [payload].concat(result))); });