From 7647d6b21e1ebff3c88983fce057fae130aa2dde Mon Sep 17 00:00:00 2001 From: ifandelse Date: Wed, 29 Jan 2014 02:25:51 -0500 Subject: [PATCH] Updated Conduit code, slimmed down basic version --- lib/basic/postal.basic.js | 98 +------- lib/basic/postal.basic.min.js | 2 +- lib/postal.js | 228 +++++++++--------- lib/postal.min.js | 2 +- lib/strategies-add-on/postal.strategies.js | 27 ++- .../postal.strategies.min.js | 2 +- spec/basic.html | 1 - spec/postaljs.spec.js | 19 +- spec/postaljs.strategies.spec.js | 14 +- spec/subscriptionDefinition.spec.js | 13 - src/Api.js | 9 +- src/ChannelDefinition.js | 12 +- src/SubscriptionDefinition.js | 9 +- src/conduit.js | 75 ++++++ src/postal.basic.js | 1 - src/postal.js | 4 +- src/strategies.js | 31 ++- src/strategy.js | 70 ------ 18 files changed, 269 insertions(+), 348 deletions(-) create mode 100644 src/conduit.js delete mode 100644 src/strategy.js diff --git a/lib/basic/postal.basic.js b/lib/basic/postal.basic.js index 140bf4e..2687953 100644 --- a/lib/basic/postal.basic.js +++ b/lib/basic/postal.basic.js @@ -21,80 +21,17 @@ }(this, function (_, global, undefined) { var _postal; var prevPostal = global.postal; - var Strategy = function (options) { - var _target = options.owner[options.prop]; - if (typeof _target !== "function") { - throw new Error("Strategies can only target methods."); - } - var _strategies = []; - var _context = options.context || options.owner; - var strategy = function () { - var idx = 0; - var next = function next() { - var args = Array.prototype.slice.call(arguments, 0); - var thisIdx = idx; - var strategy; - idx += 1; - if (thisIdx < _strategies.length) { - strategy = _strategies[thisIdx]; - strategy.fn.apply(strategy.context || _context, [next].concat(args)); - } else { - _target.apply(_context, args); - } - }; - next.apply(this, arguments); - }; - strategy.target = function () { - return _target; - }; - strategy.context = function (ctx) { - if (arguments.length === 0) { - return _context; - } else { - _context = ctx; - } - }; - strategy.strategies = function () { - return _strategies; - }; - // TODO: add option to shift or push - strategy.useStrategy = function (strategy) { - var idx = 0, - exists = false; - while (idx < _strategies.length) { - if (_strategies[idx].name === strategy.name) { - _strategies[idx] = strategy; - exists = true; - break; - } - idx += 1; - } - if (!exists) { - _strategies.push(strategy); - } - }; - strategy.reset = function () { - _strategies = []; - }; - if (options.lazyInit) { - _target.useStrategy = function () { - options.owner[options.prop] = strategy; - strategy.useStrategy.apply(strategy, arguments); - }; - _target.context = function () { - options.owner[options.prop] = strategy; - return strategy.context.apply(strategy, arguments); - }; - return _target; - } else { - return strategy; - } - }; var ChannelDefinition = function (channelName) { this.channel = channelName || _postal.configuration.DEFAULT_CHANNEL; + this.initialize(); }; + ChannelDefinition.prototype.initialize = function () {}; ChannelDefinition.prototype.subscribe = function () { - return _postal.subscribe(arguments.length === 1 ? new SubscriptionDefinition(this.channel, arguments[0].topic, arguments[0].callback) : new SubscriptionDefinition(this.channel, arguments[0], arguments[1])); + return _postal.subscribe({ + channel: this.channel, + topic: (arguments.length === 1 ? arguments[0].topic : arguments[0]), + callback: (arguments.length === 1 ? arguments[0].callback : arguments[1]) + }); }; ChannelDefinition.prototype.publish = function () { var envelope = arguments.length === 1 ? (Object.prototype.toString.call(arguments[0]) === "[object String]" ? { @@ -104,7 +41,7 @@ data: arguments[1] }; envelope.channel = this.channel; - return _postal.publish(envelope); + _postal.publish(envelope); }; var SubscriptionDefinition = function (channel, topic, callback) { if (arguments.length !== 3) { @@ -124,20 +61,12 @@ _postal.unsubscribe(this); } }, - // Move strat optimization here.... subscribe: function (callback) { this.callback = callback; - this.callback = new Strategy({ - owner: this, - prop: "callback", - context: this, - // TODO: is this the best option? - lazyInit: true - }); return this; }, withContext: function (context) { - this.callback.context(context); + this.context = context; return this; } }; @@ -178,13 +107,7 @@ }; var fireSub = function (subDef, envelope) { if (!subDef.inactive && _postal.configuration.resolver.compare(subDef.topic, envelope.topic)) { - if (_.all(subDef.constraints, function (constraint) { - return constraint.call(subDef.context, envelope.data, envelope); - })) { - if (typeof subDef.callback === "function") { - subDef.callback.call(subDef.context, envelope.data, envelope); - } - } + subDef.callback.call(subDef.context || this, envelope.data, envelope); } }; var pubInProgress = 0; @@ -252,7 +175,6 @@ if (--pubInProgress === 0) { clearUnSubQueue(); } - return envelope; }, unsubscribe: function (subDef) { if (pubInProgress) { diff --git a/lib/basic/postal.basic.min.js b/lib/basic/postal.basic.min.js index d85fa27..1f72797 100644 --- a/lib/basic/postal.basic.min.js +++ b/lib/basic/postal.basic.min.js @@ -5,4 +5,4 @@ * Url: http://github.com/postaljs/postal.js * License(s): MIT, GPL */ -(function(n,t){"object"==typeof module&&module.exports?module.exports=t(require("underscore"),this):"function"==typeof define&&define.amd?define(["underscore"],function(i){return t(i,n)}):n.postal=t(n._,n)})(this,function(n,t){var i,e=t.postal,c=function(n){var t=n.owner[n.prop];if("function"!=typeof t)throw new Error("Strategies can only target methods.");var i=[],e=n.context||n.owner,c=function(){var n=0,c=function r(){var c,s=Array.prototype.slice.call(arguments,0),o=n;n+=1,oe;)(i=n[e++])&&a(i,t)}),0===--u&&p(),t},unsubscribe:function(n){if(u)return void h.push(n);if(this.subscriptions[n.channel]&&this.subscriptions[n.channel][n.topic])for(var t=this.subscriptions[n.channel][n.topic].length,i=0;t>i;){if(this.subscriptions[n.channel][n.topic][i]===n){this.subscriptions[n.channel][n.topic].splice(i,1);break}i+=1}this.publish({channel:this.configuration.SYSTEM_CHANNEL,topic:"subscription.removed",data:{event:"subscription.removed",channel:n.channel,topic:n.topic}})},addWireTap:function(n){var t=this;return t.wireTaps.push(n),function(){var i=t.wireTaps.indexOf(n);-1!==i&&t.wireTaps.splice(i,1)}},linkChannels:function(t,i){var e=[],c=this;return t=n.isArray(t)?t:[t],i=n.isArray(i)?i:[i],n.each(t,function(t){var r=t.topic||"#";n.each(i,function(i){var s=i.channel||c.configuration.DEFAULT_CHANNEL;e.push(c.subscribe({channel:t.channel||c.configuration.DEFAULT_CHANNEL,topic:r,callback:function(t,e){var r=n.clone(e);r.topic=n.isFunction(i.topic)?i.topic(e.topic):i.topic||e.topic,r.channel=s,r.data=t,c.publish(r)}}))})}),e},noConflict:function(){if("undefined"==typeof window)throw new Error("noConflict can only be used in browser clients which aren't using AMD modules");return t.postal=e,this},getSubscribersFor:function(){var n=arguments[0],t=arguments[1];return 1===arguments.length&&(n=arguments[0].channel||this.configuration.DEFAULT_CHANNEL,t=arguments[0].topic),this.subscriptions[n]&&Object.prototype.hasOwnProperty.call(this.subscriptions[n],t)?this.subscriptions[n][t]:[]},reset:function(){this.subscriptions&&(n.each(this.subscriptions,function(t){n.each(t,function(n){for(;n.length;)n.pop().unsubscribe()})}),this.subscriptions={}),this.configuration.resolver.reset()}},i.subscriptions[i.configuration.SYSTEM_CHANNEL]={},t&&Object.prototype.hasOwnProperty.call(t,"__postalReady__")&&n.isArray(t.__postalReady__))for(;t.__postalReady__.length;)t.__postalReady__.shift().onReady(i);return i}); \ No newline at end of file +(function(n,t){"object"==typeof module&&module.exports?module.exports=t(require("underscore"),this):"function"==typeof define&&define.amd?define(["underscore"],function(i){return t(i,n)}):n.postal=t(n._,n)})(this,function(n,t){var i,e=t.postal,s=function(n){this.channel=n||i.configuration.DEFAULT_CHANNEL,this.initialize()};s.prototype.initialize=function(){},s.prototype.subscribe=function(){return i.subscribe({channel:this.channel,topic:1===arguments.length?arguments[0].topic:arguments[0],callback:1===arguments.length?arguments[0].callback:arguments[1]})},s.prototype.publish=function(){var n=1===arguments.length?"[object String]"===Object.prototype.toString.call(arguments[0])?{topic:arguments[0]}:arguments[0]:{topic:arguments[0],data:arguments[1]};n.channel=this.channel,i.publish(n)};var c=function(n,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=n,this.topic=t,this.subscribe(i)};c.prototype={unsubscribe:function(){this.inactive||(this.inactive=!0,i.unsubscribe(this))},subscribe:function(n){return this.callback=n,this},withContext:function(n){return this.context=n,this}};var o={cache:{},regex:{},compare:function(t,i){var e,s,c,o=this.cache[i]&&this.cache[i][t];return"undefined"!=typeof o?o:((s=this.regex[t])||(e="^"+n.map(t.split("."),function(n){var t="";return c&&(t="#"!==c?"\\.\\b":"\\b"),t+="#"===n?"[\\s\\S]*":"*"===n?"[^.]+":n,c=n,t}).join("")+"$",s=this.regex[t]=new RegExp(e)),this.cache[i]=this.cache[i]||{},this.cache[i][t]=o=s.test(i),o)},reset:function(){this.cache={},this.regex={}}},r=function(n,t){!n.inactive&&i.configuration.resolver.compare(n.topic,t.topic)&&n.callback.call(n.context||this,t.data,t)},a=0,u=[],h=function(){for(;u.length;)i.unsubscribe(u.shift())};if(i={configuration:{resolver:o,DEFAULT_CHANNEL:"/",SYSTEM_CHANNEL:"postal"},subscriptions:{},wireTaps:[],ChannelDefinition:s,SubscriptionDefinition:c,channel:function(n){return new s(n)},subscribe:function(n){var t,i=new c(n.channel||this.configuration.DEFAULT_CHANNEL,n.topic,n.callback),e=this.subscriptions[i.channel];return this.publish({channel:this.configuration.SYSTEM_CHANNEL,topic:"subscription.created",data:{event:"subscription.created",channel:i.channel,topic:i.topic}}),e||(e=this.subscriptions[i.channel]={}),t=this.subscriptions[i.channel][i.topic],t||(t=this.subscriptions[i.channel][i.topic]=[]),t.push(i),i},publish:function(t){++a,t.channel=t.channel||this.configuration.DEFAULT_CHANNEL,t.timeStamp=new Date,n.each(this.wireTaps,function(n){n(t.data,t)}),this.subscriptions[t.channel]&&n.each(this.subscriptions[t.channel],function(n){for(var i,e=0,s=n.length;s>e;)(i=n[e++])&&r(i,t)}),0===--a&&h()},unsubscribe:function(n){if(a)return void u.push(n);if(this.subscriptions[n.channel]&&this.subscriptions[n.channel][n.topic])for(var t=this.subscriptions[n.channel][n.topic].length,i=0;t>i;){if(this.subscriptions[n.channel][n.topic][i]===n){this.subscriptions[n.channel][n.topic].splice(i,1);break}i+=1}this.publish({channel:this.configuration.SYSTEM_CHANNEL,topic:"subscription.removed",data:{event:"subscription.removed",channel:n.channel,topic:n.topic}})},addWireTap:function(n){var t=this;return t.wireTaps.push(n),function(){var i=t.wireTaps.indexOf(n);-1!==i&&t.wireTaps.splice(i,1)}},linkChannels:function(t,i){var e=[],s=this;return t=n.isArray(t)?t:[t],i=n.isArray(i)?i:[i],n.each(t,function(t){var c=t.topic||"#";n.each(i,function(i){var o=i.channel||s.configuration.DEFAULT_CHANNEL;e.push(s.subscribe({channel:t.channel||s.configuration.DEFAULT_CHANNEL,topic:c,callback:function(t,e){var c=n.clone(e);c.topic=n.isFunction(i.topic)?i.topic(e.topic):i.topic||e.topic,c.channel=o,c.data=t,s.publish(c)}}))})}),e},noConflict:function(){if("undefined"==typeof window)throw new Error("noConflict can only be used in browser clients which aren't using AMD modules");return t.postal=e,this},getSubscribersFor:function(){var n=arguments[0],t=arguments[1];return 1===arguments.length&&(n=arguments[0].channel||this.configuration.DEFAULT_CHANNEL,t=arguments[0].topic),this.subscriptions[n]&&Object.prototype.hasOwnProperty.call(this.subscriptions[n],t)?this.subscriptions[n][t]:[]},reset:function(){this.subscriptions&&(n.each(this.subscriptions,function(t){n.each(t,function(n){for(;n.length;)n.pop().unsubscribe()})}),this.subscriptions={}),this.configuration.resolver.reset()}},i.subscriptions[i.configuration.SYSTEM_CHANNEL]={},t&&Object.prototype.hasOwnProperty.call(t,"__postalReady__")&&n.isArray(t.__postalReady__))for(;t.__postalReady__.length;)t.__postalReady__.shift().onReady(i);return i}); \ No newline at end of file diff --git a/lib/postal.js b/lib/postal.js index 43dba8a..f05f396 100644 --- a/lib/postal.js +++ b/lib/postal.js @@ -21,6 +21,107 @@ }(this, function (_, global, undefined) { var _postal; var prevPostal = global.postal; + var Conduit = function (options) { + if (typeof options.target !== "function") { + throw new Error("You can only make functions into Conduits."); + } + var _steps = { + pre: options.pre || [], + post: options.post || [], + all: [] + }; + var _defaultContext = options.context; + var _targetStep = { + isTarget: true, + fn: function (next) { + var args = Array.prototype.slice.call(arguments, 1); + options.target.apply(_defaultContext, args); + next.apply(this, args); + } + }; + var _genPipeline = function () { + _steps.all = _steps.pre.concat([_targetStep].concat(_steps.post)); + }; + _genPipeline(); + var conduit = function () { + var idx = 0; + var next = function next() { + var args = Array.prototype.slice.call(arguments, 0); + var thisIdx = idx; + var step; + idx += 1; + if (thisIdx < _steps.all.length) { + step = _steps.all[thisIdx]; + step.fn.apply(step.context || _defaultContext, [next].concat(args)); + } + }; + next.apply(this, arguments); + }; + conduit.steps = function () { + return _steps.all; + }; + conduit.context = function (ctx) { + if (arguments.length === 0) { + return _defaultContext; + } else { + _defaultContext = ctx; + } + }; + conduit.before = function (step, options) { + step = typeof step === "function" ? { + fn: step + } : step; + options = options || {}; + if (options.prepend) { + _steps.pre.unshift(step); + } else { + _steps.pre.push(step); + } + _genPipeline(); + }; + conduit.after = function (step, options) { + step = typeof step === "function" ? { + fn: step + } : step; + options = options || {}; + if (options.prepend) { + _steps.post.unshift(step); + } else { + _steps.post.push(step); + } + _genPipeline(); + }; + conduit.clear = function () { + _steps = { + pre: [], + post: [], + all: [] + }; + }; + return conduit; + }; + var ChannelDefinition = function (channelName) { + this.channel = channelName || _postal.configuration.DEFAULT_CHANNEL; + this.initialize(); + }; + ChannelDefinition.prototype.initialize = function () {}; + ChannelDefinition.prototype.subscribe = function () { + return _postal.subscribe({ + channel: this.channel, + topic: (arguments.length === 1 ? arguments[0].topic : arguments[0]), + callback: (arguments.length === 1 ? arguments[0].callback : arguments[1]) + }); + }; + ChannelDefinition.prototype.publish = function () { + var envelope = arguments.length === 1 ? (Object.prototype.toString.call(arguments[0]) === "[object String]" ? { + topic: arguments[0] + } : arguments[0]) : { + topic: arguments[0], + data: arguments[1] + }; + envelope.channel = this.channel; + _postal.publish(envelope); + }; 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."); @@ -39,92 +140,15 @@ _postal.unsubscribe(this); } }, - // Move strat optimization here.... subscribe: function (callback) { this.callback = callback; - this.callback = new Strategy({ - owner: this, - prop: "callback", - context: this, - // TODO: is this the best option? - lazyInit: true - }); return this; }, withContext: function (context) { - this.callback.context(context); + this.context = context; return this; } }; - var Strategy = function (options) { - var _target = options.owner[options.prop]; - if (typeof _target !== "function") { - throw new Error("Strategies can only target methods."); - } - var _strategies = []; - var _context = options.context || options.owner; - var strategy = function () { - var idx = 0; - var next = function next() { - var args = Array.prototype.slice.call(arguments, 0); - var thisIdx = idx; - var strategy; - idx += 1; - if (thisIdx < _strategies.length) { - strategy = _strategies[thisIdx]; - strategy.fn.apply(strategy.context || _context, [next].concat(args)); - } else { - _target.apply(_context, args); - } - }; - next.apply(this, arguments); - }; - strategy.target = function () { - return _target; - }; - strategy.context = function (ctx) { - if (arguments.length === 0) { - return _context; - } else { - _context = ctx; - } - }; - strategy.strategies = function () { - return _strategies; - }; - // TODO: add option to shift or push - strategy.useStrategy = function (strategy) { - var idx = 0, - exists = false; - while (idx < _strategies.length) { - if (_strategies[idx].name === strategy.name) { - _strategies[idx] = strategy; - exists = true; - break; - } - idx += 1; - } - if (!exists) { - _strategies.push(strategy); - } - }; - strategy.reset = function () { - _strategies = []; - }; - if (options.lazyInit) { - _target.useStrategy = function () { - options.owner[options.prop] = strategy; - strategy.useStrategy.apply(strategy, arguments); - }; - _target.context = function () { - options.owner[options.prop] = strategy; - return strategy.context.apply(strategy, arguments); - }; - return _target; - } else { - return strategy; - } - }; var ConsecutiveDistinctPredicate = function () { var previous; return function (data) { @@ -237,22 +261,22 @@ } }; SubscriptionDefinition.prototype.defer = function () { - this.callback.useStrategy(strats.defer()); + this.callback.before(strats.defer()); return this; }; SubscriptionDefinition.prototype.disposeAfter = function (maxCalls) { var self = this; - self.callback.useStrategy(strats.stopAfter(maxCalls, function () { + self.callback.before(strats.stopAfter(maxCalls, function () { self.unsubscribe.call(self); })); return self; }; SubscriptionDefinition.prototype.distinctUntilChanged = function () { - this.callback.useStrategy(strats.distinct()); + this.callback.before(strats.distinct()); return this; }; SubscriptionDefinition.prototype.distinct = function () { - this.callback.useStrategy(strats.distinct({ + this.callback.before(strats.distinct({ all: true })); return this; @@ -262,36 +286,31 @@ return this; }; SubscriptionDefinition.prototype.withConstraint = function (predicate) { - this.callback.useStrategy(strats.withConstraint(predicate)); + this.callback.before(strats.withConstraint(predicate)); return this; }; SubscriptionDefinition.prototype.withDebounce = function (milliseconds, immediate) { - this.callback.useStrategy(strats.withDebounce(milliseconds, immediate)); + this.callback.before(strats.withDebounce(milliseconds, immediate)); return this; }; SubscriptionDefinition.prototype.withDelay = function (milliseconds) { - this.callback.useStrategy(strats.withDelay(milliseconds)); + this.callback.before(strats.withDelay(milliseconds)); return this; }; SubscriptionDefinition.prototype.withThrottle = function (milliseconds) { - this.callback.useStrategy(strats.withThrottle(milliseconds)); + this.callback.before(strats.withThrottle(milliseconds)); return this; }; - var ChannelDefinition = function (channelName) { - this.channel = channelName || _postal.configuration.DEFAULT_CHANNEL; + SubscriptionDefinition.prototype.subscribe = function (callback) { + this.callback = new Conduit({ + target: callback, + context: this + }); + return this; }; - ChannelDefinition.prototype.subscribe = function () { - return _postal.subscribe(arguments.length === 1 ? new SubscriptionDefinition(this.channel, arguments[0].topic, arguments[0].callback) : new SubscriptionDefinition(this.channel, arguments[0], arguments[1])); - }; - ChannelDefinition.prototype.publish = function () { - var envelope = arguments.length === 1 ? (Object.prototype.toString.call(arguments[0]) === "[object String]" ? { - topic: arguments[0] - } : arguments[0]) : { - topic: arguments[0], - data: arguments[1] - }; - envelope.channel = this.channel; - return _postal.publish(envelope); + SubscriptionDefinition.prototype.withContext = function (context) { + this.callback.context(context); + return this; }; var bindingsResolver = { cache: {}, @@ -330,13 +349,7 @@ }; var fireSub = function (subDef, envelope) { if (!subDef.inactive && _postal.configuration.resolver.compare(subDef.topic, envelope.topic)) { - if (_.all(subDef.constraints, function (constraint) { - return constraint.call(subDef.context, envelope.data, envelope); - })) { - if (typeof subDef.callback === "function") { - subDef.callback.call(subDef.context, envelope.data, envelope); - } - } + subDef.callback.call(subDef.context || this, envelope.data, envelope); } }; var pubInProgress = 0; @@ -404,7 +417,6 @@ if (--pubInProgress === 0) { clearUnSubQueue(); } - return envelope; }, unsubscribe: function (subDef) { if (pubInProgress) { diff --git a/lib/postal.min.js b/lib/postal.min.js index 5924d89..8fb8fa3 100644 --- a/lib/postal.min.js +++ b/lib/postal.min.js @@ -5,4 +5,4 @@ * Url: http://github.com/postaljs/postal.js * License(s): MIT, GPL */ -(function(t,n){"object"==typeof module&&module.exports?module.exports=n(require("underscore"),this):"function"==typeof define&&define.amd?define(["underscore"],function(i){return n(i,t)}):t.postal=n(t._,t)})(this,function(t,n){var i,e=n.postal,r=function(t,n,i){if(3!==arguments.length)throw new Error("You must provide a channel, topic and callback when creating a SubscriptionDefinition instance.");if(0===n.length)throw new Error("Topics cannot be empty");this.channel=t,this.topic=n,this.subscribe(i)};r.prototype={unsubscribe:function(){this.inactive||(this.inactive=!0,i.unsubscribe(this))},subscribe:function(t){return this.callback=t,this.callback=new o({owner:this,prop:"callback",context:this,lazyInit:!0}),this},withContext:function(t){return this.callback.context(t),this}};var o=function(t){var n=t.owner[t.prop];if("function"!=typeof n)throw new Error("Strategies can only target methods.");var i=[],e=t.context||t.owner,r=function(){var t=0,r=function o(){var r,c=Array.prototype.slice.call(arguments,0),s=t;t+=1,s=n)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var e=t.after(n,i);return{name:"stopAfter",fn:function(t,n,i){e(),t(n,i)}}},withThrottle:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";return{name:"withThrottle",fn:t.throttle(function(t,n,i){t(n,i)},n)}},withDebounce:function(n,i){if(t.isNaN(n))throw"Milliseconds must be a number";return{name:"debounce",fn:t.debounce(function(t,n,i){t(n,i)},n,!!i)}},withConstraint:function(n){if(!t.isFunction(n))throw"Predicate constraint must be a function";return{name:"withConstraint",fn:function(t,i,e){n.call(this,i,e)&&t.call(this,i,e)}}},distinct:function(t){t=t||{};var n=function(t){return t[0]},i=t.all?new s(n):new c(n);return{name:"distinct",fn:function(t,n,e){i(n)&&t(n,e)}}}};r.prototype.defer=function(){return this.callback.useStrategy(a.defer()),this},r.prototype.disposeAfter=function(t){var n=this;return n.callback.useStrategy(a.stopAfter(t,function(){n.unsubscribe.call(n)})),n},r.prototype.distinctUntilChanged=function(){return this.callback.useStrategy(a.distinct()),this},r.prototype.distinct=function(){return this.callback.useStrategy(a.distinct({all:!0})),this},r.prototype.once=function(){return this.disposeAfter(1),this},r.prototype.withConstraint=function(t){return this.callback.useStrategy(a.withConstraint(t)),this},r.prototype.withDebounce=function(t,n){return this.callback.useStrategy(a.withDebounce(t,n)),this},r.prototype.withDelay=function(t){return this.callback.useStrategy(a.withDelay(t)),this},r.prototype.withThrottle=function(t){return this.callback.useStrategy(a.withThrottle(t)),this};var u=function(t){this.channel=t||i.configuration.DEFAULT_CHANNEL};u.prototype.subscribe=function(){return i.subscribe(1===arguments.length?new r(this.channel,arguments[0].topic,arguments[0].callback):new r(this.channel,arguments[0],arguments[1]))},u.prototype.publish=function(){var t=1===arguments.length?"[object String]"===Object.prototype.toString.call(arguments[0])?{topic:arguments[0]}:arguments[0]:{topic:arguments[0],data:arguments[1]};return t.channel=this.channel,i.publish(t)};var h={cache:{},regex:{},compare:function(n,i){var e,r,o,c=this.cache[i]&&this.cache[i][n];return"undefined"!=typeof c?c:((r=this.regex[n])||(e="^"+t.map(n.split("."),function(t){var n="";return o&&(n="#"!==o?"\\.\\b":"\\b"),n+="#"===t?"[\\s\\S]*":"*"===t?"[^.]+":t,o=t,n}).join("")+"$",r=this.regex[n]=new RegExp(e)),this.cache[i]=this.cache[i]||{},this.cache[i][n]=c=r.test(i),c)},reset:function(){this.cache={},this.regex={}}},l=function(n,e){!n.inactive&&i.configuration.resolver.compare(n.topic,e.topic)&&t.all(n.constraints,function(t){return t.call(n.context,e.data,e)})&&"function"==typeof n.callback&&n.callback.call(n.context,e.data,e)},p=0,f=[],b=function(){for(;f.length;)i.unsubscribe(f.shift())};if(i={configuration:{resolver:h,DEFAULT_CHANNEL:"/",SYSTEM_CHANNEL:"postal"},subscriptions:{},wireTaps:[],ChannelDefinition:u,SubscriptionDefinition:r,channel:function(t){return new u(t)},subscribe:function(t){var n,i=new r(t.channel||this.configuration.DEFAULT_CHANNEL,t.topic,t.callback),e=this.subscriptions[i.channel];return this.publish({channel:this.configuration.SYSTEM_CHANNEL,topic:"subscription.created",data:{event:"subscription.created",channel:i.channel,topic:i.topic}}),e||(e=this.subscriptions[i.channel]={}),n=this.subscriptions[i.channel][i.topic],n||(n=this.subscriptions[i.channel][i.topic]=[]),n.push(i),i},publish:function(n){return++p,n.channel=n.channel||this.configuration.DEFAULT_CHANNEL,n.timeStamp=new Date,t.each(this.wireTaps,function(t){t(n.data,n)}),this.subscriptions[n.channel]&&t.each(this.subscriptions[n.channel],function(t){for(var i,e=0,r=t.length;r>e;)(i=t[e++])&&l(i,n)}),0===--p&&b(),n},unsubscribe:function(t){if(p)return void f.push(t);if(this.subscriptions[t.channel]&&this.subscriptions[t.channel][t.topic])for(var n=this.subscriptions[t.channel][t.topic].length,i=0;n>i;){if(this.subscriptions[t.channel][t.topic][i]===t){this.subscriptions[t.channel][t.topic].splice(i,1);break}i+=1}this.publish({channel:this.configuration.SYSTEM_CHANNEL,topic:"subscription.removed",data:{event:"subscription.removed",channel:t.channel,topic:t.topic}})},addWireTap:function(t){var n=this;return n.wireTaps.push(t),function(){var i=n.wireTaps.indexOf(t);-1!==i&&n.wireTaps.splice(i,1)}},linkChannels:function(n,i){var e=[],r=this;return n=t.isArray(n)?n:[n],i=t.isArray(i)?i:[i],t.each(n,function(n){var o=n.topic||"#";t.each(i,function(i){var c=i.channel||r.configuration.DEFAULT_CHANNEL;e.push(r.subscribe({channel:n.channel||r.configuration.DEFAULT_CHANNEL,topic:o,callback:function(n,e){var o=t.clone(e);o.topic=t.isFunction(i.topic)?i.topic(e.topic):i.topic||e.topic,o.channel=c,o.data=n,r.publish(o)}}))})}),e},noConflict:function(){if("undefined"==typeof window)throw new Error("noConflict can only be used in browser clients which aren't using AMD modules");return n.postal=e,this},getSubscribersFor:function(){var t=arguments[0],n=arguments[1];return 1===arguments.length&&(t=arguments[0].channel||this.configuration.DEFAULT_CHANNEL,n=arguments[0].topic),this.subscriptions[t]&&Object.prototype.hasOwnProperty.call(this.subscriptions[t],n)?this.subscriptions[t][n]:[]},reset:function(){this.subscriptions&&(t.each(this.subscriptions,function(n){t.each(n,function(t){for(;t.length;)t.pop().unsubscribe()})}),this.subscriptions={}),this.configuration.resolver.reset()}},i.subscriptions[i.configuration.SYSTEM_CHANNEL]={},n&&Object.prototype.hasOwnProperty.call(n,"__postalReady__")&&t.isArray(n.__postalReady__))for(;n.__postalReady__.length;)n.__postalReady__.shift().onReady(i);return i}); \ No newline at end of file +(function(t,n){"object"==typeof module&&module.exports?module.exports=n(require("underscore"),this):"function"==typeof define&&define.amd?define(["underscore"],function(i){return n(i,t)}):t.postal=n(t._,t)})(this,function(t,n){var i,e=n.postal,r=function(t){if("function"!=typeof t.target)throw new Error("You can only make functions into Conduits.");var n={pre:t.pre||[],post:t.post||[],all:[]},i=t.context,e={isTarget:!0,fn:function(n){var e=Array.prototype.slice.call(arguments,1);t.target.apply(i,e),n.apply(this,e)}},r=function(){n.all=n.pre.concat([e].concat(n.post))};r();var o=function(){var t=0,e=function r(){var e,o=Array.prototype.slice.call(arguments,0),c=t;t+=1,c=n)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var e=t.after(n,i);return{name:"stopAfter",fn:function(t,n,i){e(),t(n,i)}}},withThrottle:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";return{name:"withThrottle",fn:t.throttle(function(t,n,i){t(n,i)},n)}},withDebounce:function(n,i){if(t.isNaN(n))throw"Milliseconds must be a number";return{name:"debounce",fn:t.debounce(function(t,n,i){t(n,i)},n,!!i)}},withConstraint:function(n){if(!t.isFunction(n))throw"Predicate constraint must be a function";return{name:"withConstraint",fn:function(t,i,e){n.call(this,i,e)&&t.call(this,i,e)}}},distinct:function(t){t=t||{};var n=function(t){return t[0]},i=t.all?new a(n):new s(n);return{name:"distinct",fn:function(t,n,e){i(n)&&t(n,e)}}}};c.prototype.defer=function(){return this.callback.before(u.defer()),this},c.prototype.disposeAfter=function(t){var n=this;return n.callback.before(u.stopAfter(t,function(){n.unsubscribe.call(n)})),n},c.prototype.distinctUntilChanged=function(){return this.callback.before(u.distinct()),this},c.prototype.distinct=function(){return this.callback.before(u.distinct({all:!0})),this},c.prototype.once=function(){return this.disposeAfter(1),this},c.prototype.withConstraint=function(t){return this.callback.before(u.withConstraint(t)),this},c.prototype.withDebounce=function(t,n){return this.callback.before(u.withDebounce(t,n)),this},c.prototype.withDelay=function(t){return this.callback.before(u.withDelay(t)),this},c.prototype.withThrottle=function(t){return this.callback.before(u.withThrottle(t)),this},c.prototype.subscribe=function(t){return this.callback=new r({target:t,context:this}),this},c.prototype.withContext=function(t){return this.callback.context(t),this};var h={cache:{},regex:{},compare:function(n,i){var e,r,o,c=this.cache[i]&&this.cache[i][n];return"undefined"!=typeof c?c:((r=this.regex[n])||(e="^"+t.map(n.split("."),function(t){var n="";return o&&(n="#"!==o?"\\.\\b":"\\b"),n+="#"===t?"[\\s\\S]*":"*"===t?"[^.]+":t,o=t,n}).join("")+"$",r=this.regex[n]=new RegExp(e)),this.cache[i]=this.cache[i]||{},this.cache[i][n]=c=r.test(i),c)},reset:function(){this.cache={},this.regex={}}},l=function(t,n){!t.inactive&&i.configuration.resolver.compare(t.topic,n.topic)&&t.callback.call(t.context||this,n.data,n)},p=0,f=[],b=function(){for(;f.length;)i.unsubscribe(f.shift())};if(i={configuration:{resolver:h,DEFAULT_CHANNEL:"/",SYSTEM_CHANNEL:"postal"},subscriptions:{},wireTaps:[],ChannelDefinition:o,SubscriptionDefinition:c,channel:function(t){return new o(t)},subscribe:function(t){var n,i=new c(t.channel||this.configuration.DEFAULT_CHANNEL,t.topic,t.callback),e=this.subscriptions[i.channel];return this.publish({channel:this.configuration.SYSTEM_CHANNEL,topic:"subscription.created",data:{event:"subscription.created",channel:i.channel,topic:i.topic}}),e||(e=this.subscriptions[i.channel]={}),n=this.subscriptions[i.channel][i.topic],n||(n=this.subscriptions[i.channel][i.topic]=[]),n.push(i),i},publish:function(n){++p,n.channel=n.channel||this.configuration.DEFAULT_CHANNEL,n.timeStamp=new Date,t.each(this.wireTaps,function(t){t(n.data,n)}),this.subscriptions[n.channel]&&t.each(this.subscriptions[n.channel],function(t){for(var i,e=0,r=t.length;r>e;)(i=t[e++])&&l(i,n)}),0===--p&&b()},unsubscribe:function(t){if(p)return void f.push(t);if(this.subscriptions[t.channel]&&this.subscriptions[t.channel][t.topic])for(var n=this.subscriptions[t.channel][t.topic].length,i=0;n>i;){if(this.subscriptions[t.channel][t.topic][i]===t){this.subscriptions[t.channel][t.topic].splice(i,1);break}i+=1}this.publish({channel:this.configuration.SYSTEM_CHANNEL,topic:"subscription.removed",data:{event:"subscription.removed",channel:t.channel,topic:t.topic}})},addWireTap:function(t){var n=this;return n.wireTaps.push(t),function(){var i=n.wireTaps.indexOf(t);-1!==i&&n.wireTaps.splice(i,1)}},linkChannels:function(n,i){var e=[],r=this;return n=t.isArray(n)?n:[n],i=t.isArray(i)?i:[i],t.each(n,function(n){var o=n.topic||"#";t.each(i,function(i){var c=i.channel||r.configuration.DEFAULT_CHANNEL;e.push(r.subscribe({channel:n.channel||r.configuration.DEFAULT_CHANNEL,topic:o,callback:function(n,e){var o=t.clone(e);o.topic=t.isFunction(i.topic)?i.topic(e.topic):i.topic||e.topic,o.channel=c,o.data=n,r.publish(o)}}))})}),e},noConflict:function(){if("undefined"==typeof window)throw new Error("noConflict can only be used in browser clients which aren't using AMD modules");return n.postal=e,this},getSubscribersFor:function(){var t=arguments[0],n=arguments[1];return 1===arguments.length&&(t=arguments[0].channel||this.configuration.DEFAULT_CHANNEL,n=arguments[0].topic),this.subscriptions[t]&&Object.prototype.hasOwnProperty.call(this.subscriptions[t],n)?this.subscriptions[t][n]:[]},reset:function(){this.subscriptions&&(t.each(this.subscriptions,function(n){t.each(n,function(t){for(;t.length;)t.pop().unsubscribe()})}),this.subscriptions={}),this.configuration.resolver.reset()}},i.subscriptions[i.configuration.SYSTEM_CHANNEL]={},n&&Object.prototype.hasOwnProperty.call(n,"__postalReady__")&&t.isArray(n.__postalReady__))for(;n.__postalReady__.length;)n.__postalReady__.shift().onReady(i);return i}); \ No newline at end of file diff --git a/lib/strategies-add-on/postal.strategies.js b/lib/strategies-add-on/postal.strategies.js index 994ce8c..6fba75b 100644 --- a/lib/strategies-add-on/postal.strategies.js +++ b/lib/strategies-add-on/postal.strategies.js @@ -134,22 +134,22 @@ } }; SubscriptionDefinition.prototype.defer = function () { - this.callback.useStrategy(strats.defer()); + this.callback.before(strats.defer()); return this; }; SubscriptionDefinition.prototype.disposeAfter = function (maxCalls) { var self = this; - self.callback.useStrategy(strats.stopAfter(maxCalls, function () { + self.callback.before(strats.stopAfter(maxCalls, function () { self.unsubscribe.call(self); })); return self; }; SubscriptionDefinition.prototype.distinctUntilChanged = function () { - this.callback.useStrategy(strats.distinct()); + this.callback.before(strats.distinct()); return this; }; SubscriptionDefinition.prototype.distinct = function () { - this.callback.useStrategy(strats.distinct({ + this.callback.before(strats.distinct({ all: true })); return this; @@ -159,19 +159,30 @@ return this; }; SubscriptionDefinition.prototype.withConstraint = function (predicate) { - this.callback.useStrategy(strats.withConstraint(predicate)); + this.callback.before(strats.withConstraint(predicate)); return this; }; SubscriptionDefinition.prototype.withDebounce = function (milliseconds, immediate) { - this.callback.useStrategy(strats.withDebounce(milliseconds, immediate)); + this.callback.before(strats.withDebounce(milliseconds, immediate)); return this; }; SubscriptionDefinition.prototype.withDelay = function (milliseconds) { - this.callback.useStrategy(strats.withDelay(milliseconds)); + this.callback.before(strats.withDelay(milliseconds)); return this; }; SubscriptionDefinition.prototype.withThrottle = function (milliseconds) { - this.callback.useStrategy(strats.withThrottle(milliseconds)); + this.callback.before(strats.withThrottle(milliseconds)); + return this; + }; + SubscriptionDefinition.prototype.subscribe = function (callback) { + this.callback = new Conduit({ + target: callback, + context: this + }); + return this; + }; + SubscriptionDefinition.prototype.withContext = function (context) { + this.callback.context(context); return this; }; }(postal.SubscriptionDefinition)); diff --git a/lib/strategies-add-on/postal.strategies.min.js b/lib/strategies-add-on/postal.strategies.min.js index 2b76575..6c6980c 100644 --- a/lib/strategies-add-on/postal.strategies.min.js +++ b/lib/strategies-add-on/postal.strategies.min.js @@ -5,4 +5,4 @@ * Url: http://github.com/postaljs/postal.js * License(s): MIT, GPL */ -(function(t,n){"object"==typeof module&&module.exports?module.exports=function(t){return n(t,this)}:"function"==typeof define&&define.amd?define(["postal"],function(e){return n(e,t)}):t.postal=n(t.postal,t)})(this,function(t){return function(t){var n=function(){var t;return function(n){var e=!1;return _.isString(n)?(e=n===t,t=n):(e=_.isEqual(n,t),t=_.clone(n)),!e}},e=function(){var t=[];return function(n){var e=!_.any(t,function(t){return _.isObject(n)||_.isArray(n)?_.isEqual(n,t):n===t});return e&&t.push(n),e}},i={withDelay:function(t){if(_.isNaN(t))throw"Milliseconds must be a number";return{name:"withDelay",fn:function(n,e,i){setTimeout(function(){n(e,i)},t)}}},defer:function(){return this.withDelay(0)},stopAfter:function(t,n){if(_.isNaN(t)||0>=t)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var e=_.after(t,n);return{name:"stopAfter",fn:function(t,n,i){e(),t(n,i)}}},withThrottle:function(t){if(_.isNaN(t))throw"Milliseconds must be a number";return{name:"withThrottle",fn:_.throttle(function(t,n,e){t(n,e)},t)}},withDebounce:function(t,n){if(_.isNaN(t))throw"Milliseconds must be a number";return{name:"debounce",fn:_.debounce(function(t,n,e){t(n,e)},t,!!n)}},withConstraint:function(t){if(!_.isFunction(t))throw"Predicate constraint must be a function";return{name:"withConstraint",fn:function(n,e,i){t.call(this,e,i)&&n.call(this,e,i)}}},distinct:function(t){t=t||{};var i=function(t){return t[0]},r=t.all?new e(i):new n(i);return{name:"distinct",fn:function(t,n,e){r(n)&&t(n,e)}}}};t.prototype.defer=function(){return this.callback.useStrategy(i.defer()),this},t.prototype.disposeAfter=function(t){var n=this;return n.callback.useStrategy(i.stopAfter(t,function(){n.unsubscribe.call(n)})),n},t.prototype.distinctUntilChanged=function(){return this.callback.useStrategy(i.distinct()),this},t.prototype.distinct=function(){return this.callback.useStrategy(i.distinct({all:!0})),this},t.prototype.once=function(){return this.disposeAfter(1),this},t.prototype.withConstraint=function(t){return this.callback.useStrategy(i.withConstraint(t)),this},t.prototype.withDebounce=function(t,n){return this.callback.useStrategy(i.withDebounce(t,n)),this},t.prototype.withDelay=function(t){return this.callback.useStrategy(i.withDelay(t)),this},t.prototype.withThrottle=function(t){return this.callback.useStrategy(i.withThrottle(t)),this}}(t.SubscriptionDefinition),t}); \ No newline at end of file +(function(t,n){"object"==typeof module&&module.exports?module.exports=function(t){return n(t,this)}:"function"==typeof define&&define.amd?define(["postal"],function(e){return n(e,t)}):t.postal=n(t.postal,t)})(this,function(t){return function(t){var n=function(){var t;return function(n){var e=!1;return _.isString(n)?(e=n===t,t=n):(e=_.isEqual(n,t),t=_.clone(n)),!e}},e=function(){var t=[];return function(n){var e=!_.any(t,function(t){return _.isObject(n)||_.isArray(n)?_.isEqual(n,t):n===t});return e&&t.push(n),e}},i={withDelay:function(t){if(_.isNaN(t))throw"Milliseconds must be a number";return{name:"withDelay",fn:function(n,e,i){setTimeout(function(){n(e,i)},t)}}},defer:function(){return this.withDelay(0)},stopAfter:function(t,n){if(_.isNaN(t)||0>=t)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var e=_.after(t,n);return{name:"stopAfter",fn:function(t,n,i){e(),t(n,i)}}},withThrottle:function(t){if(_.isNaN(t))throw"Milliseconds must be a number";return{name:"withThrottle",fn:_.throttle(function(t,n,e){t(n,e)},t)}},withDebounce:function(t,n){if(_.isNaN(t))throw"Milliseconds must be a number";return{name:"debounce",fn:_.debounce(function(t,n,e){t(n,e)},t,!!n)}},withConstraint:function(t){if(!_.isFunction(t))throw"Predicate constraint must be a function";return{name:"withConstraint",fn:function(n,e,i){t.call(this,e,i)&&n.call(this,e,i)}}},distinct:function(t){t=t||{};var i=function(t){return t[0]},r=t.all?new e(i):new n(i);return{name:"distinct",fn:function(t,n,e){r(n)&&t(n,e)}}}};t.prototype.defer=function(){return this.callback.before(i.defer()),this},t.prototype.disposeAfter=function(t){var n=this;return n.callback.before(i.stopAfter(t,function(){n.unsubscribe.call(n)})),n},t.prototype.distinctUntilChanged=function(){return this.callback.before(i.distinct()),this},t.prototype.distinct=function(){return this.callback.before(i.distinct({all:!0})),this},t.prototype.once=function(){return this.disposeAfter(1),this},t.prototype.withConstraint=function(t){return this.callback.before(i.withConstraint(t)),this},t.prototype.withDebounce=function(t,n){return this.callback.before(i.withDebounce(t,n)),this},t.prototype.withDelay=function(t){return this.callback.before(i.withDelay(t)),this},t.prototype.withThrottle=function(t){return this.callback.before(i.withThrottle(t)),this},t.prototype.subscribe=function(t){return this.callback=new Conduit({target:t,context:this}),this},t.prototype.withContext=function(t){return this.callback.context(t),this}}(t.SubscriptionDefinition),t}); \ No newline at end of file diff --git a/spec/basic.html b/spec/basic.html index 00d6e69..a258525 100644 --- a/spec/basic.html +++ b/spec/basic.html @@ -18,7 +18,6 @@ mocha.setup({ ui: 'bdd', timeout: 60000 }); - diff --git a/spec/postaljs.spec.js b/spec/postaljs.spec.js index 0134fc1..256ef41 100644 --- a/spec/postaljs.spec.js +++ b/spec/postaljs.spec.js @@ -63,9 +63,6 @@ it( "should have set subscription topic value", function () { expect( sub.topic ).to.be( "MyTopic" ); } ); - it( "should have defaulted the subscription context value", function () { - expect( sub.callback.context() ).to.be( sub ); - } ); it( "should have captured subscription creation event", function () { expect( caughtSubscribeEvent ).to.be.ok(); } ); @@ -162,8 +159,7 @@ channel = postal.channel( "ContextChannel" ); subscription = channel.subscribe( "MyTopic", function ( data ) { this.increment(); - } ) - .withContext( obj ); + }).withContext( obj ); channel.publish( "MyTopic", "Testing123" ); } ); after( function () { @@ -201,9 +197,6 @@ it( "should have set subscription topic value", function () { expect( sub.topic ).to.be( "MyTopic" ); } ); - it( "should have defaulted the subscription context value", function () { - expect( sub.callback.context() ).to.be( sub ); - } ); } ); }); @@ -231,16 +224,6 @@ expect( msgData ).to.be( "Testing123" ); } ); } ); - describe( "When publishing on a channel where no subscribers exist", function () { - it( "should return expected results for MyChannel/MyTopic", function () { - var env = postal.publish( { - channel : "NoOneIsUsingThisOne", - topic : "This.Is.A.Lonely.Topic", - data : "Y U NO SUBSCRIBE TO ME?" - } ); - expect( !_.isEmpty( env ) ).to.be( true ); - } ); - } ); describe( "When using global publish api", function () { var msgReceivedCnt = 0, msgData; diff --git a/spec/postaljs.strategies.spec.js b/spec/postaljs.strategies.spec.js index 92a0006..2dc78f1 100644 --- a/spec/postaljs.strategies.spec.js +++ b/spec/postaljs.strategies.spec.js @@ -9,7 +9,7 @@ var caughtSubscribeEvent = false; var caughtUnsubscribeEvent = false; - describe("Subscription Creation - Strategies", function(){ + describe("Subscription Creation - Pipeline Steps", function(){ describe( "When subscribing and ignoring duplicates", function () { var subInvokedCnt = 0; before( function () { @@ -186,10 +186,10 @@ recvd = true; } ) .withConstraint(function () { - return false; + return true; }) .withConstraint(function () { - return false; + return true; }) .withConstraint(function () { return true; @@ -200,8 +200,8 @@ postal.reset(); recvd = false; } ); - it( "should overwrite constraint with last one passed in", function () { - expect( subscription.callback.strategies().length ).to.be( 1 ); + it( "should show all 4 constraints added", function () { + expect( subscription.callback.steps().length ).to.be( 4 ); } ); it( "should have invoked the callback", function () { expect( recvd ).to.be.ok(); @@ -224,7 +224,7 @@ recvd = false; } ); it( "should have a constraint on the subscription", function () { - expect( subscription.callback.strategies()[0].name ).to.be( "withConstraint" ); + expect( subscription.callback.steps()[0].name ).to.be( "withConstraint" ); } ); it( "should not have invoked the subscription callback", function () { expect( recvd ).to.not.be.ok(); @@ -247,7 +247,7 @@ recvd = false; } ); it( "should have a constraint on the subscription", function () { - expect( subscription.callback.strategies()[0].name ).to.be( "withConstraint" ); + expect( subscription.callback.steps()[0].name ).to.be( "withConstraint" ); } ); it( "should have invoked the subscription callback", function () { expect( recvd ).to.be.ok(); diff --git a/spec/subscriptionDefinition.spec.js b/spec/subscriptionDefinition.spec.js index 12cd4ef..1938c71 100644 --- a/spec/subscriptionDefinition.spec.js +++ b/spec/subscriptionDefinition.spec.js @@ -19,9 +19,6 @@ it( "should set the topic to SubDefTestTopic", function () { expect( sDef.topic ).to.be( "SubDefTestTopic" ); } ); - it( "should set the callback", function () { - expect( sDef.callback ).to.be( NO_OP ); - } ); it( "should default the context", function () { expect( sDef.context ).to.be( undefined ); } ); @@ -45,15 +42,5 @@ expect( name ).to.be( "Rose" ); } ); } ); - - describe( "When calling subscribe to set the callback", function () { - var sDefe = new SubscriptionDefinition( "TestChannel", "TestTopic", NO_OP ), - fn = function () {}; - sDefe.subscribe( fn ); - - it( "Should set the callback", function () { - expect( sDefe.callback ).to.be( fn ); - } ); - } ); } ); }()); \ No newline at end of file diff --git a/src/Api.js b/src/Api.js index ebc741a..5cd638d 100644 --- a/src/Api.js +++ b/src/Api.js @@ -2,13 +2,7 @@ /*jshint -W020 */ var fireSub = function ( subDef, envelope ) { if ( !subDef.inactive && _postal.configuration.resolver.compare( subDef.topic, envelope.topic ) ) { - if ( _.all( subDef.constraints, function ( constraint ) { - return constraint.call( subDef.context, envelope.data, envelope ); - } ) ) { - if ( typeof subDef.callback === "function" ) { - subDef.callback.call( subDef.context, envelope.data, envelope ); - } - } + subDef.callback.call( subDef.context || this, envelope.data, envelope ); } }; var pubInProgress = 0; @@ -78,7 +72,6 @@ _postal = { if ( --pubInProgress === 0 ) { clearUnSubQueue(); } - return envelope; }, unsubscribe: function( subDef ) { diff --git a/src/ChannelDefinition.js b/src/ChannelDefinition.js index cfc2968..82f7ead 100644 --- a/src/ChannelDefinition.js +++ b/src/ChannelDefinition.js @@ -1,12 +1,16 @@ /* global _postal, SubscriptionDefinition */ var ChannelDefinition = function ( channelName ) { this.channel = channelName || _postal.configuration.DEFAULT_CHANNEL; + this.initialize(); }; +ChannelDefinition.prototype.initialize = function() {}; ChannelDefinition.prototype.subscribe = function () { - return _postal.subscribe(arguments.length === 1 ? - new SubscriptionDefinition( this.channel, arguments[0].topic, arguments[0].callback ) : - new SubscriptionDefinition( this.channel, arguments[0], arguments[1] )); + return _postal.subscribe({ + channel: this.channel, + topic: (arguments.length === 1 ? arguments[0].topic : arguments[0]), + callback: (arguments.length === 1 ? arguments[0].callback : arguments[1]) + }); }; ChannelDefinition.prototype.publish = function () { @@ -16,5 +20,5 @@ ChannelDefinition.prototype.publish = function () { arguments[0] ) : { topic : arguments[0], data : arguments[1] }; envelope.channel = this.channel; - return _postal.publish( envelope ); + _postal.publish( envelope ); }; \ No newline at end of file diff --git a/src/SubscriptionDefinition.js b/src/SubscriptionDefinition.js index d9511f7..364e565 100644 --- a/src/SubscriptionDefinition.js +++ b/src/SubscriptionDefinition.js @@ -20,20 +20,13 @@ SubscriptionDefinition.prototype = { } }, - // Move strat optimization here.... subscribe : function ( callback ) { this.callback = callback; - this.callback = new Strategy({ - owner : this, - prop : "callback", - context : this, // TODO: is this the best option? - lazyInit : true - }); return this; }, withContext : function ( context ) { - this.callback.context(context); + this.context = context; return this; } }; diff --git a/src/conduit.js b/src/conduit.js new file mode 100644 index 0000000..9bb4f63 --- /dev/null +++ b/src/conduit.js @@ -0,0 +1,75 @@ +var Conduit = function( options ) { + if ( typeof options.target !== "function" ) { + throw new Error( "You can only make functions into Conduits." ); + } + var _steps = { + pre : options.pre || [], + post: options.post || [], + all : [] + }; + var _defaultContext = options.context; + var _targetStep = { + isTarget: true, + fn: function(next) { + var args = Array.prototype.slice.call( arguments, 1 ); + options.target.apply( _defaultContext, args); + next.apply(this, args); + } + }; + var _genPipeline = function() { + _steps.all = _steps.pre.concat([_targetStep].concat(_steps.post)); + }; + _genPipeline(); + var conduit = function() { + var idx = 0; + var next = function next() { + var args = Array.prototype.slice.call( arguments, 0 ); + var thisIdx = idx; + var step; + idx += 1; + if (thisIdx < _steps.all.length ) { + step = _steps.all[thisIdx]; + step.fn.apply( step.context || _defaultContext, [next].concat( args ) ); + } + }; + next.apply( this, arguments ); + }; + conduit.steps = function() { + return _steps.all; + }; + conduit.context = function( ctx ) { + if ( arguments.length === 0 ) { + return _defaultContext; + } else { + _defaultContext = ctx; + } + }; + conduit.before = function(step, options) { + step = typeof step === "function" ? { fn: step } : step; + options = options || {}; + if(options.prepend) { + _steps.pre.unshift( step ); + } else { + _steps.pre.push( step ); + } + _genPipeline(); + }; + conduit.after = function(step, options) { + step = typeof step === "function" ? { fn: step } : step; + options = options || {}; + if(options.prepend) { + _steps.post.unshift( step ); + } else { + _steps.post.push( step ); + } + _genPipeline(); + }; + conduit.clear = function() { + _steps = { + pre : [], + post: [], + all : [] + }; + }; + return conduit; +}; \ No newline at end of file diff --git a/src/postal.basic.js b/src/postal.basic.js index b1fcb53..2e4494b 100644 --- a/src/postal.basic.js +++ b/src/postal.basic.js @@ -17,7 +17,6 @@ var _postal; var prevPostal = global.postal; - //import("strategy.js"); //import("ChannelDefinition.js"); //import("SubscriptionDefinition.js"); //import("AmqpBindingsResolver.js"); diff --git a/src/postal.js b/src/postal.js index 72f498a..cbb374f 100644 --- a/src/postal.js +++ b/src/postal.js @@ -17,10 +17,10 @@ var _postal; var prevPostal = global.postal; + //import("conduit.js"); + //import("ChannelDefinition.js"); //import("SubscriptionDefinition.js"); - //import("strategy.js"); //import("strategies.js"); - //import("ChannelDefinition.js"); //import("AmqpBindingsResolver.js"); //import("Api.js"); diff --git a/src/strategies.js b/src/strategies.js index bbcd5cc..7242d6e 100644 --- a/src/strategies.js +++ b/src/strategies.js @@ -1,4 +1,4 @@ -/* global DistinctPredicate,ConsecutiveDistinctPredicate,SubscriptionDefinition */ +/* global DistinctPredicate,ConsecutiveDistinctPredicate,SubscriptionDefinition,Conduit */ /*jshint -W098 */ var ConsecutiveDistinctPredicate = function () { var previous; @@ -117,25 +117,25 @@ var strats = { }; SubscriptionDefinition.prototype.defer = function () { - this.callback.useStrategy(strats.defer()); + this.callback.before(strats.defer()); return this; }; SubscriptionDefinition.prototype.disposeAfter = function ( maxCalls ) { var self = this; - self.callback.useStrategy(strats.stopAfter(maxCalls, function() { + self.callback.before(strats.stopAfter(maxCalls, function() { self.unsubscribe.call(self); })); return self; }; SubscriptionDefinition.prototype.distinctUntilChanged = function () { - this.callback.useStrategy(strats.distinct()); + this.callback.before(strats.distinct()); return this; }; SubscriptionDefinition.prototype.distinct = function () { - this.callback.useStrategy(strats.distinct({ all : true })); + this.callback.before(strats.distinct({ all : true })); return this; }; @@ -145,21 +145,34 @@ SubscriptionDefinition.prototype.once = function () { }; SubscriptionDefinition.prototype.withConstraint = function ( predicate ) { - this.callback.useStrategy(strats.withConstraint(predicate)); + this.callback.before(strats.withConstraint(predicate)); return this; }; SubscriptionDefinition.prototype.withDebounce = function ( milliseconds, immediate ) { - this.callback.useStrategy(strats.withDebounce(milliseconds, immediate)); + this.callback.before(strats.withDebounce(milliseconds, immediate)); return this; }; SubscriptionDefinition.prototype.withDelay = function ( milliseconds ) { - this.callback.useStrategy(strats.withDelay(milliseconds)); + this.callback.before(strats.withDelay(milliseconds)); return this; }; SubscriptionDefinition.prototype.withThrottle = function ( milliseconds ) { - this.callback.useStrategy(strats.withThrottle(milliseconds)); + this.callback.before(strats.withThrottle(milliseconds)); + return this; +}; + +SubscriptionDefinition.prototype.subscribe = function ( callback ) { + this.callback = new Conduit({ + target : callback, + context : this + }); + return this; +}; + +SubscriptionDefinition.prototype.withContext = function ( context ) { + this.callback.context(context); return this; }; \ No newline at end of file diff --git a/src/strategy.js b/src/strategy.js deleted file mode 100644 index a688618..0000000 --- a/src/strategy.js +++ /dev/null @@ -1,70 +0,0 @@ -var Strategy = function( options ) { - var _target = options.owner[options.prop]; - if ( typeof _target !== "function" ) { - throw new Error( "Strategies can only target methods." ); - } - var _strategies = []; - var _context = options.context || options.owner; - var strategy = function() { - var idx = 0; - var next = function next() { - var args = Array.prototype.slice.call( arguments, 0 ); - var thisIdx = idx; - var strategy; - idx += 1; - if ( thisIdx < _strategies.length ) { - strategy = _strategies[thisIdx]; - strategy.fn.apply( strategy.context || _context, [next].concat( args ) ); - } else { - _target.apply( _context, args ); - } - }; - next.apply( this, arguments ); - }; - strategy.target = function() { - return _target; - }; - strategy.context = function( ctx ) { - if ( arguments.length === 0 ) { - return _context; - } else { - _context = ctx; - } - }; - strategy.strategies = function() { - return _strategies; - }; - - // TODO: add option to shift or push - strategy.useStrategy = function( strategy ) { - var idx = 0, - exists = false; - while ( idx < _strategies.length ) { - if ( _strategies[idx].name === strategy.name ) { - _strategies[idx] = strategy; - exists = true; - break; - } - idx += 1; - } - if ( !exists ) { - _strategies.push( strategy ); - } - }; - strategy.reset = function() { - _strategies = []; - }; - if ( options.lazyInit ) { - _target.useStrategy = function() { - options.owner[options.prop] = strategy; - strategy.useStrategy.apply( strategy, arguments ); - }; - _target.context = function() { - options.owner[options.prop] = strategy; - return strategy.context.apply( strategy, arguments ); - }; - return _target; - } else { - return strategy; - } -}; \ No newline at end of file