From ea92a8443009dc87048ca053c3daa3bde4d0fbaa Mon Sep 17 00:00:00 2001 From: Jim Cowart Date: Thu, 7 May 2015 01:12:15 -0400 Subject: [PATCH] Fixed #95. Added JSCS for formatting. Bumped version to v1.0.3 --- .jscsrc | 108 ++++++++++++++++++++++++ .jshintrc | 1 - bower.json | 2 +- changelog.md | 4 + component.json | 2 +- example/amd/js/examples.js | 1 - gulpfile.js | 24 +++++- lib/postal.js | 37 ++++---- lib/postal.lodash.js | 59 +++++++------ lib/postal.lodash.min.js | 4 +- lib/postal.min.js | 4 +- package.json | 33 ++++---- spec/.jshintrc | 5 +- spec/helpers/node-lodash-build-setup.js | 1 + spec/helpers/phantomjs-shims.js | 5 +- spec/publishing.spec.js | 43 ++++++++-- spec/subscriptions.spec.js | 31 +++---- spec/utils.spec.js | 4 +- src/AmqpBindingsResolver.js | 2 +- src/Api.js | 35 ++++---- src/ChannelDefinition.js | 2 +- src/SubscriptionDefinition.js | 20 ++--- src/mindash.js | 22 ++--- src/postal.js | 7 +- src/postal.lodash.js | 8 +- 25 files changed, 319 insertions(+), 145 deletions(-) create mode 100644 .jscsrc diff --git a/.jscsrc b/.jscsrc new file mode 100644 index 00000000..4e6647b3 --- /dev/null +++ b/.jscsrc @@ -0,0 +1,108 @@ +{ + // Project Specific + "excludeFiles": [ + "node_modules/**", + "coverage/**", + "lib/**" + ], + + "esnext": true, + + // Normal jscsrc + "disallowKeywords": [ + "with" + ], + "disallowKeywordsOnNewLine": [ + "else" + ], + "disallowMixedSpacesAndTabs": "smart", + "disallowMultipleLineBreaks": true, + "disallowMultipleLineStrings": true, + "disallowMultipleSpaces": true, + "disallowMultipleVarDecl": "exceptUndefined", + "disallowNewlineBeforeBlockStatements": true, + "disallowOperatorBeforeLineBreak": [ + "+", + "." + ], + "disallowPaddingNewlinesInBlocks": true, + "disallowQuotedKeysInObjects": "allButReserved", + "disallowSpaceAfterObjectKeys": true, + "disallowSpaceAfterPrefixUnaryOperators": true, + "disallowSpaceBeforeBinaryOperators": [ + ",", + ":" + ], + "disallowSpaceBeforePostfixUnaryOperators": true, + "disallowSpacesInAnonymousFunctionExpression": { + "beforeOpeningRoundBrace": true + }, + "disallowSpacesInCallExpression": true, + "disallowSpacesInFunctionExpression": { + "beforeOpeningRoundBrace": true + }, + "disallowSpacesInNamedFunctionExpression": { + "beforeOpeningRoundBrace": true + }, + "disallowTrailingComma": true, + "disallowTrailingWhitespace": true, + "maximumLineLength": null, + "requireBlocksOnNewline": true, + "requireCamelCaseOrUpperCaseIdentifiers": "ignoreProperties", + "requireCapitalizedConstructors": true, + "requireCommaBeforeLineBreak": true, + "requireCurlyBraces": [ + "if", + "else", + "for", + "while", + "do", + "try", + "catch" + ], + "requireDotNotation": "except_snake_case", + "requireLineFeedAtFileEnd": true, + "requireOperatorBeforeLineBreak": true, + "requirePaddingNewLinesBeforeLineComments": null, + "requireParenthesesAroundIIFE": true, + "requireSemicolons": true, + "requireSpaceAfterBinaryOperators": true, + "requireSpaceAfterKeywords": [ + "if", + "else", + "for", + "while", + "do", + "switch", + "return", + "try", + "catch" + ], + "requireSpaceBeforeBinaryOperators": [ + "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=", "&=", "|=", "^=", "+=", "+", "-", + "*", "/", "%", "<<", ">>", ">>>", "&", "|", "^", "&&", "||", "===", "==", ">=", "<=", "<", ">", "!=", "!==" + ], + "requireSpaceBeforeBlockStatements": true, + "requireSpaceBeforeObjectValues": true, + "requireSpaceBetweenArguments": true, + "requireSpacesInAnonymousFunctionExpression": { + "beforeOpeningCurlyBrace": true + }, + "requireSpacesInConditionalExpression": true, + "requireSpacesInForStatement": true, + "requireSpacesInFunctionExpression": { + "beforeOpeningCurlyBrace": true + }, + "requireSpacesInNamedFunctionExpression": { + "beforeOpeningCurlyBrace": true + }, + "requireSpacesInsideArrayBrackets": "all", + "requireSpacesInsideObjectBrackets": "all", + "requireSpacesInsideParentheses": "all", + "validateIndentation": "\t", + "validateLineBreaks": "LF", + "validateQuoteMarks": { + "escape": true, + "mark": "\"" + } +} diff --git a/.jshintrc b/.jshintrc index 53e53aa1..8b000a74 100644 --- a/.jshintrc +++ b/.jshintrc @@ -84,7 +84,6 @@ "yui" : false, //defines globals exposed by the YUI JavaScript framework "predef" : [ // Custom globals. - "_", "define" ], diff --git a/bower.json b/bower.json index 37f6f57b..fa9bff23 100755 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "postal.js", - "version": "1.0.2", + "version": "1.0.3", "description": "Pub/Sub library providing wildcard subscriptions, complex message handling, etc. Works server and client-side.", "homepage": "https://github.com/postaljs/postal.js", "keywords": [ diff --git a/changelog.md b/changelog.md index f0d65c0b..e17ef72f 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,7 @@ +## v1.0.3 + +* Fixed memory leak issue referred to [here](https://github.com/postaljs/postal.js/issues/95#issuecomment-99336472). Postal will not place subscriptions in the lookup cache if the `resolverNoCache` header is present on the published envelope. + ## v1.0.2 * Updated lodash dependency to 3.x. diff --git a/component.json b/component.json index 55a9c475..f3669448 100644 --- a/component.json +++ b/component.json @@ -2,7 +2,7 @@ "name": "postal.js", "repo": "postaljs/postal.js", "description": "Client-side messaging library", - "version": "1.0.2", + "version": "1.0.3", "keywords": [ "pub/sub", "pub", diff --git a/example/amd/js/examples.js b/example/amd/js/examples.js index c5eb9024..ca562471 100644 --- a/example/amd/js/examples.js +++ b/example/amd/js/examples.js @@ -1,6 +1,5 @@ /* global $ */ define( [ "postal", "postaldiags" ], function( postal, diags ) { - // This gets you a handle to the default postal channel... // For grins, you can get a named channel instead like this: // var channel = postal.channel( 'DoctorWho' ); diff --git a/gulpfile.js b/gulpfile.js index dfd3fe81..be223621 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -12,6 +12,9 @@ var path = require( "path" ); var pkg = require( "./package.json" ); var open = require( "open" ); //jshint ignore:line var port = 3080; +var jshint = require( "gulp-jshint" ); +var jscs = require( "gulp-jscs" ); +var gulpChanged = require( "gulp-changed" ); var banner = [ "/**", " * <%= pkg.name %> - <%= pkg.description %>", @@ -25,7 +28,7 @@ var banner = [ "/**", gulp.task( "combine", [ "combine.postal" ] ); -gulp.task( "combine.postal", function() { +gulp.task( "combine.postal", [ "format" ], function() { return gulp.src( [ "./src/postal.js" ] ) .pipe( header( banner, { pkg: pkg @@ -49,7 +52,7 @@ gulp.task( "combine.postal", function() { .pipe( gulp.dest( "./lib/" ) ); } ); -gulp.task( "combine.postal-lodash", function() { +gulp.task( "combine.postal-lodash", [ "format" ], function() { return gulp.src( [ "./src/postal.lodash.js" ] ) .pipe( header( banner, { pkg: pkg @@ -131,3 +134,20 @@ gulp.task( "watch", [ "default", "mocha" ], function() { gulp.watch( "src/**/*", [ "default" ] ); gulp.watch( "{lib,spec}/**/*", [ "mocha" ] ); } ); + +gulp.task( "jshint", function() { + return gulp.src( [ "src/**/*.js", "spec/**/*.js" ] ) + .pipe( jshint() ) + .pipe( jshint.reporter( "jshint-stylish" ) ) + .pipe( jshint.reporter( "fail" ) ); +} ); + +gulp.task( "format", [ "jshint" ], function() { + return gulp.src( [ "./src/**/*.js", "!node_modules/**" ] ) + .pipe( jscs( { + configPath: ".jscsrc", + fix: true + } ) ) + .pipe( gulpChanged( "./src", { hasChanged: gulpChanged.compareSha1Digest } ) ) + .pipe( gulp.dest( "./src" ) ); +} ); diff --git a/lib/postal.js b/lib/postal.js index 339d2855..0a6f2e22 100644 --- a/lib/postal.js +++ b/lib/postal.js @@ -1,7 +1,7 @@ /** * postal - Pub/Sub library providing wildcard subscriptions, complex message handling, etc. Works server and client-side. * Author: Jim Cowart (http://ifandelse.com) - * Version: v1.0.2 + * Version: v1.0.3 * Url: http://github.com/postaljs/postal.js * License(s): MIT */ @@ -78,7 +78,7 @@ var previous; return function (data) { var eq = false; - if (typeof data == 'string') { + if (typeof data === "string") { eq = data === previous; previous = data; } else { @@ -117,7 +117,7 @@ return this.delay(0); }, disposeAfter: function disposeAfter(maxCalls) { - if (typeof maxCalls != 'number' || maxCalls <= 0) { + if (typeof maxCalls !== "number" || maxCalls <= 0) { throw new Error("The value provided to disposeAfter (maxCalls) must be a number greater than zero."); } var self = this; @@ -171,7 +171,8 @@ } else { report = console.log; } - this["catch"](report); + this. + catch (report); } return this; }, @@ -188,7 +189,7 @@ } }, constraint: function constraint(predicate) { - if (typeof predicate != 'function') { + if (typeof predicate !== "function") { throw new Error("Predicate constraint must be a function"); } this.pipeline.push(function (data, env, next) { @@ -210,7 +211,7 @@ return this; }, debounce: function debounce(milliseconds, immediate) { - if (typeof milliseconds != 'number') { + if (typeof milliseconds !== "number") { throw new Error("Milliseconds must be a number"); } this.pipeline.push( @@ -220,7 +221,7 @@ return this; }, delay: function delay(milliseconds) { - if (typeof milliseconds != 'number') { + if (typeof milliseconds !== "number") { throw new Error("Milliseconds must be a number"); } var self = this; @@ -232,7 +233,7 @@ return this; }, throttle: function throttle(milliseconds) { - if (typeof milliseconds != 'number') { + if (typeof milliseconds !== "number") { throw new Error("Milliseconds must be a number"); } var fn = function (data, env, next) { @@ -363,11 +364,15 @@ } }; } - function getCacher(topic, cache, cacheKey, done, envelope) { + function getCacher(topic, pubCache, cacheKey, done, envelope) { var headers = envelope && envelope.headers || {}; return function (subDef) { + var cache; if (_config.resolver.compare(subDef.topic, topic, headers)) { - cache.push(subDef); + if (!headers.resolverNoCache) { + cache = pubCache[cacheKey] = (pubCache[cacheKey] || []); + cache.push(subDef); + } subDef.cacheKeys.push(cacheKey); if (done) { done(subDef); @@ -397,17 +402,17 @@ }; } else { return function (sub) { - var compared = 0, - matched = 0; + var compared = 0; + var matched = 0; _.each(options, function (val, prop) { compared += 1; if ( // We use the bindings resolver to compare the options.topic to subDef.topic (prop === "topic" && resolver.compare(sub.topic, options.topic, { resolverNoCache: true - })) || (prop === "context" && options.context === sub._context) + })) || (prop === "context" && options.context === sub._context) || // Any other potential prop/value matching outside topic & context... - || (sub[prop] === options[prop])) { + (sub[prop] === options[prop])) { matched += 1; } }); @@ -466,9 +471,8 @@ var skipped = 0; var activated = 0; if (!cache) { - cache = this.cache[cacheKey] = []; var cacherFn = getCacher( - topic, cache, cacheKey, function (candidate) { + topic, this.cache, cacheKey, function (candidate) { if (candidate.invokeSubscriber(envelope.data, envelope)) { activated++; } else { @@ -501,6 +505,7 @@ this.unsubscribeFor(); _config.resolver.reset(); this.subscriptions = {}; + this.cache = {}; }, subscribe: function subscribe(options) { var subscriptions = this.subscriptions; diff --git a/lib/postal.lodash.js b/lib/postal.lodash.js index 247b4496..875d7d14 100644 --- a/lib/postal.lodash.js +++ b/lib/postal.lodash.js @@ -1,26 +1,26 @@ /** * postal - Pub/Sub library providing wildcard subscriptions, complex message handling, etc. Works server and client-side. * Author: Jim Cowart (http://ifandelse.com) - * Version: v1.0.2 + * Version: v1.0.3 * Url: http://github.com/postaljs/postal.js * License(s): MIT */ (function (root, factory) { - var createPartialWrapper = require('lodash/internal/createPartialWrapper'); + var createPartialWrapper = require("lodash/internal/createPartialWrapper"); var _ = { - after: require('lodash/function/after'), - any: require('lodash/internal/arraySome'), + after: require("lodash/function/after"), + any: require("lodash/internal/arraySome"), bind: function (func, thisArg, arg) { return createPartialWrapper(func, 33, thisArg, [arg]); }, - debounce: require('lodash/function/debounce'), - each: require('lodash/internal/baseEach'), - extend: require('lodash/internal/baseAssign'), - filter: require('lodash/internal/arrayFilter'), - isEqual: require('lodash/lang/isEqual'), - keys: require('lodash/object/keys'), - map: require('lodash/internal/arrayMap'), - throttle: require('lodash/function/throttle') + debounce: require("lodash/function/debounce"), + each: require("lodash/internal/baseEach"), + extend: require("lodash/internal/baseAssign"), + filter: require("lodash/internal/arrayFilter"), + isEqual: require("lodash/lang/isEqual"), + keys: require("lodash/object/keys"), + map: require("lodash/internal/arrayMap"), + throttle: require("lodash/function/throttle") }; /* istanbul ignore if */ if (typeof define === "function" && define.amd) { // AMD. Register as an anonymous module. @@ -94,7 +94,7 @@ var previous; return function (data) { var eq = false; - if (typeof data == 'string') { + if (typeof data === "string") { eq = data === previous; previous = data; } else { @@ -133,7 +133,7 @@ return this.delay(0); }, disposeAfter: function disposeAfter(maxCalls) { - if (typeof maxCalls != 'number' || maxCalls <= 0) { + if (typeof maxCalls !== "number" || maxCalls <= 0) { throw new Error("The value provided to disposeAfter (maxCalls) must be a number greater than zero."); } var self = this; @@ -187,7 +187,8 @@ } else { report = console.log; } - this["catch"](report); + this. + catch (report); } return this; }, @@ -204,7 +205,7 @@ } }, constraint: function constraint(predicate) { - if (typeof predicate != 'function') { + if (typeof predicate !== "function") { throw new Error("Predicate constraint must be a function"); } this.pipeline.push(function (data, env, next) { @@ -226,7 +227,7 @@ return this; }, debounce: function debounce(milliseconds, immediate) { - if (typeof milliseconds != 'number') { + if (typeof milliseconds !== "number") { throw new Error("Milliseconds must be a number"); } this.pipeline.push( @@ -236,7 +237,7 @@ return this; }, delay: function delay(milliseconds) { - if (typeof milliseconds != 'number') { + if (typeof milliseconds !== "number") { throw new Error("Milliseconds must be a number"); } var self = this; @@ -248,7 +249,7 @@ return this; }, throttle: function throttle(milliseconds) { - if (typeof milliseconds != 'number') { + if (typeof milliseconds !== "number") { throw new Error("Milliseconds must be a number"); } var fn = function (data, env, next) { @@ -379,11 +380,15 @@ } }; } - function getCacher(topic, cache, cacheKey, done, envelope) { + function getCacher(topic, pubCache, cacheKey, done, envelope) { var headers = envelope && envelope.headers || {}; return function (subDef) { + var cache; if (_config.resolver.compare(subDef.topic, topic, headers)) { - cache.push(subDef); + if (!headers.resolverNoCache) { + cache = pubCache[cacheKey] = (pubCache[cacheKey] || []); + cache.push(subDef); + } subDef.cacheKeys.push(cacheKey); if (done) { done(subDef); @@ -413,17 +418,17 @@ }; } else { return function (sub) { - var compared = 0, - matched = 0; + var compared = 0; + var matched = 0; _.each(options, function (val, prop) { compared += 1; if ( // We use the bindings resolver to compare the options.topic to subDef.topic (prop === "topic" && resolver.compare(sub.topic, options.topic, { resolverNoCache: true - })) || (prop === "context" && options.context === sub._context) + })) || (prop === "context" && options.context === sub._context) || // Any other potential prop/value matching outside topic & context... - || (sub[prop] === options[prop])) { + (sub[prop] === options[prop])) { matched += 1; } }); @@ -482,9 +487,8 @@ var skipped = 0; var activated = 0; if (!cache) { - cache = this.cache[cacheKey] = []; var cacherFn = getCacher( - topic, cache, cacheKey, function (candidate) { + topic, this.cache, cacheKey, function (candidate) { if (candidate.invokeSubscriber(envelope.data, envelope)) { activated++; } else { @@ -517,6 +521,7 @@ this.unsubscribeFor(); _config.resolver.reset(); this.subscriptions = {}; + this.cache = {}; }, subscribe: function subscribe(options) { var subscriptions = this.subscriptions; diff --git a/lib/postal.lodash.min.js b/lib/postal.lodash.min.js index c94aa200..ce760368 100644 --- a/lib/postal.lodash.min.js +++ b/lib/postal.lodash.min.js @@ -1,8 +1,8 @@ /** * postal - Pub/Sub library providing wildcard subscriptions, complex message handling, etc. Works server and client-side. * Author: Jim Cowart (http://ifandelse.com) - * Version: v1.0.2 + * Version: v1.0.3 * Url: http://github.com/postaljs/postal.js * License(s): MIT */ -(function(e,t){var n=require("lodash/internal/createPartialWrapper"),i={after:require("lodash/function/after"),any:require("lodash/internal/arraySome"),bind:function(e,t,i){return n(e,33,t,[i])},debounce:require("lodash/function/debounce"),each:require("lodash/internal/baseEach"),extend:require("lodash/internal/baseAssign"),filter:require("lodash/internal/arrayFilter"),isEqual:require("lodash/lang/isEqual"),keys:require("lodash/object/keys"),map:require("lodash/internal/arrayMap"),throttle:require("lodash/function/throttle")};"function"==typeof define&&define.amd?define(function(){return t(i,e)}):"object"==typeof module&&module.exports?module.exports=t(i,this):e.postal=t(i,e)})(this,function(e,t,n){function i(e,t){return function(){if(console.warn||console.log){var n="Warning, the "+e+" method has been deprecated. Please use "+t+" instead.";console.warn?console.warn(n):console.log(n)}return b.prototype[t].apply(this,arguments)}}function r(){for(;_.length;)l.unsubscribe(_.shift())}function c(e,t,n){return function(i,r,c){i===e&&c.splice(r,1),0===c.length&&delete n[t]}}function s(e,t,n,i,r){var c=r&&r.headers||{};return function(r){f.resolver.compare(r.topic,e,c)&&(t.push(r),r.cacheKeys.push(n),i&&i(r))}}function o(e,t){return{channel:f.SYSTEM_CHANNEL,topic:"subscription."+e,data:{event:"subscription."+e,channel:t.channel,topic:t.topic}}}function a(t,n){return"function"==typeof t?t:t?function(i){var r=0,c=0;return e.each(t,function(e,s){r+=1,("topic"===s&&n.compare(i.topic,t.topic,{resolverNoCache:!0})||"context"===s&&t.context===i._context||i[s]===t[s])&&(c+=1)}),r===c}:function(){return!0}}var u=t.postal,h={DEFAULT_CHANNEL:"/",SYSTEM_CHANNEL:"postal",enableSystemMessages:!0,cacheKeyDelimiter:"|",autoCompactResolver:!1},l={configuration:e.extend({},h)},f=l.configuration,p=function(e,t){this.bus=t,this.channel=e||f.DEFAULT_CHANNEL};p.prototype.subscribe=function(){return this.bus.subscribe({channel:this.channel,topic:1===arguments.length?arguments[0].topic:arguments[0],callback:1===arguments.length?arguments[0].callback:arguments[1]})},p.prototype.publish=function(){var e,t={};"string"==typeof arguments[0]?(t.topic=arguments[0],t.data=arguments[1],e=arguments[2]):(t=arguments[0],e=arguments[1]),t.channel=this.channel,this.bus.publish(t,e)};var b=function(e,t,i){if(3!==arguments.length)throw new Error("You must provide a channel, topic and callback when creating a SubscriptionDefinition instance.");if(0===t.length)throw new Error("Topics cannot be empty");this.channel=e,this.topic=t,this.callback=i,this.pipeline=[],this.cacheKeys=[],this._context=n},d=function(){var t;return function(n){var i=!1;return"string"==typeof n?(i=n===t,t=n):(i=e.isEqual(n,t),t=e.extend({},n)),!i}},m=function(){var t=[];return function(n){var i=!e.any(t,function(t){return e.isEqual(n,t)});return i&&t.push(n),i}};b.prototype={"catch":function(e){var t=this.callback,n=function(){try{t.apply(this,arguments)}catch(n){e(n,arguments[0])}};return this.callback=n,this},defer:function(){return this.delay(0)},disposeAfter:function(t){if("number"!=typeof t||0>=t)throw new Error("The value provided to disposeAfter (maxCalls) must be a number greater than zero.");var n=this,i=e.after(t,e.bind(function(){n.unsubscribe()}));return n.pipeline.push(function(e,t,n){n(e,t),i()}),n},distinct:function(){return this.constraint(new m)},distinctUntilChanged:function(){return this.constraint(new d)},invokeSubscriber:function(e,t){if(!this.inactive){var n=this,i=n.pipeline,r=i.length,c=n._context,s=-1,o=!1;if(r){i=i.concat([n.callback]);var a=function u(e,t){s+=1,r>s?i[s].call(c,e,t,u):(n.callback.call(c,e,t),o=!0)};a(e,t,0)}else n.callback.call(c,e,t),o=!0;return o}},logError:function(){if(console){var e;e=console.warn?console.warn:console.log,this["catch"](e)}return this},once:function(){return this.disposeAfter(1)},subscribe:function(e){return this.callback=e,this},unsubscribe:function(){this.inactive||l.unsubscribe(this)},constraint:function(e){if("function"!=typeof e)throw new Error("Predicate constraint must be a function");return this.pipeline.push(function(t,n,i){e.call(this,t,n)&&i(t,n)}),this},constraints:function(t){var n=this;return e.each(t,function(e){n.constraint(e)}),n},context:function(e){return this._context=e,this},debounce:function(t,n){if("number"!=typeof t)throw new Error("Milliseconds must be a number");return this.pipeline.push(e.debounce(function(e,t,n){n(e,t)},t,!!n)),this},delay:function(e){if("number"!=typeof e)throw new Error("Milliseconds must be a number");var t=this;return t.pipeline.push(function(t,n,i){setTimeout(function(){i(t,n)},e)}),this},throttle:function(t){if("number"!=typeof t)throw new Error("Milliseconds must be a number");var n=function(e,t,n){n(e,t)};return this.pipeline.push(e.throttle(n,t)),this}};for(var g=["withConstraint","withConstraints","withContext","withDebounce","withDelay","withThrottle"],v=["constraint","constraints","context","debounce","delay","throttle"],y=0;6>y;y++){var w=g[y];b.prototype[w]=i(w,v[y])}var E=(f.resolver={cache:{},regex:{},enableCache:!0,compare:function(t,n,i){var r,c,s,o=n+f.cacheKeyDelimiter+t,a=this.cache[o],u=i||{},h=this.enableCache&&!u.resolverNoCache;return a===!0?a:-1===t.indexOf("#")&&-1===t.indexOf("*")?(a=n===t,h&&(this.cache[o]=a),a):((c=this.regex[t])||(r="^"+e.map(t.split("."),function(e){var t="";return s&&(t="#"!==s?"\\.\\b":"\\b"),t+="#"===e?"[\\s\\S]*":"*"===e?"[^.]+":e,s=e,t}).join("")+"$",c=this.regex[t]=new RegExp(r)),a=c.test(n),h&&(this.cache[o]=a),a)},reset:function(){this.cache={},this.regex={}},purge:function(t){var n=this,i=f.cacheKeyDelimiter,r=function(e,r){var c=r.split(i),s=c[0],o=c[1];"undefined"!=typeof t.topic&&t.topic!==s||"undefined"!=typeof t.binding&&t.binding!==o||delete n.cache[r]},c=function(e,t){var r=t.split(i);0===l.getSubscribersFor({topic:r[0]}).length&&delete n.cache[t]};if("undefined"==typeof t)this.reset();else{var s=t.compact===!0?c:r;e.each(this.cache,s)}}},0),_=[],x=0,C=e.bind(o,this,"created"),k=e.bind(o,this,"removed");if(e.extend(l,{cache:{},subscriptions:{},wireTaps:[],ChannelDefinition:p,SubscriptionDefinition:b,channel:function(e){return new p(e,this)},addWireTap:function(e){var t=this;return t.wireTaps.push(e),function(){var n=t.wireTaps.indexOf(e);-1!==n&&t.wireTaps.splice(n,1)}},noConflict:function(){if("undefined"==typeof window||"undefined"!=typeof window&&"function"==typeof define&&define.amd)throw new Error("noConflict can only be used in browser clients which aren't using AMD modules");return t.postal=u,this},getSubscribersFor:function(t){var n=[],i=this;return e.each(i.subscriptions,function(i){e.each(i,function(i){n=n.concat(e.filter(i,a(t,f.resolver)))})}),n},publish:function(t,n){++E;var i=t.channel=t.channel||f.DEFAULT_CHANNEL,c=t.topic;t.timeStamp=new Date,this.wireTaps.length&&e.each(this.wireTaps,function(e){e(t.data,t,E)});var o=i+f.cacheKeyDelimiter+c,a=this.cache[o],u=0,h=0;if(a)e.each(a,function(e){e.invokeSubscriber(t.data,t)?h++:u++});else{a=this.cache[o]=[];var l=s(c,a,o,function(e){e.invokeSubscriber(t.data,t)?h++:u++},t);e.each(this.subscriptions[i],function(t){e.each(t,l)})}0===--E&&r(),n&&n({activated:h,skipped:u})},reset:function(){this.unsubscribeFor(),f.resolver.reset(),this.subscriptions={}},subscribe:function(t){var n,i=this.subscriptions,r=new b(t.channel||f.DEFAULT_CHANNEL,t.topic,t.callback),c=i[r.channel],o=r.channel.length;return c||(c=i[r.channel]={}),n=i[r.channel][r.topic],n||(n=i[r.channel][r.topic]=[]),n.push(r),e.each(this.cache,function(e,t){t.substr(0,o)===r.channel&&s(t.split(f.cacheKeyDelimiter)[1],e,t)(r)}),f.enableSystemMessages&&this.publish(C(r)),r},unsubscribe:function(){for(var t,n,i,r,s=arguments.length,o=0;s>o;o++){if(t=arguments[o],t.inactive=!0,E)return _.push(t),void 0;if(n=this.subscriptions[t.channel],i=n&&n[t.topic]){var a=i.length;for(r=0;a>r;){if(i[r]===t){i.splice(r,1);break}r+=1}if(0===i.length&&(delete n[t.topic],e.keys(n).length||delete this.subscriptions[t.channel]),t.cacheKeys&&t.cacheKeys.length)for(var u;u=t.cacheKeys.pop();)e.each(this.cache[u],c(t,u,this.cache));if("function"==typeof f.resolver.purge){var h=f.autoCompactResolver===!0?0:"number"==typeof f.autoCompactResolver?f.autoCompactResolver-1:!1;h>=0&&x===h?(f.resolver.purge({compact:!0}),x=0):h>=0&&h>x&&(x+=1)}}f.enableSystemMessages&&this.publish(k(t))}},unsubscribeFor:function(e){var t=[];this.subscriptions&&(t=this.getSubscribersFor(e),this.unsubscribe.apply(this,t))}}),t&&Object.prototype.hasOwnProperty.call(t,"__postalReady__")&&e.isArray(t.__postalReady__))for(;t.__postalReady__.length;)t.__postalReady__.shift().onReady(l);return l}); \ No newline at end of file +(function(e,t){var n=require("lodash/internal/createPartialWrapper"),i={after:require("lodash/function/after"),any:require("lodash/internal/arraySome"),bind:function(e,t,i){return n(e,33,t,[i])},debounce:require("lodash/function/debounce"),each:require("lodash/internal/baseEach"),extend:require("lodash/internal/baseAssign"),filter:require("lodash/internal/arrayFilter"),isEqual:require("lodash/lang/isEqual"),keys:require("lodash/object/keys"),map:require("lodash/internal/arrayMap"),throttle:require("lodash/function/throttle")};"function"==typeof define&&define.amd?define(function(){return t(i,e)}):"object"==typeof module&&module.exports?module.exports=t(i,this):e.postal=t(i,e)})(this,function(e,t,n){function i(e,t){return function(){if(console.warn||console.log){var n="Warning, the "+e+" method has been deprecated. Please use "+t+" instead.";console.warn?console.warn(n):console.log(n)}return b.prototype[t].apply(this,arguments)}}function r(){for(;_.length;)l.unsubscribe(_.shift())}function c(e,t,n){return function(i,r,c){i===e&&c.splice(r,1),0===c.length&&delete n[t]}}function s(e,t,n,i,r){var c=r&&r.headers||{};return function(r){var s;f.resolver.compare(r.topic,e,c)&&(c.resolverNoCache||(s=t[n]=t[n]||[],s.push(r)),r.cacheKeys.push(n),i&&i(r))}}function o(e,t){return{channel:f.SYSTEM_CHANNEL,topic:"subscription."+e,data:{event:"subscription."+e,channel:t.channel,topic:t.topic}}}function a(t,n){return"function"==typeof t?t:t?function(i){var r=0,c=0;return e.each(t,function(e,s){r+=1,("topic"===s&&n.compare(i.topic,t.topic,{resolverNoCache:!0})||"context"===s&&t.context===i._context||i[s]===t[s])&&(c+=1)}),r===c}:function(){return!0}}var u=t.postal,h={DEFAULT_CHANNEL:"/",SYSTEM_CHANNEL:"postal",enableSystemMessages:!0,cacheKeyDelimiter:"|",autoCompactResolver:!1},l={configuration:e.extend({},h)},f=l.configuration,p=function(e,t){this.bus=t,this.channel=e||f.DEFAULT_CHANNEL};p.prototype.subscribe=function(){return this.bus.subscribe({channel:this.channel,topic:1===arguments.length?arguments[0].topic:arguments[0],callback:1===arguments.length?arguments[0].callback:arguments[1]})},p.prototype.publish=function(){var e,t={};"string"==typeof arguments[0]?(t.topic=arguments[0],t.data=arguments[1],e=arguments[2]):(t=arguments[0],e=arguments[1]),t.channel=this.channel,this.bus.publish(t,e)};var b=function(e,t,i){if(3!==arguments.length)throw new Error("You must provide a channel, topic and callback when creating a SubscriptionDefinition instance.");if(0===t.length)throw new Error("Topics cannot be empty");this.channel=e,this.topic=t,this.callback=i,this.pipeline=[],this.cacheKeys=[],this._context=n},d=function(){var t;return function(n){var i=!1;return"string"==typeof n?(i=n===t,t=n):(i=e.isEqual(n,t),t=e.extend({},n)),!i}},v=function(){var t=[];return function(n){var i=!e.any(t,function(t){return e.isEqual(n,t)});return i&&t.push(n),i}};b.prototype={"catch":function(e){var t=this.callback,n=function(){try{t.apply(this,arguments)}catch(n){e(n,arguments[0])}};return this.callback=n,this},defer:function(){return this.delay(0)},disposeAfter:function(t){if("number"!=typeof t||0>=t)throw new Error("The value provided to disposeAfter (maxCalls) must be a number greater than zero.");var n=this,i=e.after(t,e.bind(function(){n.unsubscribe()}));return n.pipeline.push(function(e,t,n){n(e,t),i()}),n},distinct:function(){return this.constraint(new v)},distinctUntilChanged:function(){return this.constraint(new d)},invokeSubscriber:function(e,t){if(!this.inactive){var n=this,i=n.pipeline,r=i.length,c=n._context,s=-1,o=!1;if(r){i=i.concat([n.callback]);var a=function u(e,t){s+=1,r>s?i[s].call(c,e,t,u):(n.callback.call(c,e,t),o=!0)};a(e,t,0)}else n.callback.call(c,e,t),o=!0;return o}},logError:function(){if(console){var e;e=console.warn?console.warn:console.log,this["catch"](e)}return this},once:function(){return this.disposeAfter(1)},subscribe:function(e){return this.callback=e,this},unsubscribe:function(){this.inactive||l.unsubscribe(this)},constraint:function(e){if("function"!=typeof e)throw new Error("Predicate constraint must be a function");return this.pipeline.push(function(t,n,i){e.call(this,t,n)&&i(t,n)}),this},constraints:function(t){var n=this;return e.each(t,function(e){n.constraint(e)}),n},context:function(e){return this._context=e,this},debounce:function(t,n){if("number"!=typeof t)throw new Error("Milliseconds must be a number");return this.pipeline.push(e.debounce(function(e,t,n){n(e,t)},t,!!n)),this},delay:function(e){if("number"!=typeof e)throw new Error("Milliseconds must be a number");var t=this;return t.pipeline.push(function(t,n,i){setTimeout(function(){i(t,n)},e)}),this},throttle:function(t){if("number"!=typeof t)throw new Error("Milliseconds must be a number");var n=function(e,t,n){n(e,t)};return this.pipeline.push(e.throttle(n,t)),this}};for(var m=["withConstraint","withConstraints","withContext","withDebounce","withDelay","withThrottle"],g=["constraint","constraints","context","debounce","delay","throttle"],y=0;6>y;y++){var w=m[y];b.prototype[w]=i(w,g[y])}var E=(f.resolver={cache:{},regex:{},enableCache:!0,compare:function(t,n,i){var r,c,s,o=n+f.cacheKeyDelimiter+t,a=this.cache[o],u=i||{},h=this.enableCache&&!u.resolverNoCache;return a===!0?a:-1===t.indexOf("#")&&-1===t.indexOf("*")?(a=n===t,h&&(this.cache[o]=a),a):((c=this.regex[t])||(r="^"+e.map(t.split("."),function(e){var t="";return s&&(t="#"!==s?"\\.\\b":"\\b"),t+="#"===e?"[\\s\\S]*":"*"===e?"[^.]+":e,s=e,t}).join("")+"$",c=this.regex[t]=new RegExp(r)),a=c.test(n),h&&(this.cache[o]=a),a)},reset:function(){this.cache={},this.regex={}},purge:function(t){var n=this,i=f.cacheKeyDelimiter,r=function(e,r){var c=r.split(i),s=c[0],o=c[1];"undefined"!=typeof t.topic&&t.topic!==s||"undefined"!=typeof t.binding&&t.binding!==o||delete n.cache[r]},c=function(e,t){var r=t.split(i);0===l.getSubscribersFor({topic:r[0]}).length&&delete n.cache[t]};if("undefined"==typeof t)this.reset();else{var s=t.compact===!0?c:r;e.each(this.cache,s)}}},0),_=[],x=0,C=e.bind(o,this,"created"),k=e.bind(o,this,"removed");if(e.extend(l,{cache:{},subscriptions:{},wireTaps:[],ChannelDefinition:p,SubscriptionDefinition:b,channel:function(e){return new p(e,this)},addWireTap:function(e){var t=this;return t.wireTaps.push(e),function(){var n=t.wireTaps.indexOf(e);-1!==n&&t.wireTaps.splice(n,1)}},noConflict:function(){if("undefined"==typeof window||"undefined"!=typeof window&&"function"==typeof define&&define.amd)throw new Error("noConflict can only be used in browser clients which aren't using AMD modules");return t.postal=u,this},getSubscribersFor:function(t){var n=[],i=this;return e.each(i.subscriptions,function(i){e.each(i,function(i){n=n.concat(e.filter(i,a(t,f.resolver)))})}),n},publish:function(t,n){++E;var i=t.channel=t.channel||f.DEFAULT_CHANNEL,c=t.topic;t.timeStamp=new Date,this.wireTaps.length&&e.each(this.wireTaps,function(e){e(t.data,t,E)});var o=i+f.cacheKeyDelimiter+c,a=this.cache[o],u=0,h=0;if(a)e.each(a,function(e){e.invokeSubscriber(t.data,t)?h++:u++});else{var l=s(c,this.cache,o,function(e){e.invokeSubscriber(t.data,t)?h++:u++},t);e.each(this.subscriptions[i],function(t){e.each(t,l)})}0===--E&&r(),n&&n({activated:h,skipped:u})},reset:function(){this.unsubscribeFor(),f.resolver.reset(),this.subscriptions={},this.cache={}},subscribe:function(t){var n,i=this.subscriptions,r=new b(t.channel||f.DEFAULT_CHANNEL,t.topic,t.callback),c=i[r.channel],o=r.channel.length;return c||(c=i[r.channel]={}),n=i[r.channel][r.topic],n||(n=i[r.channel][r.topic]=[]),n.push(r),e.each(this.cache,function(e,t){t.substr(0,o)===r.channel&&s(t.split(f.cacheKeyDelimiter)[1],e,t)(r)}),f.enableSystemMessages&&this.publish(C(r)),r},unsubscribe:function(){for(var t,n,i,r,s=arguments.length,o=0;s>o;o++){if(t=arguments[o],t.inactive=!0,E)return void _.push(t);if(n=this.subscriptions[t.channel],i=n&&n[t.topic]){var a=i.length;for(r=0;a>r;){if(i[r]===t){i.splice(r,1);break}r+=1}if(0===i.length&&(delete n[t.topic],e.keys(n).length||delete this.subscriptions[t.channel]),t.cacheKeys&&t.cacheKeys.length)for(var u;u=t.cacheKeys.pop();)e.each(this.cache[u],c(t,u,this.cache));if("function"==typeof f.resolver.purge){var h=f.autoCompactResolver===!0?0:"number"==typeof f.autoCompactResolver?f.autoCompactResolver-1:!1;h>=0&&x===h?(f.resolver.purge({compact:!0}),x=0):h>=0&&h>x&&(x+=1)}}f.enableSystemMessages&&this.publish(k(t))}},unsubscribeFor:function(e){var t=[];this.subscriptions&&(t=this.getSubscribersFor(e),this.unsubscribe.apply(this,t))}}),t&&Object.prototype.hasOwnProperty.call(t,"__postalReady__")&&e.isArray(t.__postalReady__))for(;t.__postalReady__.length;)t.__postalReady__.shift().onReady(l);return l}); \ No newline at end of file diff --git a/lib/postal.min.js b/lib/postal.min.js index aa9c5151..0d8735eb 100644 --- a/lib/postal.min.js +++ b/lib/postal.min.js @@ -1,8 +1,8 @@ /** * postal - Pub/Sub library providing wildcard subscriptions, complex message handling, etc. Works server and client-side. * Author: Jim Cowart (http://ifandelse.com) - * Version: v1.0.2 + * Version: v1.0.3 * Url: http://github.com/postaljs/postal.js * License(s): MIT */ -(function(e,t){"function"==typeof define&&define.amd?define(["lodash"],function(n){return t(n,e)}):"object"==typeof module&&module.exports?module.exports=t(require("lodash"),this):e.postal=t(e._,e)})(this,function(e,t,n){function i(e,t){return function(){if(console.warn||console.log){var n="Warning, the "+e+" method has been deprecated. Please use "+t+" instead.";console.warn?console.warn(n):console.log(n)}return b.prototype[t].apply(this,arguments)}}function r(){for(;E.length;)l.unsubscribe(E.shift())}function c(e,t,n){return function(i,r,c){i===e&&c.splice(r,1),0===c.length&&delete n[t]}}function s(e,t,n,i,r){var c=r&&r.headers||{};return function(r){f.resolver.compare(r.topic,e,c)&&(t.push(r),r.cacheKeys.push(n),i&&i(r))}}function o(e,t){return{channel:f.SYSTEM_CHANNEL,topic:"subscription."+e,data:{event:"subscription."+e,channel:t.channel,topic:t.topic}}}function a(t,n){return"function"==typeof t?t:t?function(i){var r=0,c=0;return e.each(t,function(e,s){r+=1,("topic"===s&&n.compare(i.topic,t.topic,{resolverNoCache:!0})||"context"===s&&t.context===i._context||i[s]===t[s])&&(c+=1)}),r===c}:function(){return!0}}var u=t.postal,h={DEFAULT_CHANNEL:"/",SYSTEM_CHANNEL:"postal",enableSystemMessages:!0,cacheKeyDelimiter:"|",autoCompactResolver:!1},l={configuration:e.extend({},h)},f=l.configuration,p=function(e,t){this.bus=t,this.channel=e||f.DEFAULT_CHANNEL};p.prototype.subscribe=function(){return this.bus.subscribe({channel:this.channel,topic:1===arguments.length?arguments[0].topic:arguments[0],callback:1===arguments.length?arguments[0].callback:arguments[1]})},p.prototype.publish=function(){var e,t={};"string"==typeof arguments[0]?(t.topic=arguments[0],t.data=arguments[1],e=arguments[2]):(t=arguments[0],e=arguments[1]),t.channel=this.channel,this.bus.publish(t,e)};var b=function(e,t,i){if(3!==arguments.length)throw new Error("You must provide a channel, topic and callback when creating a SubscriptionDefinition instance.");if(0===t.length)throw new Error("Topics cannot be empty");this.channel=e,this.topic=t,this.callback=i,this.pipeline=[],this.cacheKeys=[],this._context=n},d=function(){var t;return function(n){var i=!1;return"string"==typeof n?(i=n===t,t=n):(i=e.isEqual(n,t),t=e.extend({},n)),!i}},m=function(){var t=[];return function(n){var i=!e.any(t,function(t){return e.isEqual(n,t)});return i&&t.push(n),i}};b.prototype={"catch":function(e){var t=this.callback,n=function(){try{t.apply(this,arguments)}catch(n){e(n,arguments[0])}};return this.callback=n,this},defer:function(){return this.delay(0)},disposeAfter:function(t){if("number"!=typeof t||0>=t)throw new Error("The value provided to disposeAfter (maxCalls) must be a number greater than zero.");var n=this,i=e.after(t,e.bind(function(){n.unsubscribe()}));return n.pipeline.push(function(e,t,n){n(e,t),i()}),n},distinct:function(){return this.constraint(new m)},distinctUntilChanged:function(){return this.constraint(new d)},invokeSubscriber:function(e,t){if(!this.inactive){var n=this,i=n.pipeline,r=i.length,c=n._context,s=-1,o=!1;if(r){i=i.concat([n.callback]);var a=function u(e,t){s+=1,r>s?i[s].call(c,e,t,u):(n.callback.call(c,e,t),o=!0)};a(e,t,0)}else n.callback.call(c,e,t),o=!0;return o}},logError:function(){if(console){var e;e=console.warn?console.warn:console.log,this["catch"](e)}return this},once:function(){return this.disposeAfter(1)},subscribe:function(e){return this.callback=e,this},unsubscribe:function(){this.inactive||l.unsubscribe(this)},constraint:function(e){if("function"!=typeof e)throw new Error("Predicate constraint must be a function");return this.pipeline.push(function(t,n,i){e.call(this,t,n)&&i(t,n)}),this},constraints:function(t){var n=this;return e.each(t,function(e){n.constraint(e)}),n},context:function(e){return this._context=e,this},debounce:function(t,n){if("number"!=typeof t)throw new Error("Milliseconds must be a number");return this.pipeline.push(e.debounce(function(e,t,n){n(e,t)},t,!!n)),this},delay:function(e){if("number"!=typeof e)throw new Error("Milliseconds must be a number");var t=this;return t.pipeline.push(function(t,n,i){setTimeout(function(){i(t,n)},e)}),this},throttle:function(t){if("number"!=typeof t)throw new Error("Milliseconds must be a number");var n=function(e,t,n){n(e,t)};return this.pipeline.push(e.throttle(n,t)),this}};for(var v=["withConstraint","withConstraints","withContext","withDebounce","withDelay","withThrottle"],g=["constraint","constraints","context","debounce","delay","throttle"],y=0;6>y;y++){var w=v[y];b.prototype[w]=i(w,g[y])}var _=(f.resolver={cache:{},regex:{},enableCache:!0,compare:function(t,n,i){var r,c,s,o=n+f.cacheKeyDelimiter+t,a=this.cache[o],u=i||{},h=this.enableCache&&!u.resolverNoCache;return a===!0?a:-1===t.indexOf("#")&&-1===t.indexOf("*")?(a=n===t,h&&(this.cache[o]=a),a):((c=this.regex[t])||(r="^"+e.map(t.split("."),function(e){var t="";return s&&(t="#"!==s?"\\.\\b":"\\b"),t+="#"===e?"[\\s\\S]*":"*"===e?"[^.]+":e,s=e,t}).join("")+"$",c=this.regex[t]=new RegExp(r)),a=c.test(n),h&&(this.cache[o]=a),a)},reset:function(){this.cache={},this.regex={}},purge:function(t){var n=this,i=f.cacheKeyDelimiter,r=function(e,r){var c=r.split(i),s=c[0],o=c[1];"undefined"!=typeof t.topic&&t.topic!==s||"undefined"!=typeof t.binding&&t.binding!==o||delete n.cache[r]},c=function(e,t){var r=t.split(i);0===l.getSubscribersFor({topic:r[0]}).length&&delete n.cache[t]};if("undefined"==typeof t)this.reset();else{var s=t.compact===!0?c:r;e.each(this.cache,s)}}},0),E=[],x=0,C=e.bind(o,this,"created"),k=e.bind(o,this,"removed");if(e.extend(l,{cache:{},subscriptions:{},wireTaps:[],ChannelDefinition:p,SubscriptionDefinition:b,channel:function(e){return new p(e,this)},addWireTap:function(e){var t=this;return t.wireTaps.push(e),function(){var n=t.wireTaps.indexOf(e);-1!==n&&t.wireTaps.splice(n,1)}},noConflict:function(){if("undefined"==typeof window||"undefined"!=typeof window&&"function"==typeof define&&define.amd)throw new Error("noConflict can only be used in browser clients which aren't using AMD modules");return t.postal=u,this},getSubscribersFor:function(t){var n=[],i=this;return e.each(i.subscriptions,function(i){e.each(i,function(i){n=n.concat(e.filter(i,a(t,f.resolver)))})}),n},publish:function(t,n){++_;var i=t.channel=t.channel||f.DEFAULT_CHANNEL,c=t.topic;t.timeStamp=new Date,this.wireTaps.length&&e.each(this.wireTaps,function(e){e(t.data,t,_)});var o=i+f.cacheKeyDelimiter+c,a=this.cache[o],u=0,h=0;if(a)e.each(a,function(e){e.invokeSubscriber(t.data,t)?h++:u++});else{a=this.cache[o]=[];var l=s(c,a,o,function(e){e.invokeSubscriber(t.data,t)?h++:u++},t);e.each(this.subscriptions[i],function(t){e.each(t,l)})}0===--_&&r(),n&&n({activated:h,skipped:u})},reset:function(){this.unsubscribeFor(),f.resolver.reset(),this.subscriptions={}},subscribe:function(t){var n,i=this.subscriptions,r=new b(t.channel||f.DEFAULT_CHANNEL,t.topic,t.callback),c=i[r.channel],o=r.channel.length;return c||(c=i[r.channel]={}),n=i[r.channel][r.topic],n||(n=i[r.channel][r.topic]=[]),n.push(r),e.each(this.cache,function(e,t){t.substr(0,o)===r.channel&&s(t.split(f.cacheKeyDelimiter)[1],e,t)(r)}),f.enableSystemMessages&&this.publish(C(r)),r},unsubscribe:function(){for(var t,n,i,r,s=arguments.length,o=0;s>o;o++){if(t=arguments[o],t.inactive=!0,_)return E.push(t),void 0;if(n=this.subscriptions[t.channel],i=n&&n[t.topic]){var a=i.length;for(r=0;a>r;){if(i[r]===t){i.splice(r,1);break}r+=1}if(0===i.length&&(delete n[t.topic],e.keys(n).length||delete this.subscriptions[t.channel]),t.cacheKeys&&t.cacheKeys.length)for(var u;u=t.cacheKeys.pop();)e.each(this.cache[u],c(t,u,this.cache));if("function"==typeof f.resolver.purge){var h=f.autoCompactResolver===!0?0:"number"==typeof f.autoCompactResolver?f.autoCompactResolver-1:!1;h>=0&&x===h?(f.resolver.purge({compact:!0}),x=0):h>=0&&h>x&&(x+=1)}}f.enableSystemMessages&&this.publish(k(t))}},unsubscribeFor:function(e){var t=[];this.subscriptions&&(t=this.getSubscribersFor(e),this.unsubscribe.apply(this,t))}}),t&&Object.prototype.hasOwnProperty.call(t,"__postalReady__")&&e.isArray(t.__postalReady__))for(;t.__postalReady__.length;)t.__postalReady__.shift().onReady(l);return l}); \ No newline at end of file +(function(e,t){"function"==typeof define&&define.amd?define(["lodash"],function(n){return t(n,e)}):"object"==typeof module&&module.exports?module.exports=t(require("lodash"),this):e.postal=t(e._,e)})(this,function(e,t,n){function i(e,t){return function(){if(console.warn||console.log){var n="Warning, the "+e+" method has been deprecated. Please use "+t+" instead.";console.warn?console.warn(n):console.log(n)}return b.prototype[t].apply(this,arguments)}}function r(){for(;E.length;)l.unsubscribe(E.shift())}function c(e,t,n){return function(i,r,c){i===e&&c.splice(r,1),0===c.length&&delete n[t]}}function s(e,t,n,i,r){var c=r&&r.headers||{};return function(r){var s;f.resolver.compare(r.topic,e,c)&&(c.resolverNoCache||(s=t[n]=t[n]||[],s.push(r)),r.cacheKeys.push(n),i&&i(r))}}function o(e,t){return{channel:f.SYSTEM_CHANNEL,topic:"subscription."+e,data:{event:"subscription."+e,channel:t.channel,topic:t.topic}}}function a(t,n){return"function"==typeof t?t:t?function(i){var r=0,c=0;return e.each(t,function(e,s){r+=1,("topic"===s&&n.compare(i.topic,t.topic,{resolverNoCache:!0})||"context"===s&&t.context===i._context||i[s]===t[s])&&(c+=1)}),r===c}:function(){return!0}}var u=t.postal,h={DEFAULT_CHANNEL:"/",SYSTEM_CHANNEL:"postal",enableSystemMessages:!0,cacheKeyDelimiter:"|",autoCompactResolver:!1},l={configuration:e.extend({},h)},f=l.configuration,p=function(e,t){this.bus=t,this.channel=e||f.DEFAULT_CHANNEL};p.prototype.subscribe=function(){return this.bus.subscribe({channel:this.channel,topic:1===arguments.length?arguments[0].topic:arguments[0],callback:1===arguments.length?arguments[0].callback:arguments[1]})},p.prototype.publish=function(){var e,t={};"string"==typeof arguments[0]?(t.topic=arguments[0],t.data=arguments[1],e=arguments[2]):(t=arguments[0],e=arguments[1]),t.channel=this.channel,this.bus.publish(t,e)};var b=function(e,t,i){if(3!==arguments.length)throw new Error("You must provide a channel, topic and callback when creating a SubscriptionDefinition instance.");if(0===t.length)throw new Error("Topics cannot be empty");this.channel=e,this.topic=t,this.callback=i,this.pipeline=[],this.cacheKeys=[],this._context=n},d=function(){var t;return function(n){var i=!1;return"string"==typeof n?(i=n===t,t=n):(i=e.isEqual(n,t),t=e.extend({},n)),!i}},v=function(){var t=[];return function(n){var i=!e.any(t,function(t){return e.isEqual(n,t)});return i&&t.push(n),i}};b.prototype={"catch":function(e){var t=this.callback,n=function(){try{t.apply(this,arguments)}catch(n){e(n,arguments[0])}};return this.callback=n,this},defer:function(){return this.delay(0)},disposeAfter:function(t){if("number"!=typeof t||0>=t)throw new Error("The value provided to disposeAfter (maxCalls) must be a number greater than zero.");var n=this,i=e.after(t,e.bind(function(){n.unsubscribe()}));return n.pipeline.push(function(e,t,n){n(e,t),i()}),n},distinct:function(){return this.constraint(new v)},distinctUntilChanged:function(){return this.constraint(new d)},invokeSubscriber:function(e,t){if(!this.inactive){var n=this,i=n.pipeline,r=i.length,c=n._context,s=-1,o=!1;if(r){i=i.concat([n.callback]);var a=function u(e,t){s+=1,r>s?i[s].call(c,e,t,u):(n.callback.call(c,e,t),o=!0)};a(e,t,0)}else n.callback.call(c,e,t),o=!0;return o}},logError:function(){if(console){var e;e=console.warn?console.warn:console.log,this["catch"](e)}return this},once:function(){return this.disposeAfter(1)},subscribe:function(e){return this.callback=e,this},unsubscribe:function(){this.inactive||l.unsubscribe(this)},constraint:function(e){if("function"!=typeof e)throw new Error("Predicate constraint must be a function");return this.pipeline.push(function(t,n,i){e.call(this,t,n)&&i(t,n)}),this},constraints:function(t){var n=this;return e.each(t,function(e){n.constraint(e)}),n},context:function(e){return this._context=e,this},debounce:function(t,n){if("number"!=typeof t)throw new Error("Milliseconds must be a number");return this.pipeline.push(e.debounce(function(e,t,n){n(e,t)},t,!!n)),this},delay:function(e){if("number"!=typeof e)throw new Error("Milliseconds must be a number");var t=this;return t.pipeline.push(function(t,n,i){setTimeout(function(){i(t,n)},e)}),this},throttle:function(t){if("number"!=typeof t)throw new Error("Milliseconds must be a number");var n=function(e,t,n){n(e,t)};return this.pipeline.push(e.throttle(n,t)),this}};for(var m=["withConstraint","withConstraints","withContext","withDebounce","withDelay","withThrottle"],g=["constraint","constraints","context","debounce","delay","throttle"],y=0;6>y;y++){var w=m[y];b.prototype[w]=i(w,g[y])}var _=(f.resolver={cache:{},regex:{},enableCache:!0,compare:function(t,n,i){var r,c,s,o=n+f.cacheKeyDelimiter+t,a=this.cache[o],u=i||{},h=this.enableCache&&!u.resolverNoCache;return a===!0?a:-1===t.indexOf("#")&&-1===t.indexOf("*")?(a=n===t,h&&(this.cache[o]=a),a):((c=this.regex[t])||(r="^"+e.map(t.split("."),function(e){var t="";return s&&(t="#"!==s?"\\.\\b":"\\b"),t+="#"===e?"[\\s\\S]*":"*"===e?"[^.]+":e,s=e,t}).join("")+"$",c=this.regex[t]=new RegExp(r)),a=c.test(n),h&&(this.cache[o]=a),a)},reset:function(){this.cache={},this.regex={}},purge:function(t){var n=this,i=f.cacheKeyDelimiter,r=function(e,r){var c=r.split(i),s=c[0],o=c[1];"undefined"!=typeof t.topic&&t.topic!==s||"undefined"!=typeof t.binding&&t.binding!==o||delete n.cache[r]},c=function(e,t){var r=t.split(i);0===l.getSubscribersFor({topic:r[0]}).length&&delete n.cache[t]};if("undefined"==typeof t)this.reset();else{var s=t.compact===!0?c:r;e.each(this.cache,s)}}},0),E=[],x=0,C=e.bind(o,this,"created"),k=e.bind(o,this,"removed");if(e.extend(l,{cache:{},subscriptions:{},wireTaps:[],ChannelDefinition:p,SubscriptionDefinition:b,channel:function(e){return new p(e,this)},addWireTap:function(e){var t=this;return t.wireTaps.push(e),function(){var n=t.wireTaps.indexOf(e);-1!==n&&t.wireTaps.splice(n,1)}},noConflict:function(){if("undefined"==typeof window||"undefined"!=typeof window&&"function"==typeof define&&define.amd)throw new Error("noConflict can only be used in browser clients which aren't using AMD modules");return t.postal=u,this},getSubscribersFor:function(t){var n=[],i=this;return e.each(i.subscriptions,function(i){e.each(i,function(i){n=n.concat(e.filter(i,a(t,f.resolver)))})}),n},publish:function(t,n){++_;var i=t.channel=t.channel||f.DEFAULT_CHANNEL,c=t.topic;t.timeStamp=new Date,this.wireTaps.length&&e.each(this.wireTaps,function(e){e(t.data,t,_)});var o=i+f.cacheKeyDelimiter+c,a=this.cache[o],u=0,h=0;if(a)e.each(a,function(e){e.invokeSubscriber(t.data,t)?h++:u++});else{var l=s(c,this.cache,o,function(e){e.invokeSubscriber(t.data,t)?h++:u++},t);e.each(this.subscriptions[i],function(t){e.each(t,l)})}0===--_&&r(),n&&n({activated:h,skipped:u})},reset:function(){this.unsubscribeFor(),f.resolver.reset(),this.subscriptions={},this.cache={}},subscribe:function(t){var n,i=this.subscriptions,r=new b(t.channel||f.DEFAULT_CHANNEL,t.topic,t.callback),c=i[r.channel],o=r.channel.length;return c||(c=i[r.channel]={}),n=i[r.channel][r.topic],n||(n=i[r.channel][r.topic]=[]),n.push(r),e.each(this.cache,function(e,t){t.substr(0,o)===r.channel&&s(t.split(f.cacheKeyDelimiter)[1],e,t)(r)}),f.enableSystemMessages&&this.publish(C(r)),r},unsubscribe:function(){for(var t,n,i,r,s=arguments.length,o=0;s>o;o++){if(t=arguments[o],t.inactive=!0,_)return void E.push(t);if(n=this.subscriptions[t.channel],i=n&&n[t.topic]){var a=i.length;for(r=0;a>r;){if(i[r]===t){i.splice(r,1);break}r+=1}if(0===i.length&&(delete n[t.topic],e.keys(n).length||delete this.subscriptions[t.channel]),t.cacheKeys&&t.cacheKeys.length)for(var u;u=t.cacheKeys.pop();)e.each(this.cache[u],c(t,u,this.cache));if("function"==typeof f.resolver.purge){var h=f.autoCompactResolver===!0?0:"number"==typeof f.autoCompactResolver?f.autoCompactResolver-1:!1;h>=0&&x===h?(f.resolver.purge({compact:!0}),x=0):h>=0&&h>x&&(x+=1)}}f.enableSystemMessages&&this.publish(k(t))}},unsubscribeFor:function(e){var t=[];this.subscriptions&&(t=this.getSubscribersFor(e),this.unsubscribe.apply(this,t))}}),t&&Object.prototype.hasOwnProperty.call(t,"__postalReady__")&&e.isArray(t.__postalReady__))for(;t.__postalReady__.length;)t.__postalReady__.shift().onReady(l);return l}); \ No newline at end of file diff --git a/package.json b/package.json index 2cc3cafe..611e44ed 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "postal", "description": "Pub/Sub library providing wildcard subscriptions, complex message handling, etc. Works server and client-side.", - "version": "1.0.2", + "version": "1.0.3", "homepage": "http://github.com/postaljs/postal.js", "repository": { "type": "git", @@ -88,25 +88,28 @@ "lodash": "3.x" }, "devDependencies": { - "bower": "~1.2.8", - "expect.js": "~0.2.0", - "express": "~3.4.7", + "bower": "^1.4.1", + "express": "^4.12.3", "gulp": "^3.8.8", - "gulp-beautify": "~1.0.3", - "gulp-header": "~1.0.2", + "gulp-beautify": "^1.1.2", + "gulp-changed": "^1.2.1", + "gulp-header": "^1.2.2", "gulp-hint-not": "~0.0.3", "gulp-imports": "~0.0.1", - "gulp-plato": "^0.2.1", - "gulp-rename": "^1.2.0", - "gulp-spawn-mocha": "^0.5.1", - "gulp-uglify": "^0.3.0", + "gulp-jscs": "^1.6.0", + "gulp-jshint": "^1.10.0", + "gulp-plato": "^1.0.2", + "gulp-rename": "^1.2.2", + "gulp-spawn-mocha": "^2.0.1", + "gulp-uglify": "^1.2.0", "gulp-util": "~2.2.9", - "istanbul": "^0.3.2", - "karma": "^0.12.24", - "mocha": "^2.0.1", + "istanbul": "^0.3.13", + "jshint-stylish": "^1.0.2", + "karma": "^0.12.31", + "mocha": "^2.2.4", "open": "~0.0.4", - "should": "^4.0.4", - "sinon": "~1.11.1" + "should": "^6.0.1", + "sinon": "~1.14.1" }, "licenses": [ { diff --git a/spec/.jshintrc b/spec/.jshintrc index edada6c1..630174dd 100644 --- a/spec/.jshintrc +++ b/spec/.jshintrc @@ -13,7 +13,7 @@ "curly" : true, //requires you to always put curly braces around blocks in loops and conditionals "eqeqeq" : true, //prohibits the use of == and != in favor of === and !== "forin" : true, //requires all `for in` loops to filter object's items with `hasOwnProperty()` - "immed" : true, //prohibits the use of immediate function invocations without wrapping them in parentheses + "immed" : false, //prohibits the use of immediate function invocations without wrapping them in parentheses "indent" : 4, //enforces specific tab width "latedef" : true, //prohibits the use of a variable before it was defined "newcap" : false, //requires you to capitalize names of constructor functions @@ -41,7 +41,6 @@ "boss" : true, //suppresses warnings about the use of assignments in cases where comparisons are expected "debug" : false, //suppresses warnings about the debugger statements in your code "eqnull" : false, //suppresses warnings about == null comparisons - "es5" : true, //your code uses ECMAScript 5 specific features such as getters and setters "esnext" : true, //your code uses ES.next specific features such as const "evil" : false, //suppresses warnings about the use of eval "expr" : true, //suppresses warnings about the use of expressions where normally you would expect to see assignments or function calls @@ -75,7 +74,7 @@ "dojo" : false, //defines globals exposed by the Dojo Toolkit "jquery" : false, //defines globals exposed by the jQuery JavaScript library "mootools" : false, //defines globals exposed by the MooTools JavaScript framework - "node" : false, //defines globals available when your code is running inside of the Node runtime environment + "node" : true, //defines globals available when your code is running inside of the Node runtime environment "nonstandard" : true, //defines non-standard but widely adopted globals such as `escape` and `unescape` "prototypejs" : false, //defines globals exposed by the Prototype JavaScript framework "rhino" : false, //defines globals available when your code is running inside of the Rhino runtime environment diff --git a/spec/helpers/node-lodash-build-setup.js b/spec/helpers/node-lodash-build-setup.js index 44bdfe6f..88f809ca 100644 --- a/spec/helpers/node-lodash-build-setup.js +++ b/spec/helpers/node-lodash-build-setup.js @@ -1,3 +1,4 @@ +/* global global */ // Setup for running Mocha via Node require( "should/should" ); diff --git a/spec/helpers/phantomjs-shims.js b/spec/helpers/phantomjs-shims.js index dd1be0fd..8a906896 100644 --- a/spec/helpers/phantomjs-shims.js +++ b/spec/helpers/phantomjs-shims.js @@ -1,7 +1,6 @@ // From https://github.com/newtriks/react-automation-example/blob/master/test/helpers/phantomjs-shims.js -(function() { - +( function() { var Ap = Array.prototype; var slice = Ap.slice; var Fp = Function.prototype; @@ -33,4 +32,4 @@ return bound; }; } -})(); +} )(); diff --git a/spec/publishing.spec.js b/spec/publishing.spec.js index aeb53544..cd052911 100644 --- a/spec/publishing.spec.js +++ b/spec/publishing.spec.js @@ -3,6 +3,7 @@ describe( "postal.js - publishing", function() { describe( "when publishing to a new topic", function() { it( "should create cache entry", function() { postal.cache.should.not.have.property( "Doctor|Dont.Blink" ); //jshint ignore:line + var subA = postal.subscribe( { channel: "Doctor", topic: "Dont.Blink", callback: function() {} } ); postal.publish( { channel: "Doctor", topic: "Dont.Blink", @@ -110,7 +111,14 @@ describe( "postal.js - publishing", function() { } ); } ); describe( "when using envelope header `resolverNoCache`", function() { - it( "should not add a cache entry if set to true", function() { + beforeEach( function() { + postal.reset(); + postal.configuration.autoCompactResolver = true; + } ); + afterEach( function() { + postal.configuration.autoCompactResolver = false; + } ); + it( "should not add a resolver cache entry if set to true", function() { var subA = postal.subscribe( { channel: "clara", topic: "run.you.clever.*", callback: function() {} } ); var subB = postal.subscribe( { channel: "rose", topic: "bad.wolf", callback: function() {} } ); postal.publish( { @@ -125,7 +133,7 @@ describe( "postal.js - publishing", function() { subB.unsubscribe(); postal.configuration.resolver.cache.should.not.have.ownProperty( "run.you.clever.boy|run.you.clever.*" ); } ); - it( "should add a cache entry explicitly set to false)", function() { + it( "should add a resolver cache entry if explicitly set to false", function() { var subA = postal.subscribe( { channel: "clara", topic: "run.you.clever.*", callback: function() {} } ); var subB = postal.subscribe( { channel: "rose", topic: "bad.wolf", callback: function() {} } ); postal.publish( { @@ -133,13 +141,36 @@ describe( "postal.js - publishing", function() { topic: "run.you.clever.boy", data: "RYCB", headers: { - resolverNoCache: true + resolverNoCache: false } } ); postal.configuration.resolver.cache.should.not.have.ownProperty( "bad.wolf|bad.wolf" ); subB.unsubscribe(); postal.configuration.resolver.cache.should.have.ownProperty( "run.you.clever.boy|run.you.clever.*" ); } ); + it( "should not add a subscription cache entry if set to true", function() { + postal.publish( { + channel: "clara", + topic: "run.you.clever.boy", + data: "RYCB", + headers: { + resolverNoCache: true + } + } ); + postal.cache.should.not.have.ownProperty( "clara" + postal.configuration.cacheKeyDelimiter + "run.you.clever.boy" ); + } ); + it( "should add a subscription cache entry if explicitly set to false", function() { + var subA = postal.subscribe( { channel: "clara", topic: "run.you.clever.*", callback: function() {} } ); + postal.publish( { + channel: "clara", + topic: "run.you.clever.boy", + data: "RYCB!!", + headers: { + resolverNoCache: false + } + } ); + postal.cache.should.have.ownProperty( "clara" + postal.configuration.cacheKeyDelimiter + "run.you.clever.boy" ); + } ); } ); describe( "when publishing with a callback", function() { @@ -149,13 +180,13 @@ describe( "postal.js - publishing", function() { var subCCount = 0; var subDCount = 0; var subA = postal.subscribe( { channel: "rose", topic: "bad.wolf", callback: function() { - subACount++; + subACount++; } } ); var subB = postal.subscribe( { channel: "rose", topic: "*.wolf", callback: function() { - subBCount++; + subBCount++; } } ); var subC = postal.subscribe( { channel: "rose", topic: "bad.*", callback: function() { - subCCount++; + subCCount++; } } ); var subD = postal.subscribe( { channel: "rose", topic: "#", callback: function() { subDCount++; diff --git a/spec/subscriptions.spec.js b/spec/subscriptions.spec.js index 30a0265e..39f0066b 100644 --- a/spec/subscriptions.spec.js +++ b/spec/subscriptions.spec.js @@ -2,7 +2,7 @@ var sinon = require( "sinon" ); -var subFactory = (function() { +var subFactory = ( function() { var idx = 0; return { next: function( callback ) { @@ -14,7 +14,7 @@ var subFactory = (function() { } ); } }; -}()); +}() ); var NO_OP = function() {}; var systemMessages = []; @@ -116,7 +116,6 @@ describe( "postal.js - subscriptions", function() { topic: sub.topic, data: { msg: "Bad Wolf" } } ); - } ); } ); describe( "When subscribing and specifying the context", function() { @@ -162,7 +161,7 @@ describe( "postal.js - subscriptions", function() { res.push( d.msg ); name = this.name; } ).disposeAfter( 4 ).context( ctxObj ); - while (i < 4) { + while ( i < 4 ) { postal.publish( { channel: sub.channel, topic: sub.topic, @@ -177,18 +176,16 @@ describe( "postal.js - subscriptions", function() { it( "should throw an exception if the provided argument is not a number", function() { try { var sub = subFactory.next( function( d, e ) {} ).disposeAfter( "fantastic" ); - } catch (ex) { + } catch ( ex ) { ex.should.be.instanceOf( Error ); } - } ); it( "should throw an exception if the provided argument is not a number", function() { try { var sub = subFactory.next( function( d, e ) {} ).disposeAfter( "fantastic" ); - } catch (ex) { + } catch ( ex ) { ex.should.be.instanceOf( Error ); } - } ); } ); describe( "When subscribing with `distinct`", function() { @@ -389,7 +386,7 @@ describe( "postal.js - subscriptions", function() { res.push( d.msg ); name = this.actor; } ).once().context( ctxObj ); - while (i < 5) { + while ( i < 5 ) { postal.publish( { channel: sub.channel, topic: sub.topic, @@ -413,7 +410,7 @@ describe( "postal.js - subscriptions", function() { name = this.actor; return ( d.season >= 2 && d.season <= 4 ); } ).context( ctxObj ); - while (i < 8) { + while ( i < 8 ) { postal.publish( { channel: sub.channel, topic: sub.topic, @@ -435,7 +432,7 @@ describe( "postal.js - subscriptions", function() { name = this.actor; return ( d.season >= 5 && d.season <= 8 ); } ).context( ctxObj ); - while (i < 5) { + while ( i < 5 ) { postal.publish( { channel: sub.channel, topic: sub.topic, @@ -449,7 +446,7 @@ describe( "postal.js - subscriptions", function() { it( "should throw an exception if the value provided is not a function", function() { try { var sub = subFactory.next( function( d, e ) {} ).constraint( 123 ); - } catch (ex) { + } catch ( ex ) { ex.should.be.instanceOf( Error ); } } ); @@ -537,7 +534,7 @@ describe( "postal.js - subscriptions", function() { it( "should throw an exception if the value provided is not a number", function() { try { var sub = subFactory.next( function( d, e ) {} ).debounce( "gently" ); - } catch (ex) { + } catch ( ex ) { ex.should.be.instanceOf( Error ); } } ); @@ -565,7 +562,7 @@ describe( "postal.js - subscriptions", function() { it( "should throw an exception if the value provided is not a number", function() { try { var sub = subFactory.next( function( d, e ) {} ).delay( "gently" ); - } catch (ex) { + } catch ( ex ) { ex.should.be.instanceOf( Error ); } } ); @@ -585,7 +582,7 @@ describe( "postal.js - subscriptions", function() { setTimeout( function() { channel.publish( sub.topic, 800 ); }, 800 ); // should invoke callback - for (var i = 0; i < 20; i++) { + for ( var i = 0; i < 20; i++ ) { throttlePub( i ); } setTimeout( function() { @@ -598,7 +595,7 @@ describe( "postal.js - subscriptions", function() { it( "should throw an exception if the value provided is not a number", function() { try { var sub = subFactory.next( function( d, e ) {} ).throttle( "gently" ); - } catch (ex) { + } catch ( ex ) { ex.should.be.instanceOf( Error ); } } ); @@ -623,7 +620,7 @@ describe( "postal.js - subscriptions", function() { name = this.actor; return ( d.season >= 2 && d.season <= 4 ); } ).context( ctxObj ).defer(); - while (i < 8) { + while ( i < 8 ) { postal.publish( { channel: sub.channel, topic: sub.topic, diff --git a/spec/utils.spec.js b/spec/utils.spec.js index c0f68eb8..0b2d188b 100644 --- a/spec/utils.spec.js +++ b/spec/utils.spec.js @@ -10,7 +10,7 @@ describe( "postal.utils", function() { i = 10; var ch1 = postal.channel( "MyChannel" ), ch2 = postal.channel( "MyChannel2" ); - while (i) { + while ( i ) { subs.push( ch1.subscribe( "MyTopic", NO_OP ) ); if ( i % 2 === 0 ) { subs.push( ch2.subscribe( "MyTopic2", NO_OP ) ); @@ -362,7 +362,7 @@ describe( "postal.utils", function() { var err = false; try { postal.noConflict(); - } catch (e) { + } catch ( e ) { err = true; } err.should.be.ok; //jshint ignore:line diff --git a/src/AmqpBindingsResolver.js b/src/AmqpBindingsResolver.js index 2e527171..1db74e8a 100644 --- a/src/AmqpBindingsResolver.js +++ b/src/AmqpBindingsResolver.js @@ -1,5 +1,5 @@ /*jshint -W098 */ -/* global postal, _config */ +/* global postal, _config, _ */ var bindingsResolver = _config.resolver = { cache: {}, diff --git a/src/Api.js b/src/Api.js index c4a7e213..e77692d9 100644 --- a/src/Api.js +++ b/src/Api.js @@ -1,4 +1,4 @@ -/* global ChannelDefinition, SubscriptionDefinition, postal, prevPostal, global, _config */ +/* global ChannelDefinition, SubscriptionDefinition, postal, prevPostal, global, _config, _ */ /*jshint -W020 */ var pubInProgress = 0; @@ -6,7 +6,7 @@ var unSubQueue = []; var autoCompactIndex = 0; function clearUnSubQueue() { - while (unSubQueue.length) { + while ( unSubQueue.length ) { postal.unsubscribe( unSubQueue.shift() ); } } @@ -22,11 +22,15 @@ function getCachePurger( subDef, key, cache ) { }; } -function getCacher( topic, cache, cacheKey, done, envelope ) { +function getCacher( topic, pubCache, cacheKey, done, envelope ) { var headers = envelope && envelope.headers || {}; return function( subDef ) { + var cache; if ( _config.resolver.compare( subDef.topic, topic, headers ) ) { - cache.push( subDef ); + if ( !headers.resolverNoCache ) { + cache = pubCache[ cacheKey ] = ( pubCache[ cacheKey ] || [] ); + cache.push( subDef ); + } subDef.cacheKeys.push( cacheKey ); if ( done ) { done( subDef ); @@ -59,16 +63,16 @@ function getPredicate( options, resolver ) { }; } else { return function( sub ) { - var compared = 0, - matched = 0; + var compared = 0; + var matched = 0; _.each( options, function( val, prop ) { compared += 1; if ( // We use the bindings resolver to compare the options.topic to subDef.topic - ( prop === "topic" && resolver.compare( sub.topic, options.topic, { resolverNoCache: true } ) ) - || ( prop === "context" && options.context === sub._context ) + ( prop === "topic" && resolver.compare( sub.topic, options.topic, { resolverNoCache: true } ) ) || + ( prop === "context" && options.context === sub._context ) || // Any other potential prop/value matching outside topic & context... - || ( sub[ prop ] === options[ prop ] ) ) { + ( sub[ prop ] === options[ prop ] ) ) { matched += 1; } } ); @@ -135,11 +139,11 @@ _.extend( postal, { var skipped = 0; var activated = 0; if ( !cache ) { - cache = this.cache[ cacheKey ] = []; var cacherFn = getCacher( topic, - cache, - cacheKey, function( candidate ) { + this.cache, + cacheKey, + function( candidate ) { if ( candidate.invokeSubscriber( envelope.data, envelope ) ) { activated++; } else { @@ -175,6 +179,7 @@ _.extend( postal, { this.unsubscribeFor(); _config.resolver.reset(); this.subscriptions = {}; + this.cache = {}; }, subscribe: function subscribe( options ) { @@ -215,7 +220,7 @@ _.extend( postal, { var channelSubs; var topicSubs; var idx; - for (; unSubIdx < unSubLen; unSubIdx++) { + for ( ; unSubIdx < unSubLen; unSubIdx++ ) { subDef = arguments[ unSubIdx ]; subDef.inactive = true; if ( pubInProgress ) { @@ -229,7 +234,7 @@ _.extend( postal, { var len = topicSubs.length; idx = 0; // remove SubscriptionDefinition from channel list - while (idx < len) { + while ( idx < len ) { /* istanbul ignore else */ if ( topicSubs[ idx ] === subDef ) { topicSubs.splice( idx, 1 ); @@ -246,7 +251,7 @@ _.extend( postal, { // remove SubscriptionDefinition from postal cache if ( subDef.cacheKeys && subDef.cacheKeys.length ) { var key; - while (key = subDef.cacheKeys.pop()) { + while ( key = subDef.cacheKeys.pop() ) { _.each( this.cache[ key ], getCachePurger( subDef, key, this.cache ) ); } } diff --git a/src/ChannelDefinition.js b/src/ChannelDefinition.js index e6fdea6a..d4f7cbf3 100644 --- a/src/ChannelDefinition.js +++ b/src/ChannelDefinition.js @@ -1,4 +1,4 @@ -/* global _postal, SubscriptionDefinition, _config */ +/* global _postal, SubscriptionDefinition, _config, _ */ var ChannelDefinition = function( channelName, bus ) { this.bus = bus; diff --git a/src/SubscriptionDefinition.js b/src/SubscriptionDefinition.js index 59dde378..10ec8726 100644 --- a/src/SubscriptionDefinition.js +++ b/src/SubscriptionDefinition.js @@ -1,4 +1,4 @@ -/* global postal */ +/* global postal, _ */ var SubscriptionDefinition = function( channel, topic, callback ) { if ( arguments.length !== 3 ) { throw new Error( "You must provide a channel, topic and callback when creating a SubscriptionDefinition instance." ); @@ -18,7 +18,7 @@ var ConsecutiveDistinctPredicate = function() { var previous; return function( data ) { var eq = false; - if ( typeof data == 'string' ) { + if ( typeof data === "string" ) { eq = data === previous; previous = data; } else { @@ -49,7 +49,7 @@ SubscriptionDefinition.prototype = { var safeCallback = function() { try { original.apply( this, arguments ); - } catch (err) { + } catch ( err ) { errorHandler( err, arguments[ 0 ] ); } }; @@ -62,7 +62,7 @@ SubscriptionDefinition.prototype = { }, disposeAfter: function disposeAfter( maxCalls ) { - if ( typeof maxCalls != 'number' || maxCalls <= 0 ) { + if ( typeof maxCalls !== "number" || maxCalls <= 0 ) { throw new Error( "The value provided to disposeAfter (maxCalls) must be a number greater than zero." ); } var self = this; @@ -121,7 +121,7 @@ SubscriptionDefinition.prototype = { } else { report = console.log; } - this[ "catch" ]( report ); + this.catch( report ); } return this; }, @@ -143,7 +143,7 @@ SubscriptionDefinition.prototype = { }, constraint: function constraint( predicate ) { - if ( typeof predicate != 'function' ) { + if ( typeof predicate !== "function" ) { throw new Error( "Predicate constraint must be a function" ); } this.pipeline.push( function( data, env, next ) { @@ -169,7 +169,7 @@ SubscriptionDefinition.prototype = { }, debounce: function debounce( milliseconds, immediate ) { - if ( typeof milliseconds != 'number' ) { + if ( typeof milliseconds !== "number" ) { throw new Error( "Milliseconds must be a number" ); } this.pipeline.push( @@ -184,7 +184,7 @@ SubscriptionDefinition.prototype = { }, delay: function delay( milliseconds ) { - if ( typeof milliseconds != 'number' ) { + if ( typeof milliseconds !== "number" ) { throw new Error( "Milliseconds must be a number" ); } var self = this; @@ -197,7 +197,7 @@ SubscriptionDefinition.prototype = { }, throttle: function throttle( milliseconds ) { - if ( typeof milliseconds != 'number' ) { + if ( typeof milliseconds !== "number" ) { throw new Error( "Milliseconds must be a number" ); } var fn = function( data, env, next ) { @@ -225,7 +225,7 @@ function warnOnDeprecation( oldMethod, newMethod ) { } var oldMethods = [ "withConstraint", "withConstraints", "withContext", "withDebounce", "withDelay", "withThrottle" ]; var newMethods = [ "constraint", "constraints", "context", "debounce", "delay", "throttle" ]; -for (var i = 0; i < 6; i++) { +for ( var i = 0; i < 6; i++ ) { var oldMethod = oldMethods[ i ]; SubscriptionDefinition.prototype[ oldMethod ] = warnOnDeprecation( oldMethod, newMethods[ i ] ); } diff --git a/src/mindash.js b/src/mindash.js index 30686254..6113ac83 100644 --- a/src/mindash.js +++ b/src/mindash.js @@ -1,17 +1,17 @@ -var createPartialWrapper = require( 'lodash/internal/createPartialWrapper' ); +var createPartialWrapper = require( "lodash/internal/createPartialWrapper" ); var _ = { - after: require( 'lodash/function/after' ), - any: require( 'lodash/internal/arraySome' ), + after: require( "lodash/function/after" ), + any: require( "lodash/internal/arraySome" ), bind: function( func, thisArg, arg ) { return createPartialWrapper( func, 33, thisArg, [ arg ] ); }, - debounce: require( 'lodash/function/debounce' ), - each: require( 'lodash/internal/baseEach' ), - extend: require( 'lodash/internal/baseAssign' ), - filter: require( 'lodash/internal/arrayFilter' ), - isEqual: require( 'lodash/lang/isEqual' ), - keys: require( 'lodash/object/keys' ), - map: require( 'lodash/internal/arrayMap' ), - throttle: require( 'lodash/function/throttle' ) + debounce: require( "lodash/function/debounce" ), + each: require( "lodash/internal/baseEach" ), + extend: require( "lodash/internal/baseAssign" ), + filter: require( "lodash/internal/arrayFilter" ), + isEqual: require( "lodash/lang/isEqual" ), + keys: require( "lodash/object/keys" ), + map: require( "lodash/internal/arrayMap" ), + throttle: require( "lodash/function/throttle" ) }; diff --git a/src/postal.js b/src/postal.js index b5cc0fb0..b343b06d 100644 --- a/src/postal.js +++ b/src/postal.js @@ -1,5 +1,5 @@ /*jshint -W098 */ -(function( root, factory ) { +( function( root, factory ) { /* istanbul ignore if */ if ( typeof define === "function" && define.amd ) { // AMD. Register as an anonymous module. @@ -15,7 +15,6 @@ root.postal = factory( root._, root ); } }( this, function( _, global, undefined ) { - var prevPostal = global.postal; var _defaultConfig = { DEFAULT_CHANNEL: "/", @@ -36,11 +35,11 @@ /*jshint -W106 */ if ( global && Object.prototype.hasOwnProperty.call( global, "__postalReady__" ) && _.isArray( global.__postalReady__ ) ) { - while (global.__postalReady__.length) { + while ( global.__postalReady__.length ) { global.__postalReady__.shift().onReady( postal ); } } /*jshint +W106 */ return postal; -} )); +} ) ); diff --git a/src/postal.lodash.js b/src/postal.lodash.js index 51f24ae7..e1fe1779 100644 --- a/src/postal.lodash.js +++ b/src/postal.lodash.js @@ -1,5 +1,6 @@ /*jshint -W098 */ -(function( root, factory ) { +/* global _ */ +( function( root, factory ) { //import("mindash.js"); /* istanbul ignore if */ @@ -17,7 +18,6 @@ root.postal = factory( _, root ); } }( this, function( _, global, undefined ) { - var prevPostal = global.postal; var _defaultConfig = { DEFAULT_CHANNEL: "/", @@ -38,11 +38,11 @@ /*jshint -W106 */ if ( global && Object.prototype.hasOwnProperty.call( global, "__postalReady__" ) && _.isArray( global.__postalReady__ ) ) { - while (global.__postalReady__.length) { + while ( global.__postalReady__.length ) { global.__postalReady__.shift().onReady( postal ); } } /*jshint +W106 */ return postal; -} )); +} ) );