mirror of
https://github.com/Hopiu/postal.js.git
synced 2026-03-16 22:20:23 +00:00
Initial Tests Passing on Strategies Addition
This commit is contained in:
parent
186c541a37
commit
45cb57e0e5
19 changed files with 712 additions and 333 deletions
|
|
@ -25,10 +25,145 @@
|
|||
|
||||
var 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;
|
||||
};
|
||||
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;
|
||||
}
|
||||
};
|
||||
/* global DistinctPredicate,ConsecutiveDistinctPredicate */
|
||||
var strats = {
|
||||
setTimeout: function(ms) {
|
||||
return {
|
||||
name: "setTimeout",
|
||||
fn: function (next, data, envelope) {
|
||||
setTimeout(function () {
|
||||
next(data, envelope);
|
||||
}, ms);
|
||||
}
|
||||
};
|
||||
},
|
||||
after: function(maxCalls, callback) {
|
||||
var dispose = _.after(maxCalls, callback);
|
||||
return {
|
||||
name: "after",
|
||||
fn: function (next, data, envelope) {
|
||||
dispose();
|
||||
next(data, envelope);
|
||||
}
|
||||
};
|
||||
},
|
||||
throttle : function(ms) {
|
||||
return {
|
||||
name: "throttle",
|
||||
fn: _.throttle(function(next, data, envelope) {
|
||||
next(data, envelope);
|
||||
}, ms)
|
||||
};
|
||||
},
|
||||
debounce: function(ms, immediate) {
|
||||
return {
|
||||
name: "debounce",
|
||||
fn: _.debounce(function(next, data, envelope) {
|
||||
next(data, envelope);
|
||||
}, ms, !!immediate)
|
||||
};
|
||||
},
|
||||
predicate: function(pred) {
|
||||
return {
|
||||
name: "predicate",
|
||||
fn: function(next, data, envelope) {
|
||||
if(pred.call(this, data, envelope)) {
|
||||
next.call(this, data, envelope);
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
distinct : function(options) {
|
||||
options = options || {};
|
||||
var accessor = function(args) {
|
||||
return args[0];
|
||||
};
|
||||
var check = options.all ?
|
||||
new DistinctPredicate(accessor) :
|
||||
new ConsecutiveDistinctPredicate(accessor);
|
||||
return {
|
||||
name : "distinct",
|
||||
fn : function(next, data, envelope) {
|
||||
if(check(data)) {
|
||||
next(data, envelope);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
/*jshint -W098 */
|
||||
var ConsecutiveDistinctPredicate = function () {
|
||||
var ConsecutiveDistinctPredicate = function (argsAccessor) {
|
||||
var previous;
|
||||
return function ( data ) {
|
||||
return function () {
|
||||
var data = argsAccessor(arguments);
|
||||
var eq = false;
|
||||
if ( _.isString( data ) ) {
|
||||
eq = data === previous;
|
||||
|
|
@ -42,10 +177,11 @@
|
|||
};
|
||||
};
|
||||
/*jshint -W098 */
|
||||
var DistinctPredicate = function () {
|
||||
var DistinctPredicate = function (argsAccessor) {
|
||||
var previous = [];
|
||||
|
||||
return function ( data ) {
|
||||
return function () {
|
||||
var data = argsAccessor(arguments);
|
||||
var isDistinct = !_.any( previous, function ( p ) {
|
||||
if ( _.isObject( data ) || _.isArray( data ) ) {
|
||||
return _.isEqual( data, p );
|
||||
|
|
@ -55,7 +191,7 @@
|
|||
if ( isDistinct ) {
|
||||
previous.push( data );
|
||||
}
|
||||
return isDistinct;
|
||||
return isDistinct;
|
||||
};
|
||||
};
|
||||
/* global postal, SubscriptionDefinition */
|
||||
|
|
@ -83,9 +219,7 @@
|
|||
var SubscriptionDefinition = function ( channel, topic, callback ) {
|
||||
this.channel = channel;
|
||||
this.topic = topic;
|
||||
this.callback = callback;
|
||||
this.constraints = [];
|
||||
this.context = null;
|
||||
this.subscribe(callback);
|
||||
postal.configuration.bus.publish( {
|
||||
channel : postal.configuration.SYSTEM_CHANNEL,
|
||||
topic : "subscription.created",
|
||||
|
|
@ -116,13 +250,7 @@
|
|||
},
|
||||
|
||||
defer : function () {
|
||||
var self = this;
|
||||
var fn = this.callback;
|
||||
this.callback = function ( data, env ) {
|
||||
setTimeout( function () {
|
||||
fn.call( self.context, data, env );
|
||||
}, 0 );
|
||||
};
|
||||
this.callback.useStrategy(postal.configuration.strategies.setTimeout(0));
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -130,26 +258,20 @@
|
|||
if ( _.isNaN( maxCalls ) || maxCalls <= 0 ) {
|
||||
throw "The value provided to disposeAfter (maxCalls) must be a number greater than zero.";
|
||||
}
|
||||
var self = this;
|
||||
var fn = this.callback;
|
||||
var dispose = _.after( maxCalls, _.bind( function () {
|
||||
this.unsubscribe();
|
||||
}, this ) );
|
||||
|
||||
this.callback = function () {
|
||||
fn.apply( self.context, arguments );
|
||||
dispose();
|
||||
};
|
||||
return this;
|
||||
var self = this;
|
||||
self.callback.useStrategy(postal.configuration.strategies.after(maxCalls, function() {
|
||||
self.unsubscribe.call(self);
|
||||
}));
|
||||
return self;
|
||||
},
|
||||
|
||||
distinctUntilChanged : function () {
|
||||
this.withConstraint( new ConsecutiveDistinctPredicate() );
|
||||
this.callback.useStrategy(postal.configuration.strategies.distinct());
|
||||
return this;
|
||||
},
|
||||
|
||||
distinct : function () {
|
||||
this.withConstraint( new DistinctPredicate() );
|
||||
this.callback.useStrategy(postal.configuration.strategies.distinct({ all: true }));
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -162,22 +284,12 @@
|
|||
if ( !_.isFunction( predicate ) ) {
|
||||
throw "Predicate constraint must be a function";
|
||||
}
|
||||
this.constraints.push( predicate );
|
||||
this.callback.useStrategy(postal.configuration.strategies.predicate(predicate));
|
||||
return this;
|
||||
},
|
||||
|
||||
withConstraints : function ( predicates ) {
|
||||
var self = this;
|
||||
if ( _.isArray( predicates ) ) {
|
||||
_.each( predicates, function ( predicate ) {
|
||||
self.withConstraint( predicate );
|
||||
} );
|
||||
}
|
||||
return self;
|
||||
},
|
||||
|
||||
withContext : function ( context ) {
|
||||
this.context = context;
|
||||
this.callback.context(context);
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -194,13 +306,7 @@
|
|||
if ( _.isNaN( milliseconds ) ) {
|
||||
throw "Milliseconds must be a number";
|
||||
}
|
||||
var self = this;
|
||||
var fn = this.callback;
|
||||
this.callback = function ( data, env ) {
|
||||
setTimeout( function () {
|
||||
fn.call( self.context, data, env );
|
||||
}, milliseconds );
|
||||
};
|
||||
this.callback.useStrategy(postal.configuration.strategies.setTimeout(milliseconds));
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -208,13 +314,18 @@
|
|||
if ( _.isNaN( milliseconds ) ) {
|
||||
throw "Milliseconds must be a number";
|
||||
}
|
||||
var fn = this.callback;
|
||||
this.callback = _.throttle( fn, milliseconds );
|
||||
this.callback.useStrategy(postal.configuration.strategies.throttle(milliseconds));
|
||||
return this;
|
||||
},
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
|
@ -259,13 +370,7 @@
|
|||
/* global postal */
|
||||
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.callback.context ? subDef.callback.context() : this, envelope.data, envelope );
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -366,7 +471,8 @@
|
|||
bus : localBus,
|
||||
resolver : bindingsResolver,
|
||||
DEFAULT_CHANNEL : "/",
|
||||
SYSTEM_CHANNEL : "postal"
|
||||
SYSTEM_CHANNEL : "postal",
|
||||
strategies : strats
|
||||
},
|
||||
|
||||
ChannelDefinition : ChannelDefinition,
|
||||
|
|
|
|||
2
example/amd/js/libs/postal/postal.min.js
vendored
2
example/amd/js/libs/postal/postal.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -25,10 +25,145 @@
|
|||
|
||||
var 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;
|
||||
};
|
||||
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;
|
||||
}
|
||||
};
|
||||
/* global DistinctPredicate,ConsecutiveDistinctPredicate */
|
||||
var strats = {
|
||||
setTimeout: function(ms) {
|
||||
return {
|
||||
name: "setTimeout",
|
||||
fn: function (next, data, envelope) {
|
||||
setTimeout(function () {
|
||||
next(data, envelope);
|
||||
}, ms);
|
||||
}
|
||||
};
|
||||
},
|
||||
after: function(maxCalls, callback) {
|
||||
var dispose = _.after(maxCalls, callback);
|
||||
return {
|
||||
name: "after",
|
||||
fn: function (next, data, envelope) {
|
||||
dispose();
|
||||
next(data, envelope);
|
||||
}
|
||||
};
|
||||
},
|
||||
throttle : function(ms) {
|
||||
return {
|
||||
name: "throttle",
|
||||
fn: _.throttle(function(next, data, envelope) {
|
||||
next(data, envelope);
|
||||
}, ms)
|
||||
};
|
||||
},
|
||||
debounce: function(ms, immediate) {
|
||||
return {
|
||||
name: "debounce",
|
||||
fn: _.debounce(function(next, data, envelope) {
|
||||
next(data, envelope);
|
||||
}, ms, !!immediate)
|
||||
};
|
||||
},
|
||||
predicate: function(pred) {
|
||||
return {
|
||||
name: "predicate",
|
||||
fn: function(next, data, envelope) {
|
||||
if(pred.call(this, data, envelope)) {
|
||||
next.call(this, data, envelope);
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
distinct : function(options) {
|
||||
options = options || {};
|
||||
var accessor = function(args) {
|
||||
return args[0];
|
||||
};
|
||||
var check = options.all ?
|
||||
new DistinctPredicate(accessor) :
|
||||
new ConsecutiveDistinctPredicate(accessor);
|
||||
return {
|
||||
name : "distinct",
|
||||
fn : function(next, data, envelope) {
|
||||
if(check(data)) {
|
||||
next(data, envelope);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
/*jshint -W098 */
|
||||
var ConsecutiveDistinctPredicate = function () {
|
||||
var ConsecutiveDistinctPredicate = function (argsAccessor) {
|
||||
var previous;
|
||||
return function ( data ) {
|
||||
return function () {
|
||||
var data = argsAccessor(arguments);
|
||||
var eq = false;
|
||||
if ( _.isString( data ) ) {
|
||||
eq = data === previous;
|
||||
|
|
@ -42,10 +177,11 @@
|
|||
};
|
||||
};
|
||||
/*jshint -W098 */
|
||||
var DistinctPredicate = function () {
|
||||
var DistinctPredicate = function (argsAccessor) {
|
||||
var previous = [];
|
||||
|
||||
return function ( data ) {
|
||||
return function () {
|
||||
var data = argsAccessor(arguments);
|
||||
var isDistinct = !_.any( previous, function ( p ) {
|
||||
if ( _.isObject( data ) || _.isArray( data ) ) {
|
||||
return _.isEqual( data, p );
|
||||
|
|
@ -55,7 +191,7 @@
|
|||
if ( isDistinct ) {
|
||||
previous.push( data );
|
||||
}
|
||||
return isDistinct;
|
||||
return isDistinct;
|
||||
};
|
||||
};
|
||||
/* global postal, SubscriptionDefinition */
|
||||
|
|
@ -83,9 +219,7 @@
|
|||
var SubscriptionDefinition = function ( channel, topic, callback ) {
|
||||
this.channel = channel;
|
||||
this.topic = topic;
|
||||
this.callback = callback;
|
||||
this.constraints = [];
|
||||
this.context = null;
|
||||
this.subscribe(callback);
|
||||
postal.configuration.bus.publish( {
|
||||
channel : postal.configuration.SYSTEM_CHANNEL,
|
||||
topic : "subscription.created",
|
||||
|
|
@ -116,13 +250,7 @@
|
|||
},
|
||||
|
||||
defer : function () {
|
||||
var self = this;
|
||||
var fn = this.callback;
|
||||
this.callback = function ( data, env ) {
|
||||
setTimeout( function () {
|
||||
fn.call( self.context, data, env );
|
||||
}, 0 );
|
||||
};
|
||||
this.callback.useStrategy(postal.configuration.strategies.setTimeout(0));
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -130,26 +258,20 @@
|
|||
if ( _.isNaN( maxCalls ) || maxCalls <= 0 ) {
|
||||
throw "The value provided to disposeAfter (maxCalls) must be a number greater than zero.";
|
||||
}
|
||||
var self = this;
|
||||
var fn = this.callback;
|
||||
var dispose = _.after( maxCalls, _.bind( function () {
|
||||
this.unsubscribe();
|
||||
}, this ) );
|
||||
|
||||
this.callback = function () {
|
||||
fn.apply( self.context, arguments );
|
||||
dispose();
|
||||
};
|
||||
return this;
|
||||
var self = this;
|
||||
self.callback.useStrategy(postal.configuration.strategies.after(maxCalls, function() {
|
||||
self.unsubscribe.call(self);
|
||||
}));
|
||||
return self;
|
||||
},
|
||||
|
||||
distinctUntilChanged : function () {
|
||||
this.withConstraint( new ConsecutiveDistinctPredicate() );
|
||||
this.callback.useStrategy(postal.configuration.strategies.distinct());
|
||||
return this;
|
||||
},
|
||||
|
||||
distinct : function () {
|
||||
this.withConstraint( new DistinctPredicate() );
|
||||
this.callback.useStrategy(postal.configuration.strategies.distinct({ all: true }));
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -162,22 +284,12 @@
|
|||
if ( !_.isFunction( predicate ) ) {
|
||||
throw "Predicate constraint must be a function";
|
||||
}
|
||||
this.constraints.push( predicate );
|
||||
this.callback.useStrategy(postal.configuration.strategies.predicate(predicate));
|
||||
return this;
|
||||
},
|
||||
|
||||
withConstraints : function ( predicates ) {
|
||||
var self = this;
|
||||
if ( _.isArray( predicates ) ) {
|
||||
_.each( predicates, function ( predicate ) {
|
||||
self.withConstraint( predicate );
|
||||
} );
|
||||
}
|
||||
return self;
|
||||
},
|
||||
|
||||
withContext : function ( context ) {
|
||||
this.context = context;
|
||||
this.callback.context(context);
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -194,13 +306,7 @@
|
|||
if ( _.isNaN( milliseconds ) ) {
|
||||
throw "Milliseconds must be a number";
|
||||
}
|
||||
var self = this;
|
||||
var fn = this.callback;
|
||||
this.callback = function ( data, env ) {
|
||||
setTimeout( function () {
|
||||
fn.call( self.context, data, env );
|
||||
}, milliseconds );
|
||||
};
|
||||
this.callback.useStrategy(postal.configuration.strategies.setTimeout(milliseconds));
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -208,13 +314,18 @@
|
|||
if ( _.isNaN( milliseconds ) ) {
|
||||
throw "Milliseconds must be a number";
|
||||
}
|
||||
var fn = this.callback;
|
||||
this.callback = _.throttle( fn, milliseconds );
|
||||
this.callback.useStrategy(postal.configuration.strategies.throttle(milliseconds));
|
||||
return this;
|
||||
},
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
|
@ -259,13 +370,7 @@
|
|||
/* global postal */
|
||||
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.callback.context ? subDef.callback.context() : this, envelope.data, envelope );
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -366,7 +471,8 @@
|
|||
bus : localBus,
|
||||
resolver : bindingsResolver,
|
||||
DEFAULT_CHANNEL : "/",
|
||||
SYSTEM_CHANNEL : "postal"
|
||||
SYSTEM_CHANNEL : "postal",
|
||||
strategies : strats
|
||||
},
|
||||
|
||||
ChannelDefinition : ChannelDefinition,
|
||||
|
|
|
|||
2
example/standard/js/postal.min.js
vendored
2
example/standard/js/postal.min.js
vendored
File diff suppressed because one or more lines are too long
220
lib/postal.js
220
lib/postal.js
|
|
@ -25,10 +25,145 @@
|
|||
|
||||
var 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;
|
||||
};
|
||||
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;
|
||||
}
|
||||
};
|
||||
/* global DistinctPredicate,ConsecutiveDistinctPredicate */
|
||||
var strats = {
|
||||
setTimeout: function(ms) {
|
||||
return {
|
||||
name: "setTimeout",
|
||||
fn: function (next, data, envelope) {
|
||||
setTimeout(function () {
|
||||
next(data, envelope);
|
||||
}, ms);
|
||||
}
|
||||
};
|
||||
},
|
||||
after: function(maxCalls, callback) {
|
||||
var dispose = _.after(maxCalls, callback);
|
||||
return {
|
||||
name: "after",
|
||||
fn: function (next, data, envelope) {
|
||||
dispose();
|
||||
next(data, envelope);
|
||||
}
|
||||
};
|
||||
},
|
||||
throttle : function(ms) {
|
||||
return {
|
||||
name: "throttle",
|
||||
fn: _.throttle(function(next, data, envelope) {
|
||||
next(data, envelope);
|
||||
}, ms)
|
||||
};
|
||||
},
|
||||
debounce: function(ms, immediate) {
|
||||
return {
|
||||
name: "debounce",
|
||||
fn: _.debounce(function(next, data, envelope) {
|
||||
next(data, envelope);
|
||||
}, ms, !!immediate)
|
||||
};
|
||||
},
|
||||
predicate: function(pred) {
|
||||
return {
|
||||
name: "predicate",
|
||||
fn: function(next, data, envelope) {
|
||||
if(pred.call(this, data, envelope)) {
|
||||
next.call(this, data, envelope);
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
distinct : function(options) {
|
||||
options = options || {};
|
||||
var accessor = function(args) {
|
||||
return args[0];
|
||||
};
|
||||
var check = options.all ?
|
||||
new DistinctPredicate(accessor) :
|
||||
new ConsecutiveDistinctPredicate(accessor);
|
||||
return {
|
||||
name : "distinct",
|
||||
fn : function(next, data, envelope) {
|
||||
if(check(data)) {
|
||||
next(data, envelope);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
/*jshint -W098 */
|
||||
var ConsecutiveDistinctPredicate = function () {
|
||||
var ConsecutiveDistinctPredicate = function (argsAccessor) {
|
||||
var previous;
|
||||
return function ( data ) {
|
||||
return function () {
|
||||
var data = argsAccessor(arguments);
|
||||
var eq = false;
|
||||
if ( _.isString( data ) ) {
|
||||
eq = data === previous;
|
||||
|
|
@ -42,10 +177,11 @@
|
|||
};
|
||||
};
|
||||
/*jshint -W098 */
|
||||
var DistinctPredicate = function () {
|
||||
var DistinctPredicate = function (argsAccessor) {
|
||||
var previous = [];
|
||||
|
||||
return function ( data ) {
|
||||
return function () {
|
||||
var data = argsAccessor(arguments);
|
||||
var isDistinct = !_.any( previous, function ( p ) {
|
||||
if ( _.isObject( data ) || _.isArray( data ) ) {
|
||||
return _.isEqual( data, p );
|
||||
|
|
@ -55,7 +191,7 @@
|
|||
if ( isDistinct ) {
|
||||
previous.push( data );
|
||||
}
|
||||
return isDistinct;
|
||||
return isDistinct;
|
||||
};
|
||||
};
|
||||
/* global postal, SubscriptionDefinition */
|
||||
|
|
@ -83,9 +219,7 @@
|
|||
var SubscriptionDefinition = function ( channel, topic, callback ) {
|
||||
this.channel = channel;
|
||||
this.topic = topic;
|
||||
this.callback = callback;
|
||||
this.constraints = [];
|
||||
this.context = null;
|
||||
this.subscribe(callback);
|
||||
postal.configuration.bus.publish( {
|
||||
channel : postal.configuration.SYSTEM_CHANNEL,
|
||||
topic : "subscription.created",
|
||||
|
|
@ -116,13 +250,7 @@
|
|||
},
|
||||
|
||||
defer : function () {
|
||||
var self = this;
|
||||
var fn = this.callback;
|
||||
this.callback = function ( data, env ) {
|
||||
setTimeout( function () {
|
||||
fn.call( self.context, data, env );
|
||||
}, 0 );
|
||||
};
|
||||
this.callback.useStrategy(postal.configuration.strategies.setTimeout(0));
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -130,26 +258,20 @@
|
|||
if ( _.isNaN( maxCalls ) || maxCalls <= 0 ) {
|
||||
throw "The value provided to disposeAfter (maxCalls) must be a number greater than zero.";
|
||||
}
|
||||
var self = this;
|
||||
var fn = this.callback;
|
||||
var dispose = _.after( maxCalls, _.bind( function () {
|
||||
this.unsubscribe();
|
||||
}, this ) );
|
||||
|
||||
this.callback = function () {
|
||||
fn.apply( self.context, arguments );
|
||||
dispose();
|
||||
};
|
||||
return this;
|
||||
var self = this;
|
||||
self.callback.useStrategy(postal.configuration.strategies.after(maxCalls, function() {
|
||||
self.unsubscribe.call(self);
|
||||
}));
|
||||
return self;
|
||||
},
|
||||
|
||||
distinctUntilChanged : function () {
|
||||
this.withConstraint( new ConsecutiveDistinctPredicate() );
|
||||
this.callback.useStrategy(postal.configuration.strategies.distinct());
|
||||
return this;
|
||||
},
|
||||
|
||||
distinct : function () {
|
||||
this.withConstraint( new DistinctPredicate() );
|
||||
this.callback.useStrategy(postal.configuration.strategies.distinct({ all: true }));
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -162,22 +284,12 @@
|
|||
if ( !_.isFunction( predicate ) ) {
|
||||
throw "Predicate constraint must be a function";
|
||||
}
|
||||
this.constraints.push( predicate );
|
||||
this.callback.useStrategy(postal.configuration.strategies.predicate(predicate));
|
||||
return this;
|
||||
},
|
||||
|
||||
withConstraints : function ( predicates ) {
|
||||
var self = this;
|
||||
if ( _.isArray( predicates ) ) {
|
||||
_.each( predicates, function ( predicate ) {
|
||||
self.withConstraint( predicate );
|
||||
} );
|
||||
}
|
||||
return self;
|
||||
},
|
||||
|
||||
withContext : function ( context ) {
|
||||
this.context = context;
|
||||
this.callback.context(context);
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -194,13 +306,7 @@
|
|||
if ( _.isNaN( milliseconds ) ) {
|
||||
throw "Milliseconds must be a number";
|
||||
}
|
||||
var self = this;
|
||||
var fn = this.callback;
|
||||
this.callback = function ( data, env ) {
|
||||
setTimeout( function () {
|
||||
fn.call( self.context, data, env );
|
||||
}, milliseconds );
|
||||
};
|
||||
this.callback.useStrategy(postal.configuration.strategies.setTimeout(milliseconds));
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -208,13 +314,18 @@
|
|||
if ( _.isNaN( milliseconds ) ) {
|
||||
throw "Milliseconds must be a number";
|
||||
}
|
||||
var fn = this.callback;
|
||||
this.callback = _.throttle( fn, milliseconds );
|
||||
this.callback.useStrategy(postal.configuration.strategies.throttle(milliseconds));
|
||||
return this;
|
||||
},
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
|
@ -259,13 +370,7 @@
|
|||
/* global postal */
|
||||
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.callback.context ? subDef.callback.context() : this, envelope.data, envelope );
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -366,7 +471,8 @@
|
|||
bus : localBus,
|
||||
resolver : bindingsResolver,
|
||||
DEFAULT_CHANNEL : "/",
|
||||
SYSTEM_CHANNEL : "postal"
|
||||
SYSTEM_CHANNEL : "postal",
|
||||
strategies : strats
|
||||
},
|
||||
|
||||
ChannelDefinition : ChannelDefinition,
|
||||
|
|
|
|||
2
lib/postal.min.js
vendored
2
lib/postal.min.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -1,7 +1,10 @@
|
|||
/* global describe, postal, it, after, before, expect, ConsecutiveDistinctPredicate */
|
||||
describe( "ConsecutiveDistinctPredicate", function () {
|
||||
var accessor = function(args) {
|
||||
return args[0];
|
||||
};
|
||||
describe( "When calling the function with the same data multiple times", function () {
|
||||
var pred = new ConsecutiveDistinctPredicate(),
|
||||
var pred = new ConsecutiveDistinctPredicate(accessor),
|
||||
data = { name : "Dr Who" },
|
||||
results = [];
|
||||
results.push( pred( data ) );
|
||||
|
|
@ -19,7 +22,7 @@ describe( "ConsecutiveDistinctPredicate", function () {
|
|||
} );
|
||||
} );
|
||||
describe( "When calling the function with different data every time", function () {
|
||||
var predA = new ConsecutiveDistinctPredicate(),
|
||||
var predA = new ConsecutiveDistinctPredicate(accessor),
|
||||
data = { name : "Amelia" },
|
||||
res = [];
|
||||
res.push( predA( data ) );
|
||||
|
|
@ -39,7 +42,7 @@ describe( "ConsecutiveDistinctPredicate", function () {
|
|||
} );
|
||||
} );
|
||||
describe( "When calling the function with different data every two calls", function () {
|
||||
var predA = new ConsecutiveDistinctPredicate(),
|
||||
var predA = new ConsecutiveDistinctPredicate(accessor),
|
||||
data = { name : "Amelia" },
|
||||
res = [];
|
||||
res.push( predA( data ) );
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
/* global describe, postal, it, after, before, expect, DistinctPredicate */
|
||||
describe( 'DistinctPredicate', function () {
|
||||
var accessor = function(args) {
|
||||
return args[0];
|
||||
};
|
||||
|
||||
describe( 'When calling the function with the same data object multiple times', function () {
|
||||
var pred = new DistinctPredicate(),
|
||||
var pred = new DistinctPredicate(accessor),
|
||||
results = [];
|
||||
|
||||
results.push( pred( {career : 'ninja'} ) );
|
||||
|
|
@ -21,7 +24,7 @@ describe( 'DistinctPredicate', function () {
|
|||
} );
|
||||
|
||||
describe( 'When calling the function with the same primitive multiple times', function () {
|
||||
var pred = new DistinctPredicate(),
|
||||
var pred = new DistinctPredicate(accessor),
|
||||
results = [];
|
||||
|
||||
results.push( pred( 'ninja' ) );
|
||||
|
|
@ -40,7 +43,7 @@ describe( 'DistinctPredicate', function () {
|
|||
} );
|
||||
|
||||
describe( 'When calling the function with the same array multiple times', function () {
|
||||
var pred = new DistinctPredicate(),
|
||||
var pred = new DistinctPredicate(accessor),
|
||||
results = [];
|
||||
|
||||
results.push( pred( ['Jack Black', 'Kyle Gass'] ) );
|
||||
|
|
@ -61,7 +64,7 @@ describe( 'DistinctPredicate', function () {
|
|||
// ------------------------------------------
|
||||
|
||||
describe( 'When calling the function with different data object every time', function () {
|
||||
var pred = new DistinctPredicate(),
|
||||
var pred = new DistinctPredicate(accessor),
|
||||
results = [];
|
||||
|
||||
results.push( pred( {codename : 'tinker'} ) );
|
||||
|
|
@ -78,7 +81,7 @@ describe( 'DistinctPredicate', function () {
|
|||
} );
|
||||
|
||||
describe( 'When calling the function with different primitive every time', function () {
|
||||
var pred = new DistinctPredicate(),
|
||||
var pred = new DistinctPredicate(accessor),
|
||||
results = [];
|
||||
|
||||
results.push( pred( 100.5 ) );
|
||||
|
|
@ -95,7 +98,7 @@ describe( 'DistinctPredicate', function () {
|
|||
} );
|
||||
|
||||
describe( 'When calling the function with different array every time', function () {
|
||||
var pred = new DistinctPredicate(),
|
||||
var pred = new DistinctPredicate(accessor),
|
||||
results = [];
|
||||
|
||||
results.push( pred( [] ) );
|
||||
|
|
@ -114,7 +117,7 @@ describe( 'DistinctPredicate', function () {
|
|||
// ------------------------------------------
|
||||
|
||||
describe( 'When calling the function with different data object between duplicates', function () {
|
||||
var pred = new DistinctPredicate(),
|
||||
var pred = new DistinctPredicate(accessor),
|
||||
results = [];
|
||||
|
||||
results.push( pred( {game : 'Diablo 3'} ) );
|
||||
|
|
@ -141,7 +144,7 @@ describe( 'DistinctPredicate', function () {
|
|||
} );
|
||||
|
||||
describe( 'When calling the function with different primitive between duplicates', function () {
|
||||
var pred = new DistinctPredicate(),
|
||||
var pred = new DistinctPredicate(accessor),
|
||||
results = [];
|
||||
|
||||
results.push( pred( 'Stan Marsh' ) );
|
||||
|
|
@ -168,7 +171,7 @@ describe( 'DistinctPredicate', function () {
|
|||
} );
|
||||
|
||||
describe( 'When calling the function with different array between duplicates', function () {
|
||||
var pred = new DistinctPredicate(),
|
||||
var pred = new DistinctPredicate(accessor),
|
||||
results = [];
|
||||
|
||||
results.push( pred( [] ) );
|
||||
|
|
|
|||
|
|
@ -40,11 +40,8 @@ describe( "Postal", function () {
|
|||
it( "should have set subscription topic value", function () {
|
||||
expect( sub.topic ).to.be( "MyTopic" );
|
||||
} );
|
||||
it( "should have defaulted the subscription constraints array", function () {
|
||||
expect( sub.constraints.length ).to.be( 0 );
|
||||
} );
|
||||
it( "should have defaulted the subscription context value", function () {
|
||||
expect( sub.context ).to.be( null );
|
||||
expect( sub.callback.context() ).to.be( sub );
|
||||
} );
|
||||
it( "should have captured subscription creation event", function () {
|
||||
expect( caughtSubscribeEvent ).to.be.ok();
|
||||
|
|
@ -143,9 +140,9 @@ describe( "Postal", function () {
|
|||
} );
|
||||
it( "should produce expected messages", function () {
|
||||
expect( results.length ).to.be( 3 );
|
||||
expect( results[0] ).to.be( "1 received message" );
|
||||
expect( results[1] ).to.be( "2 received message" );
|
||||
expect( results[2] ).to.be( "unsubscribed" );
|
||||
expect( results[0] ).to.be( "unsubscribed" );
|
||||
expect( results[1] ).to.be( "1 received message" );
|
||||
expect( results[2] ).to.be( "2 received message" );
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
|
@ -221,8 +218,7 @@ describe( "Postal", function () {
|
|||
channel = postal.channel( "MyChannel" );
|
||||
subscription = channel.subscribe( "MyTopic", function ( data ) {
|
||||
subInvokedCnt++;
|
||||
} )
|
||||
.distinctUntilChanged();
|
||||
}).distinctUntilChanged();
|
||||
channel.publish( "MyTopic", "Testing123" );
|
||||
channel.publish( "MyTopic", "Testing123" );
|
||||
channel.publish( "MyTopic", "Testing123" );
|
||||
|
|
@ -234,9 +230,9 @@ describe( "Postal", function () {
|
|||
postal.utils.reset();
|
||||
subInvokedCnt = 0;
|
||||
} );
|
||||
it( "should have a constraint on the subscription", function () {
|
||||
expect( postal.configuration.bus.subscriptions.MyChannel.MyTopic[0].constraints.length ).to.be( 1 );
|
||||
} );
|
||||
it( "callback should be a strategy", function () {
|
||||
expect( typeof postal.configuration.bus.subscriptions.MyChannel.MyTopic[0].callback.context ).to.be( "function" );
|
||||
} );
|
||||
it( "subscription callback should be invoked once", function () {
|
||||
expect( subInvokedCnt ).to.be( 1 );
|
||||
} );
|
||||
|
|
@ -247,10 +243,9 @@ describe( "Postal", function () {
|
|||
channel = postal.channel( "MyChannel" );
|
||||
subscription = channel.subscribe( "MyTopic", function ( data ) {
|
||||
recvd = true;
|
||||
} )
|
||||
.withConstraint( function () {
|
||||
return true;
|
||||
} );
|
||||
}).withConstraint( function () {
|
||||
return true;
|
||||
});
|
||||
channel.publish( "MyTopic", "Testing123" );
|
||||
} );
|
||||
after( function () {
|
||||
|
|
@ -258,7 +253,7 @@ describe( "Postal", function () {
|
|||
recvd = false;
|
||||
} );
|
||||
it( "should have a constraint on the subscription", function () {
|
||||
expect( postal.configuration.bus.subscriptions.MyChannel.MyTopic[0].constraints.length ).to.be( 1 );
|
||||
expect( subscription.callback.strategies()[0].name ).to.be( "predicate" );
|
||||
} );
|
||||
it( "should have invoked the subscription callback", function () {
|
||||
expect( recvd ).to.be.ok();
|
||||
|
|
@ -281,70 +276,41 @@ describe( "Postal", function () {
|
|||
recvd = false;
|
||||
} );
|
||||
it( "should have a constraint on the subscription", function () {
|
||||
expect( postal.configuration.bus.subscriptions.MyChannel.MyTopic[0].constraints.length ).to.be( 1 );
|
||||
expect( subscription.callback.strategies()[0].name ).to.be( "predicate" );
|
||||
} );
|
||||
it( "should not have invoked the subscription callback", function () {
|
||||
expect( recvd ).to.not.be.ok();
|
||||
} );
|
||||
} );
|
||||
describe( "When subscribing with multiple constraints returning true", function () {
|
||||
describe( "When subscribing with multiple constraints", function () {
|
||||
var recvd = false;
|
||||
before( function () {
|
||||
channel = postal.channel( "MyChannel" );
|
||||
subscription = channel.subscribe( "MyTopic", function ( data ) {
|
||||
recvd = true;
|
||||
} )
|
||||
.withConstraints( [function () {
|
||||
return true;
|
||||
},
|
||||
function () {
|
||||
return true;
|
||||
},
|
||||
function () {
|
||||
return true;
|
||||
}] );
|
||||
.withConstraint(function () {
|
||||
return false;
|
||||
})
|
||||
.withConstraint(function () {
|
||||
return false;
|
||||
})
|
||||
.withConstraint(function () {
|
||||
return true;
|
||||
});
|
||||
channel.publish( "MyTopic", "Testing123" );
|
||||
} );
|
||||
after( function () {
|
||||
postal.utils.reset();
|
||||
recvd = false;
|
||||
} );
|
||||
it( "should have a constraint on the subscription", function () {
|
||||
expect( postal.configuration.bus.subscriptions.MyChannel.MyTopic[0].constraints.length ).to.be( 3 );
|
||||
it( "should overwrite constraint with last one passed in", function () {
|
||||
expect( subscription.callback.strategies().length ).to.be( 1 );
|
||||
} );
|
||||
it( "should have invoked the callback", function () {
|
||||
expect( recvd ).to.be.ok();
|
||||
} );
|
||||
} );
|
||||
describe( "When subscribing with multiple constraints and one returning false", function () {
|
||||
var recvd = false;
|
||||
before( function () {
|
||||
channel = postal.channel( "MyChannel" );
|
||||
subscription = channel.subscribe( "MyTopic", function ( data ) {
|
||||
recvd = true;
|
||||
} )
|
||||
.withConstraints( [function () {
|
||||
return true;
|
||||
},
|
||||
function () {
|
||||
return false;
|
||||
},
|
||||
function () {
|
||||
return true;
|
||||
}] );
|
||||
channel.publish( "MyTopic", "Testing123" );
|
||||
} );
|
||||
after( function () {
|
||||
postal.utils.reset();
|
||||
recvd = false;
|
||||
} );
|
||||
it( "should have a constraint on the subscription", function () {
|
||||
expect( postal.configuration.bus.subscriptions.MyChannel.MyTopic[0].constraints.length ).to.be( 3 );
|
||||
} );
|
||||
it( "should not have invoked the callback", function () {
|
||||
expect( recvd ).to.not.be.ok()
|
||||
} );
|
||||
} );
|
||||
describe( "When subscribing with the context being set", function () {
|
||||
var count = 0,
|
||||
obj = {
|
||||
|
|
@ -610,11 +576,8 @@ describe( "Postal", function () {
|
|||
it( "should have set subscription topic value", function () {
|
||||
expect( sub.topic ).to.be( "MyTopic" );
|
||||
} );
|
||||
it( "should have defaulted the subscription constraints array", function () {
|
||||
expect( sub.constraints.length ).to.be( 0 );
|
||||
} );
|
||||
it( "should have defaulted the subscription context value", function () {
|
||||
expect( sub.context ).to.be( null );
|
||||
it( "should have context method", function () {
|
||||
expect( typeof sub.callback.context ).to.be( "function" );
|
||||
} );
|
||||
} );
|
||||
describe( "When using global channel api", function () {
|
||||
|
|
@ -683,8 +646,7 @@ describe( "Postal", function () {
|
|||
it( "should have created a subscription definition", function () {
|
||||
expect( sub.channel ).to.be( "MyChannel" );
|
||||
expect( sub.topic ).to.be( "MyTopic" );
|
||||
expect( sub.constraints.length ).to.be( 0 );
|
||||
expect( sub.context ).to.be( null );
|
||||
expect( sub.context ).to.be( undefined );
|
||||
} );
|
||||
it( "should have created a resolver cache entry", function () {
|
||||
expect( _.isEmpty( resolver ) ).to.not.be.ok()
|
||||
|
|
|
|||
|
|
@ -34,12 +34,6 @@ describe( "SubscriptionDefinition", function () {
|
|||
it( "should set the callback", function () {
|
||||
expect( sDef.callback ).to.be( NO_OP );
|
||||
} );
|
||||
it( "should default the constraints", function () {
|
||||
expect( sDef.constraints.length ).to.be( 0 );
|
||||
} );
|
||||
it( "should default the context", function () {
|
||||
expect( sDef.context ).to.be( null );
|
||||
} );
|
||||
it( "should fire the subscription.created message", function () {
|
||||
expect( caughtSubscribeEvent ).to.be( true );
|
||||
} );
|
||||
|
|
@ -48,29 +42,18 @@ describe( "SubscriptionDefinition", function () {
|
|||
describe( "When setting distinctUntilChanged", function () {
|
||||
var sDefa = new SubscriptionDefinition( "TestChannel", "TestTopic", NO_OP ).distinctUntilChanged();
|
||||
|
||||
it( "Should add a DistinctPredicate constraint to the configuration constraints", function () {
|
||||
expect( sDefa.constraints.length ).to.be( 1 );
|
||||
} );
|
||||
it( "callback should be a strategy", function () {
|
||||
expect( typeof sDefa.callback.context ).to.be( "function" );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( "When adding a constraint", function () {
|
||||
var sDefb = new SubscriptionDefinition( "TestChannel", "TestTopic", NO_OP ).withConstraint( function () {
|
||||
} );
|
||||
|
||||
it( "Should add a constraint", function () {
|
||||
expect( sDefb.constraints.length ).to.be( 1 );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( "When adding multiple constraints", function () {
|
||||
var sDefc = new SubscriptionDefinition( "TestChannel", "TestTopic", NO_OP ).withConstraints( [function () {
|
||||
}, function () {
|
||||
}, function () {
|
||||
}] );
|
||||
|
||||
it( "Should add a constraint", function () {
|
||||
expect( sDefc.constraints.length ).to.be( 3 );
|
||||
} );
|
||||
it( "callback should be a strategy", function () {
|
||||
expect( typeof sDefb.callback.context ).to.be( "function" );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( "When setting the context", function () {
|
||||
|
|
@ -86,7 +69,7 @@ describe( "SubscriptionDefinition", function () {
|
|||
postal.publish( { channel : "TestChannel", topic : "TestTopic", data : "Oh, hai"} )
|
||||
|
||||
it( "Should set context", function () {
|
||||
expect( sDefd.context ).to.be( obj );
|
||||
expect( sDefd.callback.context() ).to.be( obj );
|
||||
} );
|
||||
it( "Should apply context to predicate/constraint", function () {
|
||||
expect( name ).to.be( "Rose" );
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
<script type="text/javascript" src="../ext/amplify.core.js"></script>
|
||||
<script type="text/javascript" src="../ext/amplify.store.js"></script>
|
||||
<script type="text/javascript" src="../ext/underscore.js"></script>
|
||||
<script type="text/javascript" src="../src/strategy.js"></script>
|
||||
<script type="text/javascript" src="../src/strategies.js"></script>
|
||||
<script type="text/javascript" src="../src/DistinctPredicate.js"></script>
|
||||
<script type="text/javascript" src="../src/ConsecutiveDistinctPredicate.js"></script>
|
||||
<script type="text/javascript" src="../src/ChannelDefinition.js"></script>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ postal = {
|
|||
bus : localBus,
|
||||
resolver : bindingsResolver,
|
||||
DEFAULT_CHANNEL : "/",
|
||||
SYSTEM_CHANNEL : "postal"
|
||||
SYSTEM_CHANNEL : "postal",
|
||||
strategies : strats
|
||||
},
|
||||
|
||||
ChannelDefinition : ChannelDefinition,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
/*jshint -W098 */
|
||||
var ConsecutiveDistinctPredicate = function () {
|
||||
var ConsecutiveDistinctPredicate = function (argsAccessor) {
|
||||
var previous;
|
||||
return function ( data ) {
|
||||
return function () {
|
||||
var data = argsAccessor(arguments);
|
||||
var eq = false;
|
||||
if ( _.isString( data ) ) {
|
||||
eq = data === previous;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
/*jshint -W098 */
|
||||
var DistinctPredicate = function () {
|
||||
var DistinctPredicate = function (argsAccessor) {
|
||||
var previous = [];
|
||||
|
||||
return function ( data ) {
|
||||
return function () {
|
||||
var data = argsAccessor(arguments);
|
||||
var isDistinct = !_.any( previous, function ( p ) {
|
||||
if ( _.isObject( data ) || _.isArray( data ) ) {
|
||||
return _.isEqual( data, p );
|
||||
|
|
@ -12,6 +13,6 @@ var DistinctPredicate = function () {
|
|||
if ( isDistinct ) {
|
||||
previous.push( data );
|
||||
}
|
||||
return isDistinct;
|
||||
return isDistinct;
|
||||
};
|
||||
};
|
||||
|
|
@ -1,13 +1,7 @@
|
|||
/* global postal */
|
||||
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.callback.context ? subDef.callback.context() : this, envelope.data, envelope );
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@
|
|||
var SubscriptionDefinition = function ( channel, topic, callback ) {
|
||||
this.channel = channel;
|
||||
this.topic = topic;
|
||||
this.callback = callback;
|
||||
this.constraints = [];
|
||||
this.context = null;
|
||||
this.subscribe(callback);
|
||||
postal.configuration.bus.publish( {
|
||||
channel : postal.configuration.SYSTEM_CHANNEL,
|
||||
topic : "subscription.created",
|
||||
|
|
@ -36,13 +34,7 @@ SubscriptionDefinition.prototype = {
|
|||
},
|
||||
|
||||
defer : function () {
|
||||
var self = this;
|
||||
var fn = this.callback;
|
||||
this.callback = function ( data, env ) {
|
||||
setTimeout( function () {
|
||||
fn.call( self.context, data, env );
|
||||
}, 0 );
|
||||
};
|
||||
this.callback.useStrategy(postal.configuration.strategies.setTimeout(0));
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -50,26 +42,20 @@ SubscriptionDefinition.prototype = {
|
|||
if ( _.isNaN( maxCalls ) || maxCalls <= 0 ) {
|
||||
throw "The value provided to disposeAfter (maxCalls) must be a number greater than zero.";
|
||||
}
|
||||
var self = this;
|
||||
var fn = this.callback;
|
||||
var dispose = _.after( maxCalls, _.bind( function () {
|
||||
this.unsubscribe();
|
||||
}, this ) );
|
||||
|
||||
this.callback = function () {
|
||||
fn.apply( self.context, arguments );
|
||||
dispose();
|
||||
};
|
||||
return this;
|
||||
var self = this;
|
||||
self.callback.useStrategy(postal.configuration.strategies.after(maxCalls, function() {
|
||||
self.unsubscribe.call(self);
|
||||
}));
|
||||
return self;
|
||||
},
|
||||
|
||||
distinctUntilChanged : function () {
|
||||
this.withConstraint( new ConsecutiveDistinctPredicate() );
|
||||
this.callback.useStrategy(postal.configuration.strategies.distinct());
|
||||
return this;
|
||||
},
|
||||
|
||||
distinct : function () {
|
||||
this.withConstraint( new DistinctPredicate() );
|
||||
this.callback.useStrategy(postal.configuration.strategies.distinct({ all: true }));
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -82,22 +68,12 @@ SubscriptionDefinition.prototype = {
|
|||
if ( !_.isFunction( predicate ) ) {
|
||||
throw "Predicate constraint must be a function";
|
||||
}
|
||||
this.constraints.push( predicate );
|
||||
this.callback.useStrategy(postal.configuration.strategies.predicate(predicate));
|
||||
return this;
|
||||
},
|
||||
|
||||
withConstraints : function ( predicates ) {
|
||||
var self = this;
|
||||
if ( _.isArray( predicates ) ) {
|
||||
_.each( predicates, function ( predicate ) {
|
||||
self.withConstraint( predicate );
|
||||
} );
|
||||
}
|
||||
return self;
|
||||
},
|
||||
|
||||
withContext : function ( context ) {
|
||||
this.context = context;
|
||||
this.callback.context(context);
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -114,13 +90,7 @@ SubscriptionDefinition.prototype = {
|
|||
if ( _.isNaN( milliseconds ) ) {
|
||||
throw "Milliseconds must be a number";
|
||||
}
|
||||
var self = this;
|
||||
var fn = this.callback;
|
||||
this.callback = function ( data, env ) {
|
||||
setTimeout( function () {
|
||||
fn.call( self.context, data, env );
|
||||
}, milliseconds );
|
||||
};
|
||||
this.callback.useStrategy(postal.configuration.strategies.setTimeout(milliseconds));
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -128,13 +98,18 @@ SubscriptionDefinition.prototype = {
|
|||
if ( _.isNaN( milliseconds ) ) {
|
||||
throw "Milliseconds must be a number";
|
||||
}
|
||||
var fn = this.callback;
|
||||
this.callback = _.throttle( fn, milliseconds );
|
||||
this.callback.useStrategy(postal.configuration.strategies.throttle(milliseconds));
|
||||
return this;
|
||||
},
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
|
@ -19,6 +19,8 @@
|
|||
|
||||
var postal;
|
||||
|
||||
//import("strategy.js");
|
||||
//import("strategies.js");
|
||||
//import("ConsecutiveDistinctPredicate.js");
|
||||
//import("DistinctPredicate.js");
|
||||
//import("ChannelDefinition.js");
|
||||
|
|
|
|||
66
src/strategies.js
Normal file
66
src/strategies.js
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/* global DistinctPredicate,ConsecutiveDistinctPredicate */
|
||||
var strats = {
|
||||
setTimeout: function(ms) {
|
||||
return {
|
||||
name: "setTimeout",
|
||||
fn: function (next, data, envelope) {
|
||||
setTimeout(function () {
|
||||
next(data, envelope);
|
||||
}, ms);
|
||||
}
|
||||
};
|
||||
},
|
||||
after: function(maxCalls, callback) {
|
||||
var dispose = _.after(maxCalls, callback);
|
||||
return {
|
||||
name: "after",
|
||||
fn: function (next, data, envelope) {
|
||||
dispose();
|
||||
next(data, envelope);
|
||||
}
|
||||
};
|
||||
},
|
||||
throttle : function(ms) {
|
||||
return {
|
||||
name: "throttle",
|
||||
fn: _.throttle(function(next, data, envelope) {
|
||||
next(data, envelope);
|
||||
}, ms)
|
||||
};
|
||||
},
|
||||
debounce: function(ms, immediate) {
|
||||
return {
|
||||
name: "debounce",
|
||||
fn: _.debounce(function(next, data, envelope) {
|
||||
next(data, envelope);
|
||||
}, ms, !!immediate)
|
||||
};
|
||||
},
|
||||
predicate: function(pred) {
|
||||
return {
|
||||
name: "predicate",
|
||||
fn: function(next, data, envelope) {
|
||||
if(pred.call(this, data, envelope)) {
|
||||
next.call(this, data, envelope);
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
distinct : function(options) {
|
||||
options = options || {};
|
||||
var accessor = function(args) {
|
||||
return args[0];
|
||||
};
|
||||
var check = options.all ?
|
||||
new DistinctPredicate(accessor) :
|
||||
new ConsecutiveDistinctPredicate(accessor);
|
||||
return {
|
||||
name : "distinct",
|
||||
fn : function(next, data, envelope) {
|
||||
if(check(data)) {
|
||||
next(data, envelope);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
68
src/strategy.js
Normal file
68
src/strategy.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
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;
|
||||
};
|
||||
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;
|
||||
}
|
||||
};
|
||||
Loading…
Reference in a new issue