From 87f6cc57e0751426c0727f6a5454224e1be17a12 Mon Sep 17 00:00:00 2001 From: ifandelse Date: Wed, 15 Jan 2014 00:52:50 -0500 Subject: [PATCH] Working build with Gulp. No built-in browser (or console) test runner yet. --- example/amd/js/libs/postal/postal.js | 897 +++++++++++----------- example/amd/js/libs/postal/postal.min.js | 13 +- example/standard/js/postal.js | 897 +++++++++++----------- example/standard/js/postal.min.js | 13 +- gulpfile.js | 34 + lib/postal.js | 903 ++++++++++++----------- lib/postal.min.js | 13 +- package.json | 176 +++-- 8 files changed, 1505 insertions(+), 1441 deletions(-) mode change 100755 => 100644 example/amd/js/libs/postal/postal.js mode change 100755 => 100644 example/amd/js/libs/postal/postal.min.js mode change 100755 => 100644 example/standard/js/postal.js mode change 100755 => 100644 example/standard/js/postal.min.js create mode 100644 gulpfile.js mode change 100755 => 100644 lib/postal.js mode change 100755 => 100644 lib/postal.min.js diff --git a/example/amd/js/libs/postal/postal.js b/example/amd/js/libs/postal/postal.js old mode 100755 new mode 100644 index 25ee641..0a03768 --- a/example/amd/js/libs/postal/postal.js +++ b/example/amd/js/libs/postal/postal.js @@ -1,450 +1,457 @@ -/* - postal - Author: Jim Cowart (http://freshbrewedcode.com/jimcowart) - License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license) - Version 0.8.11 +/** + * postal - Pub/Sub library providing wildcard subscriptions, complex message handling, etc. Works server and client-side. + * Author: Jim Cowart (http://freshbrewedcode.com/jimcowart) + * Version: v0.8.11 + * Url: http://github.com/postaljs/postal.js + * License: */ -/*jshint -W098 */ -(function ( root, factory ) { - if ( typeof module === "object" && module.exports ) { - // Node, or CommonJS-Like environments - module.exports = function ( _ ) { - _ = _ || require( "underscore" ); - return factory( _ ); - }; - } else if ( typeof define === "function" && define.amd ) { - // AMD. Register as an anonymous module. - define( ["underscore"], function ( _ ) { - return factory( _, root ); - } ); - } else { - // Browser globals - root.postal = factory( root._, root ); - } -}( this, function ( _, global, undefined ) { - var postal; +(function (root, factory) { + if (typeof module === "object" && module.exports) { + // Node, or CommonJS-Like environments + module.exports = function (_) { + _ = _ || require("underscore"); + return factory(_); + }; + } else if (typeof define === "function" && define.amd) { + // AMD. Register as an anonymous module. + define(["underscore"], function (_) { + return factory(_, root); + }); + } else { + // Browser globals + root.postal = factory(root._, root); + } +}(this, function (_, global, undefined) { - /*jshint -W098 */ - var ConsecutiveDistinctPredicate = function () { - var previous; - return function ( data ) { - var eq = false; - if ( _.isString( data ) ) { - eq = data === previous; - previous = data; - } - else { - eq = _.isEqual( data, previous ); - previous = _.clone( data ); - } - return !eq; - }; - }; - /*jshint -W098 */ - var DistinctPredicate = function () { - var previous = []; - - return function ( data ) { - var isDistinct = !_.any( previous, function ( p ) { - if ( _.isObject( data ) || _.isArray( data ) ) { - return _.isEqual( data, p ); - } - return data === p; - } ); - if ( isDistinct ) { - previous.push( data ); - } - return isDistinct; - }; - }; - /* global postal, SubscriptionDefinition */ - var ChannelDefinition = function ( channelName ) { - this.channel = channelName || postal.configuration.DEFAULT_CHANNEL; - }; - - ChannelDefinition.prototype.subscribe = function () { - return 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.configuration.bus.publish( envelope ); - }; - /* global postal */ - /*jshint -W117 */ - var SubscriptionDefinition = function ( channel, topic, callback ) { - this.channel = channel; - this.topic = topic; - this.callback = callback; - this.constraints = []; - this.context = null; - postal.configuration.bus.publish( { - channel : postal.configuration.SYSTEM_CHANNEL, - topic : "subscription.created", - data : { - event : "subscription.created", - channel : channel, - topic : topic - } - } ); - postal.configuration.bus.subscribe( this ); - }; - - SubscriptionDefinition.prototype = { - unsubscribe : function () { - if ( !this.inactive ) { - this.inactive = true; - postal.configuration.bus.unsubscribe( this ); - postal.configuration.bus.publish( { - channel : postal.configuration.SYSTEM_CHANNEL, - topic : "subscription.removed", - data : { - event : "subscription.removed", - channel : this.channel, - topic : this.topic - } - } ); - } - }, - - defer : function () { - var self = this; - var fn = this.callback; - this.callback = function ( data, env ) { - setTimeout( function () { - fn.call( self.context, data, env ); - }, 0 ); - }; - return this; - }, - - disposeAfter : function ( maxCalls ) { - 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; - }, - - distinctUntilChanged : function () { - this.withConstraint( new ConsecutiveDistinctPredicate() ); - return this; - }, - - distinct : function () { - this.withConstraint( new DistinctPredicate() ); - return this; - }, - - once : function () { - this.disposeAfter( 1 ); - return this; - }, - - withConstraint : function ( predicate ) { - if ( !_.isFunction( predicate ) ) { - throw "Predicate constraint must be a function"; - } - this.constraints.push( 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; - return this; - }, - - withDebounce : function ( milliseconds, immediate ) { - if ( _.isNaN( milliseconds ) ) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = _.debounce( fn, milliseconds, !!immediate ); - return this; - }, - - withDelay : function ( milliseconds ) { - 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 ); - }; - return this; - }, - - withThrottle : function ( milliseconds ) { - if ( _.isNaN( milliseconds ) ) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = _.throttle( fn, milliseconds ); - return this; - }, - - subscribe : function ( callback ) { - this.callback = callback; - return this; - } - }; - /*jshint -W098 */ - var bindingsResolver = { - cache : {}, - regex : {}, - - compare : function ( binding, topic ) { - var pattern, rgx, prevSegment, result = ( this.cache[ topic ] && this.cache[ topic ][ binding ] ); - if ( typeof result !== "undefined" ) { - return result; - } - if ( !( rgx = this.regex[ binding ] )) { - pattern = "^" + _.map( binding.split( "." ),function ( segment ) { - var res = ""; - if ( !!prevSegment ) { - res = prevSegment !== "#" ? "\\.\\b" : "\\b"; - } - if ( segment === "#" ) { - res += "[\\s\\S]*"; - } else if ( segment === "*" ) { - res += "[^.]+"; - } else { - res += segment; - } - prevSegment = segment; - return res; - } ).join( "" ) + "$"; - rgx = this.regex[ binding ] = new RegExp( pattern ); - } - this.cache[ topic ] = this.cache[ topic ] || {}; - this.cache[ topic ][ binding ] = result = rgx.test( topic ); - return result; - }, - - reset : function () { - this.cache = {}; - this.regex = {}; - } - }; - /* 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 ); - } - } - } - }; - - var pubInProgress = 0; - var unSubQueue = []; - var clearUnSubQueue = function () { - while ( unSubQueue.length ) { - localBus.unsubscribe(unSubQueue.shift()); - } - }; - - var localBus = { - addWireTap : function ( callback ) { - var self = this; - self.wireTaps.push( callback ); - return function () { - var idx = self.wireTaps.indexOf( callback ); - if ( idx !== -1 ) { - self.wireTaps.splice( idx, 1 ); - } - }; - }, - - publish : function ( envelope ) { - ++pubInProgress; - envelope.timeStamp = new Date(); - _.each( this.wireTaps, function ( tap ) { - tap( envelope.data, envelope ); - } ); - if ( this.subscriptions[envelope.channel] ) { - _.each( this.subscriptions[envelope.channel], function ( subscribers ) { - var idx = 0, len = subscribers.length, subDef; - while ( idx < len ) { - if ( subDef = subscribers[idx++] ) { - fireSub( subDef, envelope ); - } - } - } ); - } - if ( --pubInProgress === 0 ) { - clearUnSubQueue(); - } - return envelope; - }, - - reset : function () { - if ( this.subscriptions ) { - _.each( this.subscriptions, function ( channel ) { - _.each( channel, function ( topic ) { - while ( topic.length ) { - topic.pop().unsubscribe(); - } - } ); - } ); - this.subscriptions = {}; - } - }, - - subscribe : function ( subDef ) { - var channel = this.subscriptions[subDef.channel], subs; - if ( !channel ) { - channel = this.subscriptions[subDef.channel] = {}; - } - subs = this.subscriptions[subDef.channel][subDef.topic]; - if ( !subs ) { - subs = this.subscriptions[subDef.channel][subDef.topic] = []; - } - subs.push( subDef ); - return subDef; - }, - - subscriptions : {}, - - wireTaps : [], - - unsubscribe : function ( config ) { - if ( pubInProgress ) { - unSubQueue.push( config ); - return; - } - if ( this.subscriptions[config.channel][config.topic] ) { - var len = this.subscriptions[config.channel][config.topic].length, - idx = 0; - while ( idx < len ) { - if ( this.subscriptions[config.channel][config.topic][idx] === config ) { - this.subscriptions[config.channel][config.topic].splice( idx, 1 ); - break; - } - idx += 1; - } - } - } - }; - /* global localBus, bindingsResolver, ChannelDefinition, SubscriptionDefinition, postal */ - /*jshint -W020 */ - postal = { - configuration : { - bus : localBus, - resolver : bindingsResolver, - DEFAULT_CHANNEL : "/", - SYSTEM_CHANNEL : "postal" - }, - - ChannelDefinition : ChannelDefinition, - SubscriptionDefinition : SubscriptionDefinition, - - channel : function ( channelName ) { - return new ChannelDefinition( channelName ); - }, - - subscribe : function ( options ) { - return new SubscriptionDefinition( options.channel || postal.configuration.DEFAULT_CHANNEL, options.topic, options.callback ); - }, - - publish : function ( envelope ) { - envelope.channel = envelope.channel || postal.configuration.DEFAULT_CHANNEL; - return postal.configuration.bus.publish( envelope ); - }, - - addWireTap : function ( callback ) { - return this.configuration.bus.addWireTap( callback ); - }, - - linkChannels : function ( sources, destinations ) { - var result = []; - sources = !_.isArray( sources ) ? [ sources ] : sources; - destinations = !_.isArray( destinations ) ? [destinations] : destinations; - _.each( sources, function ( source ) { - var sourceTopic = source.topic || "#"; - _.each( destinations, function ( destination ) { - var destChannel = destination.channel || postal.configuration.DEFAULT_CHANNEL; - result.push( - postal.subscribe( { - channel : source.channel || postal.configuration.DEFAULT_CHANNEL, - topic : sourceTopic, - callback : function ( data, env ) { - var newEnv = _.clone( env ); - newEnv.topic = _.isFunction( destination.topic ) ? destination.topic( env.topic ) : destination.topic || env.topic; - newEnv.channel = destChannel; - newEnv.data = data; - postal.publish( newEnv ); - } - } ) - ); - } ); - } ); - return result; - }, - - utils : { - getSubscribersFor : function () { - var channel = arguments[ 0 ], - tpc = arguments[ 1 ]; - if ( arguments.length === 1 ) { - channel = arguments[ 0 ].channel || postal.configuration.DEFAULT_CHANNEL; - tpc = arguments[ 0 ].topic; - } - if ( postal.configuration.bus.subscriptions[ channel ] && - Object.prototype.hasOwnProperty.call( postal.configuration.bus.subscriptions[ channel ], tpc ) ) { - return postal.configuration.bus.subscriptions[ channel ][ tpc ]; - } - return []; - }, - - reset : function () { - postal.configuration.bus.reset(); - postal.configuration.resolver.reset(); - } - } - }; - localBus.subscriptions[postal.configuration.SYSTEM_CHANNEL] = {}; + var postal; - /*jshint -W106 */ - if ( global && Object.prototype.hasOwnProperty.call( global, "__postalReady__" ) && _.isArray( global.__postalReady__ ) ) { - while(global.__postalReady__.length) { - global.__postalReady__.shift().onReady(postal); - } - } - /*jshint +W106 */ - return postal; -} )); \ No newline at end of file + var ConsecutiveDistinctPredicate = function () { + var previous; + return function (data) { + var eq = false; + if (_.isString(data)) { + eq = data === previous; + previous = data; + } + else { + eq = _.isEqual(data, previous); + previous = _.clone(data); + } + return !eq; + }; + }; + + var DistinctPredicate = function () { + var previous = []; + + return function (data) { + var isDistinct = !_.any(previous, function (p) { + if (_.isObject(data) || _.isArray(data)) { + return _.isEqual(data, p); + } + return data === p; + }); + if (isDistinct) { + previous.push(data); + } + return isDistinct; + }; + }; + + var ChannelDefinition = function (channelName) { + this.channel = channelName || postal.configuration.DEFAULT_CHANNEL; + }; + + ChannelDefinition.prototype.subscribe = function () { + return 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.configuration.bus.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."); + } + if (topic.length === 0) { + throw new Error("Topics cannot be empty"); + } + this.channel = channel; + this.topic = topic; + this.callback = callback; + this.constraints = []; + this.context = null; + postal.configuration.bus.publish({ + channel: postal.configuration.SYSTEM_CHANNEL, + topic: "subscription.created", + data: { + event: "subscription.created", + channel: channel, + topic: topic + } + }); + postal.configuration.bus.subscribe(this); + }; + + SubscriptionDefinition.prototype = { + unsubscribe: function () { + if (!this.inactive) { + this.inactive = true; + postal.configuration.bus.unsubscribe(this); + postal.configuration.bus.publish({ + channel: postal.configuration.SYSTEM_CHANNEL, + topic: "subscription.removed", + data: { + event: "subscription.removed", + channel: this.channel, + topic: this.topic + } + }); + } + }, + + defer: function () { + var self = this; + var fn = this.callback; + this.callback = function (data, env) { + setTimeout(function () { + fn.call(self.context, data, env); + }, 0); + }; + return this; + }, + + disposeAfter: function (maxCalls) { + 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; + }, + + distinctUntilChanged: function () { + this.withConstraint(new ConsecutiveDistinctPredicate()); + return this; + }, + + distinct: function () { + this.withConstraint(new DistinctPredicate()); + return this; + }, + + once: function () { + this.disposeAfter(1); + return this; + }, + + withConstraint: function (predicate) { + if (!_.isFunction(predicate)) { + throw "Predicate constraint must be a function"; + } + this.constraints.push(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; + return this; + }, + + withDebounce: function (milliseconds, immediate) { + if (_.isNaN(milliseconds)) { + throw "Milliseconds must be a number"; + } + var fn = this.callback; + this.callback = _.debounce(fn, milliseconds, !! immediate); + return this; + }, + + withDelay: function (milliseconds) { + 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); + }; + return this; + }, + + withThrottle: function (milliseconds) { + if (_.isNaN(milliseconds)) { + throw "Milliseconds must be a number"; + } + var fn = this.callback; + this.callback = _.throttle(fn, milliseconds); + return this; + }, + + subscribe: function (callback) { + this.callback = callback; + return this; + } + }; + + var bindingsResolver = { + cache: {}, + regex: {}, + + compare: function (binding, topic) { + var pattern, rgx, prevSegment, result = (this.cache[topic] && this.cache[topic][binding]); + if (typeof result !== "undefined") { + return result; + } + if (!(rgx = this.regex[binding])) { + pattern = "^" + _.map(binding.split("."), function (segment) { + var res = ""; + if ( !! prevSegment) { + res = prevSegment !== "#" ? "\\.\\b" : "\\b"; + } + if (segment === "#") { + res += "[\\s\\S]*"; + } else if (segment === "*") { + res += "[^.]+"; + } else { + res += segment; + } + prevSegment = segment; + return res; + }).join("") + "$"; + rgx = this.regex[binding] = new RegExp(pattern); + } + this.cache[topic] = this.cache[topic] || {}; + this.cache[topic][binding] = result = rgx.test(topic); + return result; + }, + + reset: function () { + this.cache = {}; + this.regex = {}; + } + }; + + 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); + } + } + } + }; + + var pubInProgress = 0; + var unSubQueue = []; + var clearUnSubQueue = function () { + while (unSubQueue.length) { + localBus.unsubscribe(unSubQueue.shift()); + } + }; + + var localBus = { + addWireTap: function (callback) { + var self = this; + self.wireTaps.push(callback); + return function () { + var idx = self.wireTaps.indexOf(callback); + if (idx !== -1) { + self.wireTaps.splice(idx, 1); + } + }; + }, + + publish: function (envelope) { + ++pubInProgress; + envelope.timeStamp = new Date(); + _.each(this.wireTaps, function (tap) { + tap(envelope.data, envelope); + }); + if (this.subscriptions[envelope.channel]) { + _.each(this.subscriptions[envelope.channel], function (subscribers) { + var idx = 0, + len = subscribers.length, + subDef; + while (idx < len) { + if (subDef = subscribers[idx++]) { + fireSub(subDef, envelope); + } + } + }); + } + if (--pubInProgress === 0) { + clearUnSubQueue(); + } + return envelope; + }, + + reset: function () { + if (this.subscriptions) { + _.each(this.subscriptions, function (channel) { + _.each(channel, function (topic) { + while (topic.length) { + topic.pop().unsubscribe(); + } + }); + }); + this.subscriptions = {}; + } + }, + + subscribe: function (subDef) { + var channel = this.subscriptions[subDef.channel], + subs; + if (!channel) { + channel = this.subscriptions[subDef.channel] = {}; + } + subs = this.subscriptions[subDef.channel][subDef.topic]; + if (!subs) { + subs = this.subscriptions[subDef.channel][subDef.topic] = []; + } + subs.push(subDef); + return subDef; + }, + + subscriptions: {}, + + wireTaps: [], + + unsubscribe: function (config) { + if (pubInProgress) { + unSubQueue.push(config); + return; + } + if (this.subscriptions[config.channel][config.topic]) { + var len = this.subscriptions[config.channel][config.topic].length, + idx = 0; + while (idx < len) { + if (this.subscriptions[config.channel][config.topic][idx] === config) { + this.subscriptions[config.channel][config.topic].splice(idx, 1); + break; + } + idx += 1; + } + } + } + }; + + + postal = { + configuration: { + bus: localBus, + resolver: bindingsResolver, + DEFAULT_CHANNEL: "/", + SYSTEM_CHANNEL: "postal" + }, + + ChannelDefinition: ChannelDefinition, + SubscriptionDefinition: SubscriptionDefinition, + + channel: function (channelName) { + return new ChannelDefinition(channelName); + }, + + subscribe: function (options) { + return new SubscriptionDefinition(options.channel || postal.configuration.DEFAULT_CHANNEL, options.topic, options.callback); + }, + + publish: function (envelope) { + envelope.channel = envelope.channel || postal.configuration.DEFAULT_CHANNEL; + return postal.configuration.bus.publish(envelope); + }, + + addWireTap: function (callback) { + return this.configuration.bus.addWireTap(callback); + }, + + linkChannels: function (sources, destinations) { + var result = []; + sources = !_.isArray(sources) ? [sources] : sources; + destinations = !_.isArray(destinations) ? [destinations] : destinations; + _.each(sources, function (source) { + var sourceTopic = source.topic || "#"; + _.each(destinations, function (destination) { + var destChannel = destination.channel || postal.configuration.DEFAULT_CHANNEL; + result.push( + postal.subscribe({ + channel: source.channel || postal.configuration.DEFAULT_CHANNEL, + topic: sourceTopic, + callback: function (data, env) { + var newEnv = _.clone(env); + newEnv.topic = _.isFunction(destination.topic) ? destination.topic(env.topic) : destination.topic || env.topic; + newEnv.channel = destChannel; + newEnv.data = data; + postal.publish(newEnv); + } + })); + }); + }); + return result; + }, + + utils: { + getSubscribersFor: function () { + var channel = arguments[0], + tpc = arguments[1]; + if (arguments.length === 1) { + channel = arguments[0].channel || postal.configuration.DEFAULT_CHANNEL; + tpc = arguments[0].topic; + } + if (postal.configuration.bus.subscriptions[channel] && Object.prototype.hasOwnProperty.call(postal.configuration.bus.subscriptions[channel], tpc)) { + return postal.configuration.bus.subscriptions[channel][tpc]; + } + return []; + }, + + reset: function () { + postal.configuration.bus.reset(); + postal.configuration.resolver.reset(); + } + } + }; + localBus.subscriptions[postal.configuration.SYSTEM_CHANNEL] = {}; + + + if (global && Object.prototype.hasOwnProperty.call(global, "__postalReady__") && _.isArray(global.__postalReady__)) { + while (global.__postalReady__.length) { + global.__postalReady__.shift().onReady(postal); + } + } + + + return postal; +})); \ No newline at end of file diff --git a/example/amd/js/libs/postal/postal.min.js b/example/amd/js/libs/postal/postal.min.js old mode 100755 new mode 100644 index 6c404db..8d37800 --- a/example/amd/js/libs/postal/postal.min.js +++ b/example/amd/js/libs/postal/postal.min.js @@ -1,7 +1,8 @@ -/* - postal - Author: Jim Cowart (http://freshbrewedcode.com/jimcowart) - License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license) - Version 0.8.11 +/** + * postal - Pub/Sub library providing wildcard subscriptions, complex message handling, etc. Works server and client-side. + * Author: Jim Cowart (http://freshbrewedcode.com/jimcowart) + * Version: v0.8.11 + * Url: http://github.com/postaljs/postal.js + * License: */ -(function(t,n){"object"==typeof module&&module.exports?module.exports=function(t){return t=t||require("underscore"),n(t)}:"function"==typeof define&&define.amd?define(["underscore"],function(i){return n(i,t)}):t.postal=n(t._,t)})(this,function(t,n){var i,s=function(){var n;return function(i){var s=!1;return t.isString(i)?(s=i===n,n=i):(s=t.isEqual(i,n),n=t.clone(i)),!s}},c=function(){var n=[];return function(i){var s=!t.any(n,function(n){return t.isObject(i)||t.isArray(i)?t.isEqual(i,n):i===n});return s&&n.push(i),s}},e=function(t){this.channel=t||i.configuration.DEFAULT_CHANNEL};e.prototype.subscribe=function(){return 1===arguments.length?new r(this.channel,arguments[0].topic,arguments[0].callback):new r(this.channel,arguments[0],arguments[1])},e.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.configuration.bus.publish(t)};var r=function(t,n,s){this.channel=t,this.topic=n,this.callback=s,this.constraints=[],this.context=null,i.configuration.bus.publish({channel:i.configuration.SYSTEM_CHANNEL,topic:"subscription.created",data:{event:"subscription.created",channel:t,topic:n}}),i.configuration.bus.subscribe(this)};r.prototype={unsubscribe:function(){this.inactive||(this.inactive=!0,i.configuration.bus.unsubscribe(this),i.configuration.bus.publish({channel:i.configuration.SYSTEM_CHANNEL,topic:"subscription.removed",data:{event:"subscription.removed",channel:this.channel,topic:this.topic}}))},defer:function(){var t=this,n=this.callback;return this.callback=function(i,s){setTimeout(function(){n.call(t.context,i,s)},0)},this},disposeAfter:function(n){if(t.isNaN(n)||0>=n)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var i=this,s=this.callback,c=t.after(n,t.bind(function(){this.unsubscribe()},this));return this.callback=function(){s.apply(i.context,arguments),c()},this},distinctUntilChanged:function(){return this.withConstraint(new s),this},distinct:function(){return this.withConstraint(new c),this},once:function(){return this.disposeAfter(1),this},withConstraint:function(n){if(!t.isFunction(n))throw"Predicate constraint must be a function";return this.constraints.push(n),this},withConstraints:function(n){var i=this;return t.isArray(n)&&t.each(n,function(t){i.withConstraint(t)}),i},withContext:function(t){return this.context=t,this},withDebounce:function(n,i){if(t.isNaN(n))throw"Milliseconds must be a number";var s=this.callback;return this.callback=t.debounce(s,n,!!i),this},withDelay:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this,s=this.callback;return this.callback=function(t,c){setTimeout(function(){s.call(i.context,t,c)},n)},this},withThrottle:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.throttle(i,n),this},subscribe:function(t){return this.callback=t,this}};var o={cache:{},regex:{},compare:function(n,i){var s,c,e,r=this.cache[i]&&this.cache[i][n];return r!==undefined?r:((c=this.regex[n])||(s="^"+t.map(n.split("."),function(t){var n="";return e&&(n="#"!==e?"\\.\\b":"\\b"),n+="#"===t?"[\\s\\S]*":"*"===t?"[^.]+":t,e=t,n}).join("")+"$",c=this.regex[n]=RegExp(s)),this.cache[i]=this.cache[i]||{},this.cache[i][n]=r=c.test(i),r)},reset:function(){this.cache={},this.regex={}}},a=function(n,s){!n.inactive&&i.configuration.resolver.compare(n.topic,s.topic)&&t.all(n.constraints,function(t){return t.call(n.context,s.data,s)})&&"function"==typeof n.callback&&n.callback.call(n.context,s.data,s)},u=0,h=[],l=function(){for(;h.length;)f.unsubscribe(h.shift())},f={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)}},publish:function(n){return++u,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,s=0,c=t.length;c>s;)(i=t[s++])&&a(i,n)}),0===--u&&l(),n},reset:function(){this.subscriptions&&(t.each(this.subscriptions,function(n){t.each(n,function(t){for(;t.length;)t.pop().unsubscribe()})}),this.subscriptions={})},subscribe:function(t){var n,i=this.subscriptions[t.channel];return i||(i=this.subscriptions[t.channel]={}),n=this.subscriptions[t.channel][t.topic],n||(n=this.subscriptions[t.channel][t.topic]=[]),n.push(t),t},subscriptions:{},wireTaps:[],unsubscribe:function(t){if(u)return h.push(t),undefined;if(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}}};if(i={configuration:{bus:f,resolver:o,DEFAULT_CHANNEL:"/",SYSTEM_CHANNEL:"postal"},ChannelDefinition:e,SubscriptionDefinition:r,channel:function(t){return new e(t)},subscribe:function(t){return new r(t.channel||i.configuration.DEFAULT_CHANNEL,t.topic,t.callback)},publish:function(t){return t.channel=t.channel||i.configuration.DEFAULT_CHANNEL,i.configuration.bus.publish(t)},addWireTap:function(t){return this.configuration.bus.addWireTap(t)},linkChannels:function(n,s){var c=[];return n=t.isArray(n)?n:[n],s=t.isArray(s)?s:[s],t.each(n,function(n){var e=n.topic||"#";t.each(s,function(s){var r=s.channel||i.configuration.DEFAULT_CHANNEL;c.push(i.subscribe({channel:n.channel||i.configuration.DEFAULT_CHANNEL,topic:e,callback:function(n,c){var e=t.clone(c);e.topic=t.isFunction(s.topic)?s.topic(c.topic):s.topic||c.topic,e.channel=r,e.data=n,i.publish(e)}}))})}),c},utils:{getSubscribersFor:function(){var t=arguments[0],n=arguments[1];return 1===arguments.length&&(t=arguments[0].channel||i.configuration.DEFAULT_CHANNEL,n=arguments[0].topic),i.configuration.bus.subscriptions[t]&&Object.prototype.hasOwnProperty.call(i.configuration.bus.subscriptions[t],n)?i.configuration.bus.subscriptions[t][n]:[]},reset:function(){i.configuration.bus.reset(),i.configuration.resolver.reset()}}},f.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=function(t){return t=t||require("underscore"),n(t)}:"function"==typeof define&&define.amd?define(["underscore"],function(i){return n(i,t)}):t.postal=n(t._,t)}(this,function(t,n){var i,s=function(){var n;return function(i){var s=!1;return t.isString(i)?(s=i===n,n=i):(s=t.isEqual(i,n),n=t.clone(i)),!s}},e=function(){var n=[];return function(i){var s=!t.any(n,function(n){return t.isObject(i)||t.isArray(i)?t.isEqual(i,n):i===n});return s&&n.push(i),s}},c=function(t){this.channel=t||i.configuration.DEFAULT_CHANNEL};c.prototype.subscribe=function(){return 1===arguments.length?new r(this.channel,arguments[0].topic,arguments[0].callback):new r(this.channel,arguments[0],arguments[1])},c.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.configuration.bus.publish(t)};var r=function(t,n,s){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.callback=s,this.constraints=[],this.context=null,i.configuration.bus.publish({channel:i.configuration.SYSTEM_CHANNEL,topic:"subscription.created",data:{event:"subscription.created",channel:t,topic:n}}),i.configuration.bus.subscribe(this)};r.prototype={unsubscribe:function(){this.inactive||(this.inactive=!0,i.configuration.bus.unsubscribe(this),i.configuration.bus.publish({channel:i.configuration.SYSTEM_CHANNEL,topic:"subscription.removed",data:{event:"subscription.removed",channel:this.channel,topic:this.topic}}))},defer:function(){var t=this,n=this.callback;return this.callback=function(i,s){setTimeout(function(){n.call(t.context,i,s)},0)},this},disposeAfter:function(n){if(t.isNaN(n)||0>=n)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var i=this,s=this.callback,e=t.after(n,t.bind(function(){this.unsubscribe()},this));return this.callback=function(){s.apply(i.context,arguments),e()},this},distinctUntilChanged:function(){return this.withConstraint(new s),this},distinct:function(){return this.withConstraint(new e),this},once:function(){return this.disposeAfter(1),this},withConstraint:function(n){if(!t.isFunction(n))throw"Predicate constraint must be a function";return this.constraints.push(n),this},withConstraints:function(n){var i=this;return t.isArray(n)&&t.each(n,function(t){i.withConstraint(t)}),i},withContext:function(t){return this.context=t,this},withDebounce:function(n,i){if(t.isNaN(n))throw"Milliseconds must be a number";var s=this.callback;return this.callback=t.debounce(s,n,!!i),this},withDelay:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this,s=this.callback;return this.callback=function(t,e){setTimeout(function(){s.call(i.context,t,e)},n)},this},withThrottle:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.throttle(i,n),this},subscribe:function(t){return this.callback=t,this}};var o={cache:{},regex:{},compare:function(n,i){var s,e,c,r=this.cache[i]&&this.cache[i][n];return"undefined"!=typeof r?r:((e=this.regex[n])||(s="^"+t.map(n.split("."),function(t){var n="";return c&&(n="#"!==c?"\\.\\b":"\\b"),n+="#"===t?"[\\s\\S]*":"*"===t?"[^.]+":t,c=t,n}).join("")+"$",e=this.regex[n]=new RegExp(s)),this.cache[i]=this.cache[i]||{},this.cache[i][n]=r=e.test(i),r)},reset:function(){this.cache={},this.regex={}}},a=function(n,s){!n.inactive&&i.configuration.resolver.compare(n.topic,s.topic)&&t.all(n.constraints,function(t){return t.call(n.context,s.data,s)})&&"function"==typeof n.callback&&n.callback.call(n.context,s.data,s)},u=0,h=[],l=function(){for(;h.length;)f.unsubscribe(h.shift())},f={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)}},publish:function(n){return++u,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,s=0,e=t.length;e>s;)(i=t[s++])&&a(i,n)}),0===--u&&l(),n},reset:function(){this.subscriptions&&(t.each(this.subscriptions,function(n){t.each(n,function(t){for(;t.length;)t.pop().unsubscribe()})}),this.subscriptions={})},subscribe:function(t){var n,i=this.subscriptions[t.channel];return i||(i=this.subscriptions[t.channel]={}),n=this.subscriptions[t.channel][t.topic],n||(n=this.subscriptions[t.channel][t.topic]=[]),n.push(t),t},subscriptions:{},wireTaps:[],unsubscribe:function(t){if(u)return h.push(t),void 0;if(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}}};if(i={configuration:{bus:f,resolver:o,DEFAULT_CHANNEL:"/",SYSTEM_CHANNEL:"postal"},ChannelDefinition:c,SubscriptionDefinition:r,channel:function(t){return new c(t)},subscribe:function(t){return new r(t.channel||i.configuration.DEFAULT_CHANNEL,t.topic,t.callback)},publish:function(t){return t.channel=t.channel||i.configuration.DEFAULT_CHANNEL,i.configuration.bus.publish(t)},addWireTap:function(t){return this.configuration.bus.addWireTap(t)},linkChannels:function(n,s){var e=[];return n=t.isArray(n)?n:[n],s=t.isArray(s)?s:[s],t.each(n,function(n){var c=n.topic||"#";t.each(s,function(s){var r=s.channel||i.configuration.DEFAULT_CHANNEL;e.push(i.subscribe({channel:n.channel||i.configuration.DEFAULT_CHANNEL,topic:c,callback:function(n,e){var c=t.clone(e);c.topic=t.isFunction(s.topic)?s.topic(e.topic):s.topic||e.topic,c.channel=r,c.data=n,i.publish(c)}}))})}),e},utils:{getSubscribersFor:function(){var t=arguments[0],n=arguments[1];return 1===arguments.length&&(t=arguments[0].channel||i.configuration.DEFAULT_CHANNEL,n=arguments[0].topic),i.configuration.bus.subscriptions[t]&&Object.prototype.hasOwnProperty.call(i.configuration.bus.subscriptions[t],n)?i.configuration.bus.subscriptions[t][n]:[]},reset:function(){i.configuration.bus.reset(),i.configuration.resolver.reset()}}},f.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/example/standard/js/postal.js b/example/standard/js/postal.js old mode 100755 new mode 100644 index 25ee641..0a03768 --- a/example/standard/js/postal.js +++ b/example/standard/js/postal.js @@ -1,450 +1,457 @@ -/* - postal - Author: Jim Cowart (http://freshbrewedcode.com/jimcowart) - License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license) - Version 0.8.11 +/** + * postal - Pub/Sub library providing wildcard subscriptions, complex message handling, etc. Works server and client-side. + * Author: Jim Cowart (http://freshbrewedcode.com/jimcowart) + * Version: v0.8.11 + * Url: http://github.com/postaljs/postal.js + * License: */ -/*jshint -W098 */ -(function ( root, factory ) { - if ( typeof module === "object" && module.exports ) { - // Node, or CommonJS-Like environments - module.exports = function ( _ ) { - _ = _ || require( "underscore" ); - return factory( _ ); - }; - } else if ( typeof define === "function" && define.amd ) { - // AMD. Register as an anonymous module. - define( ["underscore"], function ( _ ) { - return factory( _, root ); - } ); - } else { - // Browser globals - root.postal = factory( root._, root ); - } -}( this, function ( _, global, undefined ) { - var postal; +(function (root, factory) { + if (typeof module === "object" && module.exports) { + // Node, or CommonJS-Like environments + module.exports = function (_) { + _ = _ || require("underscore"); + return factory(_); + }; + } else if (typeof define === "function" && define.amd) { + // AMD. Register as an anonymous module. + define(["underscore"], function (_) { + return factory(_, root); + }); + } else { + // Browser globals + root.postal = factory(root._, root); + } +}(this, function (_, global, undefined) { - /*jshint -W098 */ - var ConsecutiveDistinctPredicate = function () { - var previous; - return function ( data ) { - var eq = false; - if ( _.isString( data ) ) { - eq = data === previous; - previous = data; - } - else { - eq = _.isEqual( data, previous ); - previous = _.clone( data ); - } - return !eq; - }; - }; - /*jshint -W098 */ - var DistinctPredicate = function () { - var previous = []; - - return function ( data ) { - var isDistinct = !_.any( previous, function ( p ) { - if ( _.isObject( data ) || _.isArray( data ) ) { - return _.isEqual( data, p ); - } - return data === p; - } ); - if ( isDistinct ) { - previous.push( data ); - } - return isDistinct; - }; - }; - /* global postal, SubscriptionDefinition */ - var ChannelDefinition = function ( channelName ) { - this.channel = channelName || postal.configuration.DEFAULT_CHANNEL; - }; - - ChannelDefinition.prototype.subscribe = function () { - return 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.configuration.bus.publish( envelope ); - }; - /* global postal */ - /*jshint -W117 */ - var SubscriptionDefinition = function ( channel, topic, callback ) { - this.channel = channel; - this.topic = topic; - this.callback = callback; - this.constraints = []; - this.context = null; - postal.configuration.bus.publish( { - channel : postal.configuration.SYSTEM_CHANNEL, - topic : "subscription.created", - data : { - event : "subscription.created", - channel : channel, - topic : topic - } - } ); - postal.configuration.bus.subscribe( this ); - }; - - SubscriptionDefinition.prototype = { - unsubscribe : function () { - if ( !this.inactive ) { - this.inactive = true; - postal.configuration.bus.unsubscribe( this ); - postal.configuration.bus.publish( { - channel : postal.configuration.SYSTEM_CHANNEL, - topic : "subscription.removed", - data : { - event : "subscription.removed", - channel : this.channel, - topic : this.topic - } - } ); - } - }, - - defer : function () { - var self = this; - var fn = this.callback; - this.callback = function ( data, env ) { - setTimeout( function () { - fn.call( self.context, data, env ); - }, 0 ); - }; - return this; - }, - - disposeAfter : function ( maxCalls ) { - 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; - }, - - distinctUntilChanged : function () { - this.withConstraint( new ConsecutiveDistinctPredicate() ); - return this; - }, - - distinct : function () { - this.withConstraint( new DistinctPredicate() ); - return this; - }, - - once : function () { - this.disposeAfter( 1 ); - return this; - }, - - withConstraint : function ( predicate ) { - if ( !_.isFunction( predicate ) ) { - throw "Predicate constraint must be a function"; - } - this.constraints.push( 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; - return this; - }, - - withDebounce : function ( milliseconds, immediate ) { - if ( _.isNaN( milliseconds ) ) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = _.debounce( fn, milliseconds, !!immediate ); - return this; - }, - - withDelay : function ( milliseconds ) { - 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 ); - }; - return this; - }, - - withThrottle : function ( milliseconds ) { - if ( _.isNaN( milliseconds ) ) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = _.throttle( fn, milliseconds ); - return this; - }, - - subscribe : function ( callback ) { - this.callback = callback; - return this; - } - }; - /*jshint -W098 */ - var bindingsResolver = { - cache : {}, - regex : {}, - - compare : function ( binding, topic ) { - var pattern, rgx, prevSegment, result = ( this.cache[ topic ] && this.cache[ topic ][ binding ] ); - if ( typeof result !== "undefined" ) { - return result; - } - if ( !( rgx = this.regex[ binding ] )) { - pattern = "^" + _.map( binding.split( "." ),function ( segment ) { - var res = ""; - if ( !!prevSegment ) { - res = prevSegment !== "#" ? "\\.\\b" : "\\b"; - } - if ( segment === "#" ) { - res += "[\\s\\S]*"; - } else if ( segment === "*" ) { - res += "[^.]+"; - } else { - res += segment; - } - prevSegment = segment; - return res; - } ).join( "" ) + "$"; - rgx = this.regex[ binding ] = new RegExp( pattern ); - } - this.cache[ topic ] = this.cache[ topic ] || {}; - this.cache[ topic ][ binding ] = result = rgx.test( topic ); - return result; - }, - - reset : function () { - this.cache = {}; - this.regex = {}; - } - }; - /* 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 ); - } - } - } - }; - - var pubInProgress = 0; - var unSubQueue = []; - var clearUnSubQueue = function () { - while ( unSubQueue.length ) { - localBus.unsubscribe(unSubQueue.shift()); - } - }; - - var localBus = { - addWireTap : function ( callback ) { - var self = this; - self.wireTaps.push( callback ); - return function () { - var idx = self.wireTaps.indexOf( callback ); - if ( idx !== -1 ) { - self.wireTaps.splice( idx, 1 ); - } - }; - }, - - publish : function ( envelope ) { - ++pubInProgress; - envelope.timeStamp = new Date(); - _.each( this.wireTaps, function ( tap ) { - tap( envelope.data, envelope ); - } ); - if ( this.subscriptions[envelope.channel] ) { - _.each( this.subscriptions[envelope.channel], function ( subscribers ) { - var idx = 0, len = subscribers.length, subDef; - while ( idx < len ) { - if ( subDef = subscribers[idx++] ) { - fireSub( subDef, envelope ); - } - } - } ); - } - if ( --pubInProgress === 0 ) { - clearUnSubQueue(); - } - return envelope; - }, - - reset : function () { - if ( this.subscriptions ) { - _.each( this.subscriptions, function ( channel ) { - _.each( channel, function ( topic ) { - while ( topic.length ) { - topic.pop().unsubscribe(); - } - } ); - } ); - this.subscriptions = {}; - } - }, - - subscribe : function ( subDef ) { - var channel = this.subscriptions[subDef.channel], subs; - if ( !channel ) { - channel = this.subscriptions[subDef.channel] = {}; - } - subs = this.subscriptions[subDef.channel][subDef.topic]; - if ( !subs ) { - subs = this.subscriptions[subDef.channel][subDef.topic] = []; - } - subs.push( subDef ); - return subDef; - }, - - subscriptions : {}, - - wireTaps : [], - - unsubscribe : function ( config ) { - if ( pubInProgress ) { - unSubQueue.push( config ); - return; - } - if ( this.subscriptions[config.channel][config.topic] ) { - var len = this.subscriptions[config.channel][config.topic].length, - idx = 0; - while ( idx < len ) { - if ( this.subscriptions[config.channel][config.topic][idx] === config ) { - this.subscriptions[config.channel][config.topic].splice( idx, 1 ); - break; - } - idx += 1; - } - } - } - }; - /* global localBus, bindingsResolver, ChannelDefinition, SubscriptionDefinition, postal */ - /*jshint -W020 */ - postal = { - configuration : { - bus : localBus, - resolver : bindingsResolver, - DEFAULT_CHANNEL : "/", - SYSTEM_CHANNEL : "postal" - }, - - ChannelDefinition : ChannelDefinition, - SubscriptionDefinition : SubscriptionDefinition, - - channel : function ( channelName ) { - return new ChannelDefinition( channelName ); - }, - - subscribe : function ( options ) { - return new SubscriptionDefinition( options.channel || postal.configuration.DEFAULT_CHANNEL, options.topic, options.callback ); - }, - - publish : function ( envelope ) { - envelope.channel = envelope.channel || postal.configuration.DEFAULT_CHANNEL; - return postal.configuration.bus.publish( envelope ); - }, - - addWireTap : function ( callback ) { - return this.configuration.bus.addWireTap( callback ); - }, - - linkChannels : function ( sources, destinations ) { - var result = []; - sources = !_.isArray( sources ) ? [ sources ] : sources; - destinations = !_.isArray( destinations ) ? [destinations] : destinations; - _.each( sources, function ( source ) { - var sourceTopic = source.topic || "#"; - _.each( destinations, function ( destination ) { - var destChannel = destination.channel || postal.configuration.DEFAULT_CHANNEL; - result.push( - postal.subscribe( { - channel : source.channel || postal.configuration.DEFAULT_CHANNEL, - topic : sourceTopic, - callback : function ( data, env ) { - var newEnv = _.clone( env ); - newEnv.topic = _.isFunction( destination.topic ) ? destination.topic( env.topic ) : destination.topic || env.topic; - newEnv.channel = destChannel; - newEnv.data = data; - postal.publish( newEnv ); - } - } ) - ); - } ); - } ); - return result; - }, - - utils : { - getSubscribersFor : function () { - var channel = arguments[ 0 ], - tpc = arguments[ 1 ]; - if ( arguments.length === 1 ) { - channel = arguments[ 0 ].channel || postal.configuration.DEFAULT_CHANNEL; - tpc = arguments[ 0 ].topic; - } - if ( postal.configuration.bus.subscriptions[ channel ] && - Object.prototype.hasOwnProperty.call( postal.configuration.bus.subscriptions[ channel ], tpc ) ) { - return postal.configuration.bus.subscriptions[ channel ][ tpc ]; - } - return []; - }, - - reset : function () { - postal.configuration.bus.reset(); - postal.configuration.resolver.reset(); - } - } - }; - localBus.subscriptions[postal.configuration.SYSTEM_CHANNEL] = {}; + var postal; - /*jshint -W106 */ - if ( global && Object.prototype.hasOwnProperty.call( global, "__postalReady__" ) && _.isArray( global.__postalReady__ ) ) { - while(global.__postalReady__.length) { - global.__postalReady__.shift().onReady(postal); - } - } - /*jshint +W106 */ - return postal; -} )); \ No newline at end of file + var ConsecutiveDistinctPredicate = function () { + var previous; + return function (data) { + var eq = false; + if (_.isString(data)) { + eq = data === previous; + previous = data; + } + else { + eq = _.isEqual(data, previous); + previous = _.clone(data); + } + return !eq; + }; + }; + + var DistinctPredicate = function () { + var previous = []; + + return function (data) { + var isDistinct = !_.any(previous, function (p) { + if (_.isObject(data) || _.isArray(data)) { + return _.isEqual(data, p); + } + return data === p; + }); + if (isDistinct) { + previous.push(data); + } + return isDistinct; + }; + }; + + var ChannelDefinition = function (channelName) { + this.channel = channelName || postal.configuration.DEFAULT_CHANNEL; + }; + + ChannelDefinition.prototype.subscribe = function () { + return 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.configuration.bus.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."); + } + if (topic.length === 0) { + throw new Error("Topics cannot be empty"); + } + this.channel = channel; + this.topic = topic; + this.callback = callback; + this.constraints = []; + this.context = null; + postal.configuration.bus.publish({ + channel: postal.configuration.SYSTEM_CHANNEL, + topic: "subscription.created", + data: { + event: "subscription.created", + channel: channel, + topic: topic + } + }); + postal.configuration.bus.subscribe(this); + }; + + SubscriptionDefinition.prototype = { + unsubscribe: function () { + if (!this.inactive) { + this.inactive = true; + postal.configuration.bus.unsubscribe(this); + postal.configuration.bus.publish({ + channel: postal.configuration.SYSTEM_CHANNEL, + topic: "subscription.removed", + data: { + event: "subscription.removed", + channel: this.channel, + topic: this.topic + } + }); + } + }, + + defer: function () { + var self = this; + var fn = this.callback; + this.callback = function (data, env) { + setTimeout(function () { + fn.call(self.context, data, env); + }, 0); + }; + return this; + }, + + disposeAfter: function (maxCalls) { + 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; + }, + + distinctUntilChanged: function () { + this.withConstraint(new ConsecutiveDistinctPredicate()); + return this; + }, + + distinct: function () { + this.withConstraint(new DistinctPredicate()); + return this; + }, + + once: function () { + this.disposeAfter(1); + return this; + }, + + withConstraint: function (predicate) { + if (!_.isFunction(predicate)) { + throw "Predicate constraint must be a function"; + } + this.constraints.push(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; + return this; + }, + + withDebounce: function (milliseconds, immediate) { + if (_.isNaN(milliseconds)) { + throw "Milliseconds must be a number"; + } + var fn = this.callback; + this.callback = _.debounce(fn, milliseconds, !! immediate); + return this; + }, + + withDelay: function (milliseconds) { + 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); + }; + return this; + }, + + withThrottle: function (milliseconds) { + if (_.isNaN(milliseconds)) { + throw "Milliseconds must be a number"; + } + var fn = this.callback; + this.callback = _.throttle(fn, milliseconds); + return this; + }, + + subscribe: function (callback) { + this.callback = callback; + return this; + } + }; + + var bindingsResolver = { + cache: {}, + regex: {}, + + compare: function (binding, topic) { + var pattern, rgx, prevSegment, result = (this.cache[topic] && this.cache[topic][binding]); + if (typeof result !== "undefined") { + return result; + } + if (!(rgx = this.regex[binding])) { + pattern = "^" + _.map(binding.split("."), function (segment) { + var res = ""; + if ( !! prevSegment) { + res = prevSegment !== "#" ? "\\.\\b" : "\\b"; + } + if (segment === "#") { + res += "[\\s\\S]*"; + } else if (segment === "*") { + res += "[^.]+"; + } else { + res += segment; + } + prevSegment = segment; + return res; + }).join("") + "$"; + rgx = this.regex[binding] = new RegExp(pattern); + } + this.cache[topic] = this.cache[topic] || {}; + this.cache[topic][binding] = result = rgx.test(topic); + return result; + }, + + reset: function () { + this.cache = {}; + this.regex = {}; + } + }; + + 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); + } + } + } + }; + + var pubInProgress = 0; + var unSubQueue = []; + var clearUnSubQueue = function () { + while (unSubQueue.length) { + localBus.unsubscribe(unSubQueue.shift()); + } + }; + + var localBus = { + addWireTap: function (callback) { + var self = this; + self.wireTaps.push(callback); + return function () { + var idx = self.wireTaps.indexOf(callback); + if (idx !== -1) { + self.wireTaps.splice(idx, 1); + } + }; + }, + + publish: function (envelope) { + ++pubInProgress; + envelope.timeStamp = new Date(); + _.each(this.wireTaps, function (tap) { + tap(envelope.data, envelope); + }); + if (this.subscriptions[envelope.channel]) { + _.each(this.subscriptions[envelope.channel], function (subscribers) { + var idx = 0, + len = subscribers.length, + subDef; + while (idx < len) { + if (subDef = subscribers[idx++]) { + fireSub(subDef, envelope); + } + } + }); + } + if (--pubInProgress === 0) { + clearUnSubQueue(); + } + return envelope; + }, + + reset: function () { + if (this.subscriptions) { + _.each(this.subscriptions, function (channel) { + _.each(channel, function (topic) { + while (topic.length) { + topic.pop().unsubscribe(); + } + }); + }); + this.subscriptions = {}; + } + }, + + subscribe: function (subDef) { + var channel = this.subscriptions[subDef.channel], + subs; + if (!channel) { + channel = this.subscriptions[subDef.channel] = {}; + } + subs = this.subscriptions[subDef.channel][subDef.topic]; + if (!subs) { + subs = this.subscriptions[subDef.channel][subDef.topic] = []; + } + subs.push(subDef); + return subDef; + }, + + subscriptions: {}, + + wireTaps: [], + + unsubscribe: function (config) { + if (pubInProgress) { + unSubQueue.push(config); + return; + } + if (this.subscriptions[config.channel][config.topic]) { + var len = this.subscriptions[config.channel][config.topic].length, + idx = 0; + while (idx < len) { + if (this.subscriptions[config.channel][config.topic][idx] === config) { + this.subscriptions[config.channel][config.topic].splice(idx, 1); + break; + } + idx += 1; + } + } + } + }; + + + postal = { + configuration: { + bus: localBus, + resolver: bindingsResolver, + DEFAULT_CHANNEL: "/", + SYSTEM_CHANNEL: "postal" + }, + + ChannelDefinition: ChannelDefinition, + SubscriptionDefinition: SubscriptionDefinition, + + channel: function (channelName) { + return new ChannelDefinition(channelName); + }, + + subscribe: function (options) { + return new SubscriptionDefinition(options.channel || postal.configuration.DEFAULT_CHANNEL, options.topic, options.callback); + }, + + publish: function (envelope) { + envelope.channel = envelope.channel || postal.configuration.DEFAULT_CHANNEL; + return postal.configuration.bus.publish(envelope); + }, + + addWireTap: function (callback) { + return this.configuration.bus.addWireTap(callback); + }, + + linkChannels: function (sources, destinations) { + var result = []; + sources = !_.isArray(sources) ? [sources] : sources; + destinations = !_.isArray(destinations) ? [destinations] : destinations; + _.each(sources, function (source) { + var sourceTopic = source.topic || "#"; + _.each(destinations, function (destination) { + var destChannel = destination.channel || postal.configuration.DEFAULT_CHANNEL; + result.push( + postal.subscribe({ + channel: source.channel || postal.configuration.DEFAULT_CHANNEL, + topic: sourceTopic, + callback: function (data, env) { + var newEnv = _.clone(env); + newEnv.topic = _.isFunction(destination.topic) ? destination.topic(env.topic) : destination.topic || env.topic; + newEnv.channel = destChannel; + newEnv.data = data; + postal.publish(newEnv); + } + })); + }); + }); + return result; + }, + + utils: { + getSubscribersFor: function () { + var channel = arguments[0], + tpc = arguments[1]; + if (arguments.length === 1) { + channel = arguments[0].channel || postal.configuration.DEFAULT_CHANNEL; + tpc = arguments[0].topic; + } + if (postal.configuration.bus.subscriptions[channel] && Object.prototype.hasOwnProperty.call(postal.configuration.bus.subscriptions[channel], tpc)) { + return postal.configuration.bus.subscriptions[channel][tpc]; + } + return []; + }, + + reset: function () { + postal.configuration.bus.reset(); + postal.configuration.resolver.reset(); + } + } + }; + localBus.subscriptions[postal.configuration.SYSTEM_CHANNEL] = {}; + + + if (global && Object.prototype.hasOwnProperty.call(global, "__postalReady__") && _.isArray(global.__postalReady__)) { + while (global.__postalReady__.length) { + global.__postalReady__.shift().onReady(postal); + } + } + + + return postal; +})); \ No newline at end of file diff --git a/example/standard/js/postal.min.js b/example/standard/js/postal.min.js old mode 100755 new mode 100644 index 6c404db..8d37800 --- a/example/standard/js/postal.min.js +++ b/example/standard/js/postal.min.js @@ -1,7 +1,8 @@ -/* - postal - Author: Jim Cowart (http://freshbrewedcode.com/jimcowart) - License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license) - Version 0.8.11 +/** + * postal - Pub/Sub library providing wildcard subscriptions, complex message handling, etc. Works server and client-side. + * Author: Jim Cowart (http://freshbrewedcode.com/jimcowart) + * Version: v0.8.11 + * Url: http://github.com/postaljs/postal.js + * License: */ -(function(t,n){"object"==typeof module&&module.exports?module.exports=function(t){return t=t||require("underscore"),n(t)}:"function"==typeof define&&define.amd?define(["underscore"],function(i){return n(i,t)}):t.postal=n(t._,t)})(this,function(t,n){var i,s=function(){var n;return function(i){var s=!1;return t.isString(i)?(s=i===n,n=i):(s=t.isEqual(i,n),n=t.clone(i)),!s}},c=function(){var n=[];return function(i){var s=!t.any(n,function(n){return t.isObject(i)||t.isArray(i)?t.isEqual(i,n):i===n});return s&&n.push(i),s}},e=function(t){this.channel=t||i.configuration.DEFAULT_CHANNEL};e.prototype.subscribe=function(){return 1===arguments.length?new r(this.channel,arguments[0].topic,arguments[0].callback):new r(this.channel,arguments[0],arguments[1])},e.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.configuration.bus.publish(t)};var r=function(t,n,s){this.channel=t,this.topic=n,this.callback=s,this.constraints=[],this.context=null,i.configuration.bus.publish({channel:i.configuration.SYSTEM_CHANNEL,topic:"subscription.created",data:{event:"subscription.created",channel:t,topic:n}}),i.configuration.bus.subscribe(this)};r.prototype={unsubscribe:function(){this.inactive||(this.inactive=!0,i.configuration.bus.unsubscribe(this),i.configuration.bus.publish({channel:i.configuration.SYSTEM_CHANNEL,topic:"subscription.removed",data:{event:"subscription.removed",channel:this.channel,topic:this.topic}}))},defer:function(){var t=this,n=this.callback;return this.callback=function(i,s){setTimeout(function(){n.call(t.context,i,s)},0)},this},disposeAfter:function(n){if(t.isNaN(n)||0>=n)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var i=this,s=this.callback,c=t.after(n,t.bind(function(){this.unsubscribe()},this));return this.callback=function(){s.apply(i.context,arguments),c()},this},distinctUntilChanged:function(){return this.withConstraint(new s),this},distinct:function(){return this.withConstraint(new c),this},once:function(){return this.disposeAfter(1),this},withConstraint:function(n){if(!t.isFunction(n))throw"Predicate constraint must be a function";return this.constraints.push(n),this},withConstraints:function(n){var i=this;return t.isArray(n)&&t.each(n,function(t){i.withConstraint(t)}),i},withContext:function(t){return this.context=t,this},withDebounce:function(n,i){if(t.isNaN(n))throw"Milliseconds must be a number";var s=this.callback;return this.callback=t.debounce(s,n,!!i),this},withDelay:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this,s=this.callback;return this.callback=function(t,c){setTimeout(function(){s.call(i.context,t,c)},n)},this},withThrottle:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.throttle(i,n),this},subscribe:function(t){return this.callback=t,this}};var o={cache:{},regex:{},compare:function(n,i){var s,c,e,r=this.cache[i]&&this.cache[i][n];return r!==undefined?r:((c=this.regex[n])||(s="^"+t.map(n.split("."),function(t){var n="";return e&&(n="#"!==e?"\\.\\b":"\\b"),n+="#"===t?"[\\s\\S]*":"*"===t?"[^.]+":t,e=t,n}).join("")+"$",c=this.regex[n]=RegExp(s)),this.cache[i]=this.cache[i]||{},this.cache[i][n]=r=c.test(i),r)},reset:function(){this.cache={},this.regex={}}},a=function(n,s){!n.inactive&&i.configuration.resolver.compare(n.topic,s.topic)&&t.all(n.constraints,function(t){return t.call(n.context,s.data,s)})&&"function"==typeof n.callback&&n.callback.call(n.context,s.data,s)},u=0,h=[],l=function(){for(;h.length;)f.unsubscribe(h.shift())},f={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)}},publish:function(n){return++u,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,s=0,c=t.length;c>s;)(i=t[s++])&&a(i,n)}),0===--u&&l(),n},reset:function(){this.subscriptions&&(t.each(this.subscriptions,function(n){t.each(n,function(t){for(;t.length;)t.pop().unsubscribe()})}),this.subscriptions={})},subscribe:function(t){var n,i=this.subscriptions[t.channel];return i||(i=this.subscriptions[t.channel]={}),n=this.subscriptions[t.channel][t.topic],n||(n=this.subscriptions[t.channel][t.topic]=[]),n.push(t),t},subscriptions:{},wireTaps:[],unsubscribe:function(t){if(u)return h.push(t),undefined;if(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}}};if(i={configuration:{bus:f,resolver:o,DEFAULT_CHANNEL:"/",SYSTEM_CHANNEL:"postal"},ChannelDefinition:e,SubscriptionDefinition:r,channel:function(t){return new e(t)},subscribe:function(t){return new r(t.channel||i.configuration.DEFAULT_CHANNEL,t.topic,t.callback)},publish:function(t){return t.channel=t.channel||i.configuration.DEFAULT_CHANNEL,i.configuration.bus.publish(t)},addWireTap:function(t){return this.configuration.bus.addWireTap(t)},linkChannels:function(n,s){var c=[];return n=t.isArray(n)?n:[n],s=t.isArray(s)?s:[s],t.each(n,function(n){var e=n.topic||"#";t.each(s,function(s){var r=s.channel||i.configuration.DEFAULT_CHANNEL;c.push(i.subscribe({channel:n.channel||i.configuration.DEFAULT_CHANNEL,topic:e,callback:function(n,c){var e=t.clone(c);e.topic=t.isFunction(s.topic)?s.topic(c.topic):s.topic||c.topic,e.channel=r,e.data=n,i.publish(e)}}))})}),c},utils:{getSubscribersFor:function(){var t=arguments[0],n=arguments[1];return 1===arguments.length&&(t=arguments[0].channel||i.configuration.DEFAULT_CHANNEL,n=arguments[0].topic),i.configuration.bus.subscriptions[t]&&Object.prototype.hasOwnProperty.call(i.configuration.bus.subscriptions[t],n)?i.configuration.bus.subscriptions[t][n]:[]},reset:function(){i.configuration.bus.reset(),i.configuration.resolver.reset()}}},f.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=function(t){return t=t||require("underscore"),n(t)}:"function"==typeof define&&define.amd?define(["underscore"],function(i){return n(i,t)}):t.postal=n(t._,t)}(this,function(t,n){var i,s=function(){var n;return function(i){var s=!1;return t.isString(i)?(s=i===n,n=i):(s=t.isEqual(i,n),n=t.clone(i)),!s}},e=function(){var n=[];return function(i){var s=!t.any(n,function(n){return t.isObject(i)||t.isArray(i)?t.isEqual(i,n):i===n});return s&&n.push(i),s}},c=function(t){this.channel=t||i.configuration.DEFAULT_CHANNEL};c.prototype.subscribe=function(){return 1===arguments.length?new r(this.channel,arguments[0].topic,arguments[0].callback):new r(this.channel,arguments[0],arguments[1])},c.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.configuration.bus.publish(t)};var r=function(t,n,s){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.callback=s,this.constraints=[],this.context=null,i.configuration.bus.publish({channel:i.configuration.SYSTEM_CHANNEL,topic:"subscription.created",data:{event:"subscription.created",channel:t,topic:n}}),i.configuration.bus.subscribe(this)};r.prototype={unsubscribe:function(){this.inactive||(this.inactive=!0,i.configuration.bus.unsubscribe(this),i.configuration.bus.publish({channel:i.configuration.SYSTEM_CHANNEL,topic:"subscription.removed",data:{event:"subscription.removed",channel:this.channel,topic:this.topic}}))},defer:function(){var t=this,n=this.callback;return this.callback=function(i,s){setTimeout(function(){n.call(t.context,i,s)},0)},this},disposeAfter:function(n){if(t.isNaN(n)||0>=n)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var i=this,s=this.callback,e=t.after(n,t.bind(function(){this.unsubscribe()},this));return this.callback=function(){s.apply(i.context,arguments),e()},this},distinctUntilChanged:function(){return this.withConstraint(new s),this},distinct:function(){return this.withConstraint(new e),this},once:function(){return this.disposeAfter(1),this},withConstraint:function(n){if(!t.isFunction(n))throw"Predicate constraint must be a function";return this.constraints.push(n),this},withConstraints:function(n){var i=this;return t.isArray(n)&&t.each(n,function(t){i.withConstraint(t)}),i},withContext:function(t){return this.context=t,this},withDebounce:function(n,i){if(t.isNaN(n))throw"Milliseconds must be a number";var s=this.callback;return this.callback=t.debounce(s,n,!!i),this},withDelay:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this,s=this.callback;return this.callback=function(t,e){setTimeout(function(){s.call(i.context,t,e)},n)},this},withThrottle:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.throttle(i,n),this},subscribe:function(t){return this.callback=t,this}};var o={cache:{},regex:{},compare:function(n,i){var s,e,c,r=this.cache[i]&&this.cache[i][n];return"undefined"!=typeof r?r:((e=this.regex[n])||(s="^"+t.map(n.split("."),function(t){var n="";return c&&(n="#"!==c?"\\.\\b":"\\b"),n+="#"===t?"[\\s\\S]*":"*"===t?"[^.]+":t,c=t,n}).join("")+"$",e=this.regex[n]=new RegExp(s)),this.cache[i]=this.cache[i]||{},this.cache[i][n]=r=e.test(i),r)},reset:function(){this.cache={},this.regex={}}},a=function(n,s){!n.inactive&&i.configuration.resolver.compare(n.topic,s.topic)&&t.all(n.constraints,function(t){return t.call(n.context,s.data,s)})&&"function"==typeof n.callback&&n.callback.call(n.context,s.data,s)},u=0,h=[],l=function(){for(;h.length;)f.unsubscribe(h.shift())},f={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)}},publish:function(n){return++u,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,s=0,e=t.length;e>s;)(i=t[s++])&&a(i,n)}),0===--u&&l(),n},reset:function(){this.subscriptions&&(t.each(this.subscriptions,function(n){t.each(n,function(t){for(;t.length;)t.pop().unsubscribe()})}),this.subscriptions={})},subscribe:function(t){var n,i=this.subscriptions[t.channel];return i||(i=this.subscriptions[t.channel]={}),n=this.subscriptions[t.channel][t.topic],n||(n=this.subscriptions[t.channel][t.topic]=[]),n.push(t),t},subscriptions:{},wireTaps:[],unsubscribe:function(t){if(u)return h.push(t),void 0;if(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}}};if(i={configuration:{bus:f,resolver:o,DEFAULT_CHANNEL:"/",SYSTEM_CHANNEL:"postal"},ChannelDefinition:c,SubscriptionDefinition:r,channel:function(t){return new c(t)},subscribe:function(t){return new r(t.channel||i.configuration.DEFAULT_CHANNEL,t.topic,t.callback)},publish:function(t){return t.channel=t.channel||i.configuration.DEFAULT_CHANNEL,i.configuration.bus.publish(t)},addWireTap:function(t){return this.configuration.bus.addWireTap(t)},linkChannels:function(n,s){var e=[];return n=t.isArray(n)?n:[n],s=t.isArray(s)?s:[s],t.each(n,function(n){var c=n.topic||"#";t.each(s,function(s){var r=s.channel||i.configuration.DEFAULT_CHANNEL;e.push(i.subscribe({channel:n.channel||i.configuration.DEFAULT_CHANNEL,topic:c,callback:function(n,e){var c=t.clone(e);c.topic=t.isFunction(s.topic)?s.topic(e.topic):s.topic||e.topic,c.channel=r,c.data=n,i.publish(c)}}))})}),e},utils:{getSubscribersFor:function(){var t=arguments[0],n=arguments[1];return 1===arguments.length&&(t=arguments[0].channel||i.configuration.DEFAULT_CHANNEL,n=arguments[0].topic),i.configuration.bus.subscriptions[t]&&Object.prototype.hasOwnProperty.call(i.configuration.bus.subscriptions[t],n)?i.configuration.bus.subscriptions[t][n]:[]},reset:function(){i.configuration.bus.reset(),i.configuration.resolver.reset()}}},f.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/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..353de92 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,34 @@ +var gulp = require("gulp"); +var fileImports = require("gulp-imports"); +var pkg = require("./package.json"); +var header = require("gulp-header"); +var beautify = require("gulp-beautify"); +var hintNot = require("gulp-hint-not"); +var uglify = require("gulp-uglify"); +var rename = require("gulp-rename"); + +var banner = ["/**", + " * <%= pkg.name %> - <%= pkg.description %>", + " * Author: <%= pkg.author %>", + " * Version: v<%= pkg.version %>", + " * Url: <%= pkg.homepage %>", + " * License: <%= pkg.license %>", + " */", + ""].join("\n"); + +gulp.task("combine", function() { + gulp.src(["./src/postal.js"]) + .pipe(header(banner, { pkg : pkg })) + .pipe(fileImports()) + .pipe(hintNot()) + .pipe(beautify({indentSize: 4})) + .pipe(gulp.dest("./lib/")) + .pipe(uglify()) + .pipe(header(banner, { pkg : pkg })) + .pipe(rename("postal.min.js")) + .pipe(gulp.dest("./lib/")); +}); + +gulp.task("default", function() { + gulp.run("combine"); +}); \ No newline at end of file diff --git a/lib/postal.js b/lib/postal.js old mode 100755 new mode 100644 index 78d3c80..0a03768 --- a/lib/postal.js +++ b/lib/postal.js @@ -1,456 +1,457 @@ -/* - postal - Author: Jim Cowart (http://freshbrewedcode.com/jimcowart) - License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license) - Version 0.8.11 +/** + * postal - Pub/Sub library providing wildcard subscriptions, complex message handling, etc. Works server and client-side. + * Author: Jim Cowart (http://freshbrewedcode.com/jimcowart) + * Version: v0.8.11 + * Url: http://github.com/postaljs/postal.js + * License: */ -/*jshint -W098 */ -(function ( root, factory ) { - if ( typeof module === "object" && module.exports ) { - // Node, or CommonJS-Like environments - module.exports = function ( _ ) { - _ = _ || require( "underscore" ); - return factory( _ ); - }; - } else if ( typeof define === "function" && define.amd ) { - // AMD. Register as an anonymous module. - define( ["underscore"], function ( _ ) { - return factory( _, root ); - } ); - } else { - // Browser globals - root.postal = factory( root._, root ); - } -}( this, function ( _, global, undefined ) { - var postal; +(function (root, factory) { + if (typeof module === "object" && module.exports) { + // Node, or CommonJS-Like environments + module.exports = function (_) { + _ = _ || require("underscore"); + return factory(_); + }; + } else if (typeof define === "function" && define.amd) { + // AMD. Register as an anonymous module. + define(["underscore"], function (_) { + return factory(_, root); + }); + } else { + // Browser globals + root.postal = factory(root._, root); + } +}(this, function (_, global, undefined) { - /*jshint -W098 */ - var ConsecutiveDistinctPredicate = function () { - var previous; - return function ( data ) { - var eq = false; - if ( _.isString( data ) ) { - eq = data === previous; - previous = data; - } - else { - eq = _.isEqual( data, previous ); - previous = _.clone( data ); - } - return !eq; - }; - }; - /*jshint -W098 */ - var DistinctPredicate = function () { - var previous = []; - - return function ( data ) { - var isDistinct = !_.any( previous, function ( p ) { - if ( _.isObject( data ) || _.isArray( data ) ) { - return _.isEqual( data, p ); - } - return data === p; - } ); - if ( isDistinct ) { - previous.push( data ); - } - return isDistinct; - }; - }; - /* global postal, SubscriptionDefinition */ - var ChannelDefinition = function ( channelName ) { - this.channel = channelName || postal.configuration.DEFAULT_CHANNEL; - }; - - ChannelDefinition.prototype.subscribe = function () { - return 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.configuration.bus.publish( envelope ); - }; - /* global postal */ - /*jshint -W117 */ - 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."); - } - if(topic.length === 0) { - throw new Error("Topics cannot be empty"); - } - this.channel = channel; - this.topic = topic; - this.callback = callback; - this.constraints = []; - this.context = null; - postal.configuration.bus.publish( { - channel : postal.configuration.SYSTEM_CHANNEL, - topic : "subscription.created", - data : { - event : "subscription.created", - channel : channel, - topic : topic - } - } ); - postal.configuration.bus.subscribe( this ); - }; - - SubscriptionDefinition.prototype = { - unsubscribe : function () { - if ( !this.inactive ) { - this.inactive = true; - postal.configuration.bus.unsubscribe( this ); - postal.configuration.bus.publish( { - channel : postal.configuration.SYSTEM_CHANNEL, - topic : "subscription.removed", - data : { - event : "subscription.removed", - channel : this.channel, - topic : this.topic - } - } ); - } - }, - - defer : function () { - var self = this; - var fn = this.callback; - this.callback = function ( data, env ) { - setTimeout( function () { - fn.call( self.context, data, env ); - }, 0 ); - }; - return this; - }, - - disposeAfter : function ( maxCalls ) { - 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; - }, - - distinctUntilChanged : function () { - this.withConstraint( new ConsecutiveDistinctPredicate() ); - return this; - }, - - distinct : function () { - this.withConstraint( new DistinctPredicate() ); - return this; - }, - - once : function () { - this.disposeAfter( 1 ); - return this; - }, - - withConstraint : function ( predicate ) { - if ( !_.isFunction( predicate ) ) { - throw "Predicate constraint must be a function"; - } - this.constraints.push( 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; - return this; - }, - - withDebounce : function ( milliseconds, immediate ) { - if ( _.isNaN( milliseconds ) ) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = _.debounce( fn, milliseconds, !!immediate ); - return this; - }, - - withDelay : function ( milliseconds ) { - 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 ); - }; - return this; - }, - - withThrottle : function ( milliseconds ) { - if ( _.isNaN( milliseconds ) ) { - throw "Milliseconds must be a number"; - } - var fn = this.callback; - this.callback = _.throttle( fn, milliseconds ); - return this; - }, - - subscribe : function ( callback ) { - this.callback = callback; - return this; - } - }; - /*jshint -W098 */ - var bindingsResolver = { - cache : {}, - regex : {}, - - compare : function ( binding, topic ) { - var pattern, rgx, prevSegment, result = ( this.cache[ topic ] && this.cache[ topic ][ binding ] ); - if ( typeof result !== "undefined" ) { - return result; - } - if ( !( rgx = this.regex[ binding ] )) { - pattern = "^" + _.map( binding.split( "." ),function ( segment ) { - var res = ""; - if ( !!prevSegment ) { - res = prevSegment !== "#" ? "\\.\\b" : "\\b"; - } - if ( segment === "#" ) { - res += "[\\s\\S]*"; - } else if ( segment === "*" ) { - res += "[^.]+"; - } else { - res += segment; - } - prevSegment = segment; - return res; - } ).join( "" ) + "$"; - rgx = this.regex[ binding ] = new RegExp( pattern ); - } - this.cache[ topic ] = this.cache[ topic ] || {}; - this.cache[ topic ][ binding ] = result = rgx.test( topic ); - return result; - }, - - reset : function () { - this.cache = {}; - this.regex = {}; - } - }; - /* 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 ); - } - } - } - }; - - var pubInProgress = 0; - var unSubQueue = []; - var clearUnSubQueue = function () { - while ( unSubQueue.length ) { - localBus.unsubscribe(unSubQueue.shift()); - } - }; - - var localBus = { - addWireTap : function ( callback ) { - var self = this; - self.wireTaps.push( callback ); - return function () { - var idx = self.wireTaps.indexOf( callback ); - if ( idx !== -1 ) { - self.wireTaps.splice( idx, 1 ); - } - }; - }, - - publish : function ( envelope ) { - ++pubInProgress; - envelope.timeStamp = new Date(); - _.each( this.wireTaps, function ( tap ) { - tap( envelope.data, envelope ); - } ); - if ( this.subscriptions[envelope.channel] ) { - _.each( this.subscriptions[envelope.channel], function ( subscribers ) { - var idx = 0, len = subscribers.length, subDef; - while ( idx < len ) { - if ( subDef = subscribers[idx++] ) { - fireSub( subDef, envelope ); - } - } - } ); - } - if ( --pubInProgress === 0 ) { - clearUnSubQueue(); - } - return envelope; - }, - - reset : function () { - if ( this.subscriptions ) { - _.each( this.subscriptions, function ( channel ) { - _.each( channel, function ( topic ) { - while ( topic.length ) { - topic.pop().unsubscribe(); - } - } ); - } ); - this.subscriptions = {}; - } - }, - - subscribe : function ( subDef ) { - var channel = this.subscriptions[subDef.channel], subs; - if ( !channel ) { - channel = this.subscriptions[subDef.channel] = {}; - } - subs = this.subscriptions[subDef.channel][subDef.topic]; - if ( !subs ) { - subs = this.subscriptions[subDef.channel][subDef.topic] = []; - } - subs.push( subDef ); - return subDef; - }, - - subscriptions : {}, - - wireTaps : [], - - unsubscribe : function ( config ) { - if ( pubInProgress ) { - unSubQueue.push( config ); - return; - } - if ( this.subscriptions[config.channel][config.topic] ) { - var len = this.subscriptions[config.channel][config.topic].length, - idx = 0; - while ( idx < len ) { - if ( this.subscriptions[config.channel][config.topic][idx] === config ) { - this.subscriptions[config.channel][config.topic].splice( idx, 1 ); - break; - } - idx += 1; - } - } - } - }; - /* global localBus, bindingsResolver, ChannelDefinition, SubscriptionDefinition, postal */ - /*jshint -W020 */ - postal = { - configuration : { - bus : localBus, - resolver : bindingsResolver, - DEFAULT_CHANNEL : "/", - SYSTEM_CHANNEL : "postal" - }, - - ChannelDefinition : ChannelDefinition, - SubscriptionDefinition : SubscriptionDefinition, - - channel : function ( channelName ) { - return new ChannelDefinition( channelName ); - }, - - subscribe : function ( options ) { - return new SubscriptionDefinition( options.channel || postal.configuration.DEFAULT_CHANNEL, options.topic, options.callback ); - }, - - publish : function ( envelope ) { - envelope.channel = envelope.channel || postal.configuration.DEFAULT_CHANNEL; - return postal.configuration.bus.publish( envelope ); - }, - - addWireTap : function ( callback ) { - return this.configuration.bus.addWireTap( callback ); - }, - - linkChannels : function ( sources, destinations ) { - var result = []; - sources = !_.isArray( sources ) ? [ sources ] : sources; - destinations = !_.isArray( destinations ) ? [destinations] : destinations; - _.each( sources, function ( source ) { - var sourceTopic = source.topic || "#"; - _.each( destinations, function ( destination ) { - var destChannel = destination.channel || postal.configuration.DEFAULT_CHANNEL; - result.push( - postal.subscribe( { - channel : source.channel || postal.configuration.DEFAULT_CHANNEL, - topic : sourceTopic, - callback : function ( data, env ) { - var newEnv = _.clone( env ); - newEnv.topic = _.isFunction( destination.topic ) ? destination.topic( env.topic ) : destination.topic || env.topic; - newEnv.channel = destChannel; - newEnv.data = data; - postal.publish( newEnv ); - } - } ) - ); - } ); - } ); - return result; - }, - - utils : { - getSubscribersFor : function () { - var channel = arguments[ 0 ], - tpc = arguments[ 1 ]; - if ( arguments.length === 1 ) { - channel = arguments[ 0 ].channel || postal.configuration.DEFAULT_CHANNEL; - tpc = arguments[ 0 ].topic; - } - if ( postal.configuration.bus.subscriptions[ channel ] && - Object.prototype.hasOwnProperty.call( postal.configuration.bus.subscriptions[ channel ], tpc ) ) { - return postal.configuration.bus.subscriptions[ channel ][ tpc ]; - } - return []; - }, - - reset : function () { - postal.configuration.bus.reset(); - postal.configuration.resolver.reset(); - } - } - }; - localBus.subscriptions[postal.configuration.SYSTEM_CHANNEL] = {}; + var postal; - /*jshint -W106 */ - if ( global && Object.prototype.hasOwnProperty.call( global, "__postalReady__" ) && _.isArray( global.__postalReady__ ) ) { - while(global.__postalReady__.length) { - global.__postalReady__.shift().onReady(postal); - } - } - /*jshint +W106 */ - return postal; -} )); \ No newline at end of file + var ConsecutiveDistinctPredicate = function () { + var previous; + return function (data) { + var eq = false; + if (_.isString(data)) { + eq = data === previous; + previous = data; + } + else { + eq = _.isEqual(data, previous); + previous = _.clone(data); + } + return !eq; + }; + }; + + var DistinctPredicate = function () { + var previous = []; + + return function (data) { + var isDistinct = !_.any(previous, function (p) { + if (_.isObject(data) || _.isArray(data)) { + return _.isEqual(data, p); + } + return data === p; + }); + if (isDistinct) { + previous.push(data); + } + return isDistinct; + }; + }; + + var ChannelDefinition = function (channelName) { + this.channel = channelName || postal.configuration.DEFAULT_CHANNEL; + }; + + ChannelDefinition.prototype.subscribe = function () { + return 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.configuration.bus.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."); + } + if (topic.length === 0) { + throw new Error("Topics cannot be empty"); + } + this.channel = channel; + this.topic = topic; + this.callback = callback; + this.constraints = []; + this.context = null; + postal.configuration.bus.publish({ + channel: postal.configuration.SYSTEM_CHANNEL, + topic: "subscription.created", + data: { + event: "subscription.created", + channel: channel, + topic: topic + } + }); + postal.configuration.bus.subscribe(this); + }; + + SubscriptionDefinition.prototype = { + unsubscribe: function () { + if (!this.inactive) { + this.inactive = true; + postal.configuration.bus.unsubscribe(this); + postal.configuration.bus.publish({ + channel: postal.configuration.SYSTEM_CHANNEL, + topic: "subscription.removed", + data: { + event: "subscription.removed", + channel: this.channel, + topic: this.topic + } + }); + } + }, + + defer: function () { + var self = this; + var fn = this.callback; + this.callback = function (data, env) { + setTimeout(function () { + fn.call(self.context, data, env); + }, 0); + }; + return this; + }, + + disposeAfter: function (maxCalls) { + 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; + }, + + distinctUntilChanged: function () { + this.withConstraint(new ConsecutiveDistinctPredicate()); + return this; + }, + + distinct: function () { + this.withConstraint(new DistinctPredicate()); + return this; + }, + + once: function () { + this.disposeAfter(1); + return this; + }, + + withConstraint: function (predicate) { + if (!_.isFunction(predicate)) { + throw "Predicate constraint must be a function"; + } + this.constraints.push(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; + return this; + }, + + withDebounce: function (milliseconds, immediate) { + if (_.isNaN(milliseconds)) { + throw "Milliseconds must be a number"; + } + var fn = this.callback; + this.callback = _.debounce(fn, milliseconds, !! immediate); + return this; + }, + + withDelay: function (milliseconds) { + 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); + }; + return this; + }, + + withThrottle: function (milliseconds) { + if (_.isNaN(milliseconds)) { + throw "Milliseconds must be a number"; + } + var fn = this.callback; + this.callback = _.throttle(fn, milliseconds); + return this; + }, + + subscribe: function (callback) { + this.callback = callback; + return this; + } + }; + + var bindingsResolver = { + cache: {}, + regex: {}, + + compare: function (binding, topic) { + var pattern, rgx, prevSegment, result = (this.cache[topic] && this.cache[topic][binding]); + if (typeof result !== "undefined") { + return result; + } + if (!(rgx = this.regex[binding])) { + pattern = "^" + _.map(binding.split("."), function (segment) { + var res = ""; + if ( !! prevSegment) { + res = prevSegment !== "#" ? "\\.\\b" : "\\b"; + } + if (segment === "#") { + res += "[\\s\\S]*"; + } else if (segment === "*") { + res += "[^.]+"; + } else { + res += segment; + } + prevSegment = segment; + return res; + }).join("") + "$"; + rgx = this.regex[binding] = new RegExp(pattern); + } + this.cache[topic] = this.cache[topic] || {}; + this.cache[topic][binding] = result = rgx.test(topic); + return result; + }, + + reset: function () { + this.cache = {}; + this.regex = {}; + } + }; + + 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); + } + } + } + }; + + var pubInProgress = 0; + var unSubQueue = []; + var clearUnSubQueue = function () { + while (unSubQueue.length) { + localBus.unsubscribe(unSubQueue.shift()); + } + }; + + var localBus = { + addWireTap: function (callback) { + var self = this; + self.wireTaps.push(callback); + return function () { + var idx = self.wireTaps.indexOf(callback); + if (idx !== -1) { + self.wireTaps.splice(idx, 1); + } + }; + }, + + publish: function (envelope) { + ++pubInProgress; + envelope.timeStamp = new Date(); + _.each(this.wireTaps, function (tap) { + tap(envelope.data, envelope); + }); + if (this.subscriptions[envelope.channel]) { + _.each(this.subscriptions[envelope.channel], function (subscribers) { + var idx = 0, + len = subscribers.length, + subDef; + while (idx < len) { + if (subDef = subscribers[idx++]) { + fireSub(subDef, envelope); + } + } + }); + } + if (--pubInProgress === 0) { + clearUnSubQueue(); + } + return envelope; + }, + + reset: function () { + if (this.subscriptions) { + _.each(this.subscriptions, function (channel) { + _.each(channel, function (topic) { + while (topic.length) { + topic.pop().unsubscribe(); + } + }); + }); + this.subscriptions = {}; + } + }, + + subscribe: function (subDef) { + var channel = this.subscriptions[subDef.channel], + subs; + if (!channel) { + channel = this.subscriptions[subDef.channel] = {}; + } + subs = this.subscriptions[subDef.channel][subDef.topic]; + if (!subs) { + subs = this.subscriptions[subDef.channel][subDef.topic] = []; + } + subs.push(subDef); + return subDef; + }, + + subscriptions: {}, + + wireTaps: [], + + unsubscribe: function (config) { + if (pubInProgress) { + unSubQueue.push(config); + return; + } + if (this.subscriptions[config.channel][config.topic]) { + var len = this.subscriptions[config.channel][config.topic].length, + idx = 0; + while (idx < len) { + if (this.subscriptions[config.channel][config.topic][idx] === config) { + this.subscriptions[config.channel][config.topic].splice(idx, 1); + break; + } + idx += 1; + } + } + } + }; + + + postal = { + configuration: { + bus: localBus, + resolver: bindingsResolver, + DEFAULT_CHANNEL: "/", + SYSTEM_CHANNEL: "postal" + }, + + ChannelDefinition: ChannelDefinition, + SubscriptionDefinition: SubscriptionDefinition, + + channel: function (channelName) { + return new ChannelDefinition(channelName); + }, + + subscribe: function (options) { + return new SubscriptionDefinition(options.channel || postal.configuration.DEFAULT_CHANNEL, options.topic, options.callback); + }, + + publish: function (envelope) { + envelope.channel = envelope.channel || postal.configuration.DEFAULT_CHANNEL; + return postal.configuration.bus.publish(envelope); + }, + + addWireTap: function (callback) { + return this.configuration.bus.addWireTap(callback); + }, + + linkChannels: function (sources, destinations) { + var result = []; + sources = !_.isArray(sources) ? [sources] : sources; + destinations = !_.isArray(destinations) ? [destinations] : destinations; + _.each(sources, function (source) { + var sourceTopic = source.topic || "#"; + _.each(destinations, function (destination) { + var destChannel = destination.channel || postal.configuration.DEFAULT_CHANNEL; + result.push( + postal.subscribe({ + channel: source.channel || postal.configuration.DEFAULT_CHANNEL, + topic: sourceTopic, + callback: function (data, env) { + var newEnv = _.clone(env); + newEnv.topic = _.isFunction(destination.topic) ? destination.topic(env.topic) : destination.topic || env.topic; + newEnv.channel = destChannel; + newEnv.data = data; + postal.publish(newEnv); + } + })); + }); + }); + return result; + }, + + utils: { + getSubscribersFor: function () { + var channel = arguments[0], + tpc = arguments[1]; + if (arguments.length === 1) { + channel = arguments[0].channel || postal.configuration.DEFAULT_CHANNEL; + tpc = arguments[0].topic; + } + if (postal.configuration.bus.subscriptions[channel] && Object.prototype.hasOwnProperty.call(postal.configuration.bus.subscriptions[channel], tpc)) { + return postal.configuration.bus.subscriptions[channel][tpc]; + } + return []; + }, + + reset: function () { + postal.configuration.bus.reset(); + postal.configuration.resolver.reset(); + } + } + }; + localBus.subscriptions[postal.configuration.SYSTEM_CHANNEL] = {}; + + + if (global && Object.prototype.hasOwnProperty.call(global, "__postalReady__") && _.isArray(global.__postalReady__)) { + while (global.__postalReady__.length) { + global.__postalReady__.shift().onReady(postal); + } + } + + + return postal; +})); \ No newline at end of file diff --git a/lib/postal.min.js b/lib/postal.min.js old mode 100755 new mode 100644 index 5fa1b67..8d37800 --- a/lib/postal.min.js +++ b/lib/postal.min.js @@ -1,7 +1,8 @@ -/* - postal - Author: Jim Cowart (http://freshbrewedcode.com/jimcowart) - License: Dual licensed MIT (http://www.opensource.org/licenses/mit-license) & GPL (http://www.opensource.org/licenses/gpl-license) - Version 0.8.11 +/** + * postal - Pub/Sub library providing wildcard subscriptions, complex message handling, etc. Works server and client-side. + * Author: Jim Cowart (http://freshbrewedcode.com/jimcowart) + * Version: v0.8.11 + * Url: http://github.com/postaljs/postal.js + * License: */ -(function(t,n){"object"==typeof module&&module.exports?module.exports=function(t){return t=t||require("underscore"),n(t)}:"function"==typeof define&&define.amd?define(["underscore"],function(i){return n(i,t)}):t.postal=n(t._,t)})(this,function(t,n){var i,s=function(){var n;return function(i){var s=!1;return t.isString(i)?(s=i===n,n=i):(s=t.isEqual(i,n),n=t.clone(i)),!s}},e=function(){var n=[];return function(i){var s=!t.any(n,function(n){return t.isObject(i)||t.isArray(i)?t.isEqual(i,n):i===n});return s&&n.push(i),s}},c=function(t){this.channel=t||i.configuration.DEFAULT_CHANNEL};c.prototype.subscribe=function(){return 1===arguments.length?new r(this.channel,arguments[0].topic,arguments[0].callback):new r(this.channel,arguments[0],arguments[1])},c.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.configuration.bus.publish(t)};var r=function(t,n,s){if(3!==arguments.length)throw Error("You must provide a channel, topic and callback when creating a SubscriptionDefinition instance.");if(0===n.length)throw Error("Topics cannot be empty");this.channel=t,this.topic=n,this.callback=s,this.constraints=[],this.context=null,i.configuration.bus.publish({channel:i.configuration.SYSTEM_CHANNEL,topic:"subscription.created",data:{event:"subscription.created",channel:t,topic:n}}),i.configuration.bus.subscribe(this)};r.prototype={unsubscribe:function(){this.inactive||(this.inactive=!0,i.configuration.bus.unsubscribe(this),i.configuration.bus.publish({channel:i.configuration.SYSTEM_CHANNEL,topic:"subscription.removed",data:{event:"subscription.removed",channel:this.channel,topic:this.topic}}))},defer:function(){var t=this,n=this.callback;return this.callback=function(i,s){setTimeout(function(){n.call(t.context,i,s)},0)},this},disposeAfter:function(n){if(t.isNaN(n)||0>=n)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var i=this,s=this.callback,e=t.after(n,t.bind(function(){this.unsubscribe()},this));return this.callback=function(){s.apply(i.context,arguments),e()},this},distinctUntilChanged:function(){return this.withConstraint(new s),this},distinct:function(){return this.withConstraint(new e),this},once:function(){return this.disposeAfter(1),this},withConstraint:function(n){if(!t.isFunction(n))throw"Predicate constraint must be a function";return this.constraints.push(n),this},withConstraints:function(n){var i=this;return t.isArray(n)&&t.each(n,function(t){i.withConstraint(t)}),i},withContext:function(t){return this.context=t,this},withDebounce:function(n,i){if(t.isNaN(n))throw"Milliseconds must be a number";var s=this.callback;return this.callback=t.debounce(s,n,!!i),this},withDelay:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this,s=this.callback;return this.callback=function(t,e){setTimeout(function(){s.call(i.context,t,e)},n)},this},withThrottle:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.throttle(i,n),this},subscribe:function(t){return this.callback=t,this}};var o={cache:{},regex:{},compare:function(n,i){var s,e,c,r=this.cache[i]&&this.cache[i][n];return r!==undefined?r:((e=this.regex[n])||(s="^"+t.map(n.split("."),function(t){var n="";return c&&(n="#"!==c?"\\.\\b":"\\b"),n+="#"===t?"[\\s\\S]*":"*"===t?"[^.]+":t,c=t,n}).join("")+"$",e=this.regex[n]=RegExp(s)),this.cache[i]=this.cache[i]||{},this.cache[i][n]=r=e.test(i),r)},reset:function(){this.cache={},this.regex={}}},a=function(n,s){!n.inactive&&i.configuration.resolver.compare(n.topic,s.topic)&&t.all(n.constraints,function(t){return t.call(n.context,s.data,s)})&&"function"==typeof n.callback&&n.callback.call(n.context,s.data,s)},u=0,h=[],l=function(){for(;h.length;)f.unsubscribe(h.shift())},f={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)}},publish:function(n){return++u,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,s=0,e=t.length;e>s;)(i=t[s++])&&a(i,n)}),0===--u&&l(),n},reset:function(){this.subscriptions&&(t.each(this.subscriptions,function(n){t.each(n,function(t){for(;t.length;)t.pop().unsubscribe()})}),this.subscriptions={})},subscribe:function(t){var n,i=this.subscriptions[t.channel];return i||(i=this.subscriptions[t.channel]={}),n=this.subscriptions[t.channel][t.topic],n||(n=this.subscriptions[t.channel][t.topic]=[]),n.push(t),t},subscriptions:{},wireTaps:[],unsubscribe:function(t){if(u)return h.push(t),undefined;if(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}}};if(i={configuration:{bus:f,resolver:o,DEFAULT_CHANNEL:"/",SYSTEM_CHANNEL:"postal"},ChannelDefinition:c,SubscriptionDefinition:r,channel:function(t){return new c(t)},subscribe:function(t){return new r(t.channel||i.configuration.DEFAULT_CHANNEL,t.topic,t.callback)},publish:function(t){return t.channel=t.channel||i.configuration.DEFAULT_CHANNEL,i.configuration.bus.publish(t)},addWireTap:function(t){return this.configuration.bus.addWireTap(t)},linkChannels:function(n,s){var e=[];return n=t.isArray(n)?n:[n],s=t.isArray(s)?s:[s],t.each(n,function(n){var c=n.topic||"#";t.each(s,function(s){var r=s.channel||i.configuration.DEFAULT_CHANNEL;e.push(i.subscribe({channel:n.channel||i.configuration.DEFAULT_CHANNEL,topic:c,callback:function(n,e){var c=t.clone(e);c.topic=t.isFunction(s.topic)?s.topic(e.topic):s.topic||e.topic,c.channel=r,c.data=n,i.publish(c)}}))})}),e},utils:{getSubscribersFor:function(){var t=arguments[0],n=arguments[1];return 1===arguments.length&&(t=arguments[0].channel||i.configuration.DEFAULT_CHANNEL,n=arguments[0].topic),i.configuration.bus.subscriptions[t]&&Object.prototype.hasOwnProperty.call(i.configuration.bus.subscriptions[t],n)?i.configuration.bus.subscriptions[t][n]:[]},reset:function(){i.configuration.bus.reset(),i.configuration.resolver.reset()}}},f.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=function(t){return t=t||require("underscore"),n(t)}:"function"==typeof define&&define.amd?define(["underscore"],function(i){return n(i,t)}):t.postal=n(t._,t)}(this,function(t,n){var i,s=function(){var n;return function(i){var s=!1;return t.isString(i)?(s=i===n,n=i):(s=t.isEqual(i,n),n=t.clone(i)),!s}},e=function(){var n=[];return function(i){var s=!t.any(n,function(n){return t.isObject(i)||t.isArray(i)?t.isEqual(i,n):i===n});return s&&n.push(i),s}},c=function(t){this.channel=t||i.configuration.DEFAULT_CHANNEL};c.prototype.subscribe=function(){return 1===arguments.length?new r(this.channel,arguments[0].topic,arguments[0].callback):new r(this.channel,arguments[0],arguments[1])},c.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.configuration.bus.publish(t)};var r=function(t,n,s){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.callback=s,this.constraints=[],this.context=null,i.configuration.bus.publish({channel:i.configuration.SYSTEM_CHANNEL,topic:"subscription.created",data:{event:"subscription.created",channel:t,topic:n}}),i.configuration.bus.subscribe(this)};r.prototype={unsubscribe:function(){this.inactive||(this.inactive=!0,i.configuration.bus.unsubscribe(this),i.configuration.bus.publish({channel:i.configuration.SYSTEM_CHANNEL,topic:"subscription.removed",data:{event:"subscription.removed",channel:this.channel,topic:this.topic}}))},defer:function(){var t=this,n=this.callback;return this.callback=function(i,s){setTimeout(function(){n.call(t.context,i,s)},0)},this},disposeAfter:function(n){if(t.isNaN(n)||0>=n)throw"The value provided to disposeAfter (maxCalls) must be a number greater than zero.";var i=this,s=this.callback,e=t.after(n,t.bind(function(){this.unsubscribe()},this));return this.callback=function(){s.apply(i.context,arguments),e()},this},distinctUntilChanged:function(){return this.withConstraint(new s),this},distinct:function(){return this.withConstraint(new e),this},once:function(){return this.disposeAfter(1),this},withConstraint:function(n){if(!t.isFunction(n))throw"Predicate constraint must be a function";return this.constraints.push(n),this},withConstraints:function(n){var i=this;return t.isArray(n)&&t.each(n,function(t){i.withConstraint(t)}),i},withContext:function(t){return this.context=t,this},withDebounce:function(n,i){if(t.isNaN(n))throw"Milliseconds must be a number";var s=this.callback;return this.callback=t.debounce(s,n,!!i),this},withDelay:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this,s=this.callback;return this.callback=function(t,e){setTimeout(function(){s.call(i.context,t,e)},n)},this},withThrottle:function(n){if(t.isNaN(n))throw"Milliseconds must be a number";var i=this.callback;return this.callback=t.throttle(i,n),this},subscribe:function(t){return this.callback=t,this}};var o={cache:{},regex:{},compare:function(n,i){var s,e,c,r=this.cache[i]&&this.cache[i][n];return"undefined"!=typeof r?r:((e=this.regex[n])||(s="^"+t.map(n.split("."),function(t){var n="";return c&&(n="#"!==c?"\\.\\b":"\\b"),n+="#"===t?"[\\s\\S]*":"*"===t?"[^.]+":t,c=t,n}).join("")+"$",e=this.regex[n]=new RegExp(s)),this.cache[i]=this.cache[i]||{},this.cache[i][n]=r=e.test(i),r)},reset:function(){this.cache={},this.regex={}}},a=function(n,s){!n.inactive&&i.configuration.resolver.compare(n.topic,s.topic)&&t.all(n.constraints,function(t){return t.call(n.context,s.data,s)})&&"function"==typeof n.callback&&n.callback.call(n.context,s.data,s)},u=0,h=[],l=function(){for(;h.length;)f.unsubscribe(h.shift())},f={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)}},publish:function(n){return++u,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,s=0,e=t.length;e>s;)(i=t[s++])&&a(i,n)}),0===--u&&l(),n},reset:function(){this.subscriptions&&(t.each(this.subscriptions,function(n){t.each(n,function(t){for(;t.length;)t.pop().unsubscribe()})}),this.subscriptions={})},subscribe:function(t){var n,i=this.subscriptions[t.channel];return i||(i=this.subscriptions[t.channel]={}),n=this.subscriptions[t.channel][t.topic],n||(n=this.subscriptions[t.channel][t.topic]=[]),n.push(t),t},subscriptions:{},wireTaps:[],unsubscribe:function(t){if(u)return h.push(t),void 0;if(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}}};if(i={configuration:{bus:f,resolver:o,DEFAULT_CHANNEL:"/",SYSTEM_CHANNEL:"postal"},ChannelDefinition:c,SubscriptionDefinition:r,channel:function(t){return new c(t)},subscribe:function(t){return new r(t.channel||i.configuration.DEFAULT_CHANNEL,t.topic,t.callback)},publish:function(t){return t.channel=t.channel||i.configuration.DEFAULT_CHANNEL,i.configuration.bus.publish(t)},addWireTap:function(t){return this.configuration.bus.addWireTap(t)},linkChannels:function(n,s){var e=[];return n=t.isArray(n)?n:[n],s=t.isArray(s)?s:[s],t.each(n,function(n){var c=n.topic||"#";t.each(s,function(s){var r=s.channel||i.configuration.DEFAULT_CHANNEL;e.push(i.subscribe({channel:n.channel||i.configuration.DEFAULT_CHANNEL,topic:c,callback:function(n,e){var c=t.clone(e);c.topic=t.isFunction(s.topic)?s.topic(e.topic):s.topic||e.topic,c.channel=r,c.data=n,i.publish(c)}}))})}),e},utils:{getSubscribersFor:function(){var t=arguments[0],n=arguments[1];return 1===arguments.length&&(t=arguments[0].channel||i.configuration.DEFAULT_CHANNEL,n=arguments[0].topic),i.configuration.bus.subscriptions[t]&&Object.prototype.hasOwnProperty.call(i.configuration.bus.subscriptions[t],n)?i.configuration.bus.subscriptions[t][n]:[]},reset:function(){i.configuration.bus.reset(),i.configuration.resolver.reset()}}},f.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/package.json b/package.json index b4c4ad0..18c3dcd 100755 --- a/package.json +++ b/package.json @@ -1,88 +1,100 @@ { - "name" : "postal", - "description" : "Pub/Sub library providing wildcard subscriptions, complex message handling, etc. Works server and client-side.", - "version" : "0.8.11", - "homepage" : "http://github.com/postaljs/postal.js", - "repository" : { - "type" : "git", - "url" : "git://github.com/postaljs/postal.js.git" + "name": "postal", + "description": "Pub/Sub library providing wildcard subscriptions, complex message handling, etc. Works server and client-side.", + "version": "0.8.11", + "homepage": "http://github.com/postaljs/postal.js", + "repository": { + "type": "git", + "url": "git://github.com/postaljs/postal.js.git" + }, + "author": "Jim Cowart (http://freshbrewedcode.com/jimcowart)", + "contributors": [ + { + "name": "Jim Cowart", + "email": "WhyNotJustComment@OnMyBlog.com", + "url": "http://freshbrewedcode.com/jimcowart" }, - "author" : "Jim Cowart (http://freshbrewedcode.com/jimcowart)", - "contributors": [ - { - "name" : "Jim Cowart", - "email" : "WhyNotJustComment@OnMyBlog.com", - "url" : "http://freshbrewedcode.com/jimcowart" - }, - { - "name" : "Alex Robson", - "email" : "WhyNotJustComment@OnMyBlog.com", - "url" : "http://freshbrewedcode.com/alexrobson" - }, - { - "name" : "Nicholas Cloud", - "email" : "WhyNotJustComment@OnMyBlog.com", - "url" : "http://nicholascloud.com" - }, - { - "name" : "Doug Neiner", - "email" : "WhyNotJustComment@OnMyBlog.com", - "url" : "http://dougneiner.com" - }, - { - "name" : "Jonathan Creamer", - "email" : "WhyNotJustComment@OnMyBlog.com", - "url" : "http://freshbrewedcode.com/jonathancreamer" - }, - { - "name" : "Elijah Manor", - "email" : "WhyNotJustComment@OnMyBlog.com", - "url" : "http://www.elijahmanor.com" - }, - { - "name" : "Ger Hobbelt", - "email" : "ger@hobbelt.com", - "url" : "http://hebbut.net/" - }, - { - "name" : "Christian Haas", - "url" : "http://github.com/dertseha" - } - ], - "keywords": [ - "pub/sub", - "pub", - "sub", - "messaging", - "message", - "bus", - "event", - "mediator", - "broker", - "envelope" - ], - "bugs" : { - "email" : "PleaseJustUseTheIssuesPage@github.com", - "url" : "http://github.com/postaljs/postal.js/issues" + { + "name": "Alex Robson", + "email": "WhyNotJustComment@OnMyBlog.com", + "url": "http://freshbrewedcode.com/alexrobson" }, - "directories" : { "lib" : "lib" }, - "main" : "lib/postal.js", - "engines" : { - "node" : ">=0.4.0" + { + "name": "Nicholas Cloud", + "email": "WhyNotJustComment@OnMyBlog.com", + "url": "http://nicholascloud.com" }, - "dependencies" : { - "underscore" : ">=1.1.7" + { + "name": "Doug Neiner", + "email": "WhyNotJustComment@OnMyBlog.com", + "url": "http://dougneiner.com" }, - "bundleDependencies" : [ "underscore" ], - "devDependencies" : {}, - "licenses" : [ - { - "type" : "MIT", - "url" : "http://www.opensource.org/licenses/mit-license.php" - }, - { - "type" : "GPL", - "url" : "http://www.opensource.org/licenses/gpl-3.0.html" - } - ] + { + "name": "Jonathan Creamer", + "email": "WhyNotJustComment@OnMyBlog.com", + "url": "http://freshbrewedcode.com/jonathancreamer" + }, + { + "name": "Elijah Manor", + "email": "WhyNotJustComment@OnMyBlog.com", + "url": "http://www.elijahmanor.com" + }, + { + "name": "Ger Hobbelt", + "email": "ger@hobbelt.com", + "url": "http://hebbut.net/" + }, + { + "name": "Christian Haas", + "url": "http://github.com/dertseha" + } + ], + "keywords": [ + "pub/sub", + "pub", + "sub", + "messaging", + "message", + "bus", + "event", + "mediator", + "broker", + "envelope" + ], + "bugs": { + "email": "PleaseJustUseTheIssuesPage@github.com", + "url": "http://github.com/postaljs/postal.js/issues" + }, + "directories": { + "lib": "lib" + }, + "main": "lib/postal.js", + "engines": { + "node": ">=0.4.0" + }, + "dependencies": { + "underscore": ">=1.1.7" + }, + "bundleDependencies": [ + "underscore" + ], + "devDependencies": { + "gulp-util": "~2.2.9", + "gulp": "~3.3.1", + "gulp-imports": "~0.0.1", + "gulp-header": "~1.0.2", + "gulp-hint-not": "~0.0.3", + "gulp-uglify": "~0.1.0", + "gulp-rename": "~0.2.1" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://www.opensource.org/licenses/mit-license.php" + }, + { + "type": "GPL", + "url": "http://www.opensource.org/licenses/gpl-3.0.html" + } + ] }