Socket
Socket
Sign inDemoInstall

qbus

Package Overview
Dependencies
0
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.9.5 to 0.9.6

58

benchmark/index.js

@@ -6,44 +6,38 @@ var Benchmark = require('benchmark'),

Qbus1 = require('../index'),
Qbus2 = require('./qbus2.js'),
Qbus2 = require('../index'),
qbus1 = new Qbus1(),
qbus2 = new Qbus2();
qbus2 = new Qbus2(),
EventEmitter = require('events');
nodeEmitter = new EventEmitter();
nodeEmitter.setMaxListeners(Infinity);
function noop () {}
function woop () { console.log('woop', arguments); }
function woop () { console.log('woop'); }
// Listen on all string queries
queries.simple.forEach(function (query) {
qbus1.on(query, noop);
qbus2.on(query, noop);
});
var e = ['b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q'],
y;
// Listen on all regexp queries
queries.complex.forEach(function (query) {
qbus1.on(query, noop);
qbus2.on(query, noop);
});
var to = 1000000;
while (to--)
qbus1.on('a', noop);
console.log('Each run consists of ' + queries.simple.length + ' emits against ' + (queries.simple.length + queries.complex.length) + ' listeners.');
qbus1.on('b', noop);
suite
.add('qbus 1', function () {
queries.simple.forEach(function (query) {
qbus1.emit(query, 'a', 'b', 'c');
});
})
.add('qbus 2', function() {
queries.simple.forEach(function (query) {
qbus2.emit(query, 'a', 'b', 'c');
});
})
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').pluck('name'));
})
.run();
(new Benchmark.Suite)
.add('qbus', function () {
qbus1.emit('b');
})
.on('cycle', function(event) {
console.log(String(event.target));
})
.run();
// require('fs').writeFile(__dirname + '/qbus1.out.txt', JSON.stringify(qbus1.qbus, function (key, val) { return (val instanceof RegExp ? val.source : val); }, '\t'));
// require('fs').writeFile(__dirname + '/qbus2.out.txt', JSON.stringify(qbus2.qbus, function (key, val) { return (val instanceof RegExp ? val.source : val); }, '\t'));

@@ -6,25 +6,2 @@ /** @license Licenced under MIT - qbus - ©2015 Pehr Boman <github.com/unkelpehr> */

var root = this;
/**
* Helper function used for converting `arguments` object into a proper Array.
* I haven't come across the leaky-arguments-deoptimization yet. Is this a problem?
* When testing, the function below is 20 times faster than a local slice.call(arguments).
*
* @method toArray
* @param {arguments} args `arguments` object
* @param {number=0} from Start position
* @return {Array} A proper array
*/
function toArray (args, from) {
var i = from || 0,
x = 0,
l = args.length,
a = new Array(l - i);
for ( ; i < l; ) {
a[x++] = args[i++];
}
return a;
}

@@ -89,6 +66,12 @@ /**

function execQuery (query) {
var match;
var match, i, arr;
if ((match = this.exec(query))) {
return toArray(match, 1);
arr = new Array(match.length - 1);
for (i = 1; i < match.length; ++i) {
arr[i - 1] = match[i];
}
return arr;
}

@@ -239,18 +222,20 @@

// Get the first occurence of a wilcard or capture portion
iOP = (query.indexOf(':') === -1 ? -1 : query.search(/(^|\/)+?:+?[^\/]+?/));
iOW = (query.indexOf('*') === -1 ? -1 : query.search(/(^|\/)+?[^\/]*?\*{1}/));
// Search for the the first occurence of a wildcard or capture portion
iOP = query.search(/(^|\/)+?:+?[^\/]+?/);
iOW = query.search(/(^|\/)+?[^\/]*?\*{1}/);
// Both negative - static query
if (iOP === -1 && iOW === -1) {
fixed = query;
} else {
fixed = query.substr(0, Math.min(
iOP !== -1 ? iOP : query.length,
iOW !== -1 ? iOW : query.length
));
return query;
}
// Pop slash from fixed
if (fixed[fixed.length - 1] === '/') {
fixed = fixed.substr(0, fixed.length - 1);
}
// Extract static portion
fixed = query.substr(0, Math.min(
iOP !== -1 ? iOP : query.length,
iOW !== -1 ? iOW : query.length
));
// Pop slash
if (fixed[fixed.length - 1] === '/') {
fixed = fixed.substr(0, fixed.length - 1);
}

@@ -265,15 +250,16 @@

* @method on
* @param {String|RegExp} query Query to subscribe to. String or a RegExp object
* @param {Function} handler A function to execute when the query is matched.
* @param {String|RegExp} expr Expression to match against. String or a RegExp object
* @param {Function} handler A function to execute when the expression is matched.
* @return {Object} `this`
*/
Qbus.prototype.on = function (query, handler) {
var normal,
Qbus.prototype.on = function (expr, handler) {
var paths = this.qbus.paths,
normal,
fixed,
isRegExp = query instanceof RegExp;
isRegExp = expr instanceof RegExp;
if ((!isRegExp && typeof query !== 'string') || typeof handler !== 'function') {
if ((!isRegExp && typeof expr !== 'string') || typeof handler !== 'function') {
throw new TypeError(
'Usage: qbus.on(<`query` = String|RegExp>, <`handler` = Function>)\n'+
'Got: qbus.on(<`' + typeof query + '` = ' + query + '>, <`' + typeof handler + '` = ' + handler + '>)'
'Usage: qbus.on(<`expr` = String|RegExp>, <`handler` = Function>)\n'+
'Got: qbus.on(<`' + typeof expr + '` = ' + expr + '>, <`' + typeof handler + '` = ' + handler + '>)'
);

@@ -284,6 +270,6 @@ }

if (isRegExp) {
(this.qbus.paths['/'] || (this.qbus.paths['/'] = [])).push({
input: query.source,
(paths['/'] || (paths['/'] = [])).push({
input: expr.source,
handler: handler,
expr: parse(query)
expr: parse(expr)
});

@@ -295,20 +281,20 @@

// Trim slashes and remove doubles
normal = normalizePath(query);
normal = normalizePath(expr);
fixed = getFixed(normal);
// Get the static portion of the expression or fallback on '/'.
fixed = getFixed(normal) || '/';
// Create namespace
// Must be stored with leading frontslash or the key would be "" on e.g. /*
if (!this.qbus.paths['/' + fixed]) {
this.qbus.paths['/' + fixed] = [];
if (!paths[fixed]) {
paths[fixed] = [];
}
// All done
this.qbus.paths['/' + fixed].push({
paths[fixed].push({
input: normal,
handler: handler,
// If the fixed portion of the query equals the normal
// then this is a simple, non-regexp query that can use string comparison.
expr: normal === fixed ? normal : parse(query)
// If the fixed portion of the expr equals the normal
// then this is a simple, non-regexp expr that can use string comparison.
expr: normal === fixed ? normal : parse(expr)
});

@@ -324,19 +310,26 @@

* @method on
* @param {String|RegExp} query Query to subscribe to. String or a RegExp object
* @param {Function} handler A function to execute when the query is matched.
* @param {String|RegExp} expr Expression to match against. String or a RegExp object
* @param {Function} handler A function to execute when the expression is matched.
* @return {Object} `this`
*/
Qbus.prototype.once = function (query, handler) {
Qbus.prototype.once = function (expr, handler) {
var self = this;
if (typeof handler !== 'function' || (typeof query !== 'string' && (!query instanceof RegExp))) {
if (typeof handler !== 'function' || (typeof expr !== 'string' && !(expr instanceof RegExp))) {
throw new TypeError(
'Usage: qbus.once(<`query` = String|RegExp>, <`handler` = Function>)\n'+
'Got: qbus.once(<`' + typeof query + '` = ' + query + '>, <`' + typeof handler + '` = ' + handler + '>)'
'Usage: qbus.once(<`expr` = String|RegExp>, <`handler` = Function>)\n'+
'Got: qbus.once(<`' + typeof expr + '` = ' + expr + '>, <`' + typeof handler + '` = ' + handler + '>)'
);
}
return this.on(query, function temp () {
self.off(query, temp);
exec(handler, self, toArray(arguments));
return this.on(expr, function temp () {
var i = 0,
args = new Array(arguments.length);
for (; i < args.length; ++i) {
args[i] = arguments[i];
}
self.off(expr, temp);
exec(handler, self, args);
});

@@ -346,16 +339,19 @@ };

/**
* Removes all subscriptions matching `query` and the optional `handler` function.
* Removes all subscriptions matching `expr` and the optional `handler` function.
*
* @method off
* @param {String|RegExp} query Query to match
* @param {String|RegExp} expr Expression to match
* @param {Function=} handler Function to match
* @return {Object} `this`
*/
Qbus.prototype.off = function (query, handler) {
var i, sub, dir, isRegExp;
Qbus.prototype.off = function (expr, handler) {
var paths = this.qbus.paths,
isRegExp,
parent,
i;
if ((typeof query !== 'string' && !(isRegExp = query instanceof RegExp)) || (typeof handler !== 'undefined' && typeof handler !== 'function')) {
if ((typeof expr !== 'string' && !(isRegExp = expr instanceof RegExp)) || (typeof handler !== 'undefined' && typeof handler !== 'function')) {
throw new TypeError(
'Usage: qbus.off(<`query` = String|RegExp>[, <`handler` = Function>])\n'+
'Got: qbus.off(<`' + typeof query + '` = ' + query + '>, <`' + typeof handler + '` = ' + handler + '>)'
'Usage: qbus.off(<`expr` = String|RegExp>[, <`handler` = Function>])\n'+
'Got: qbus.off(<`' + typeof expr + '` = ' + expr + '>, <`' + typeof handler + '` = ' + handler + '>)'
);

@@ -366,21 +362,13 @@ }

if (isRegExp) {
query = query.source;
dir = '/';
expr = expr.source;
parent = paths['/'];
} else {
query = normalizePath(query);
dir = '/' + getFixed(query);
expr = normalizePath(expr);
parent = paths[getFixed(expr) || '/'];
}
if ((dir = this.qbus.paths[dir])) {
i = 0;
while ((sub = dir[i++])) {
if (sub.input === query && (!handler || sub.handler === handler)) {
// What's actually going on is that this function only
// marks the subscription as to-be-deleted.
//
// The emit function does the actual deletion,
// this is because otherwise the collection of
// subscriptions would change if a handler caused
// itself or other handlers to remove themselves.
sub.remove = true;
if (parent) {
for (i = 0; i < parent.length; ++i) {
if (parent[i].input === expr && (!handler || parent[i].handler === handler)) {
parent.splice(--i, 1);
}

@@ -400,79 +388,89 @@ }

*/
Qbus.prototype.emit = function (query /*, arg1, arg2, ... */) {
var qbus = this.qbus,
i, sub,
Qbus.prototype.emit = function (query) {
var paths = this.qbus.paths,
i, x,
sub,
match,
args,
level,
args = [],
parent,
needle,
returned,
slashEnd = '',
normal;
slashEnd,
normal,
argsLen = arguments.length;
// Get all arguments after `query` as a regular array
if (argsLen > 1) {
for (i = 1; i < argsLen; ++i) {
args.push(arguments[i]);
}
}
// Typecheck after converting the arguments to a regular array so we can include `args` in the message.
// Dropping the `arguments` bomb causes V8 bailout: Bad value context for arguments value.
if (typeof query !== 'string') {
throw new TypeError(
'Usage: qbus.emit(<`query` = String>[, <`arg1` = *>], <`arg2` = *>, ...)\n'+
'Got: qbus.emit(<`' + typeof query + '` = ' + query + '>, ' + arguments + ')'
'Got: qbus.emit(<`' + typeof query + '` = ' + query + '>, ' + args + ')'
);
}
// Get all arguments after `query` as a regular array
args = toArray(arguments, 1);
slashEnd = query[query.length - 1] == '/' ? '/' : '';
slashEnd = query[query.length - 1] === '/' ? '/' : '';
// `needle` will be modified while we look for listeners so
// `normal` will be the value that we'll compare against.
needle = normal = normalizePath(query);
// Trim slashes and remove doubles
normal = normalizePath(query);
// Skip a do...while by setting `needle` to '/' if it's empty.
// It will be empty if the query equaled '/' before normalizePath trimmed the slashes.
needle = needle || '/';
needle = normal + '/';
// Loop it backwards:
// 'foo/bar/baz'
// 'foo/bar'
// 'foo'
// ''
//
// This is because the most explicit matches should have a
// running chance to potentially stop the loop by returning false.
while (needle) {
// For each run we pop a part of the needle
// 'foo/bar/baz'.substr(0, 7) => foo/bar
needle = needle.substr(0, needle.lastIndexOf('/'));
parent = paths[needle];
// By prepending frontslash unto the key for the haystack
// lookup we don't need a complex condition for the while-loop
// to get to following behaviour:
//
// '/foo/bar/baz'
// '/foo/bar'
// '/foo'
// '/'
if (!(level = qbus.paths['/' + needle])) {
continue;
}
if (parent) {
for (i = 0; i < parent.length; ++i) {
sub = parent[i];
i = 0;
while ((sub = level[i++])) {
// Ignore and splice of subscriptions marked as to-be-deleted.
if (sub.remove) {
level.splice(--i, 1);
}
// RegExp matching
if (sub.expr.query) {
if ((match = sub.expr.query(normal + slashEnd))) {
// Extend `args` into matches
for (x = 0; x < args.length; ++x) {
match.push(args[x]);
}
// RegExp subscription
else if (sub.expr.query) {
if ((match = sub.expr.query(normal + slashEnd))) {
returned = exec(sub.handler, this, match.concat(args));
returned = exec(sub.handler, this, match);
}
}
// String comparison
else if (normal == sub.expr) {
returned = exec(sub.handler, this, args);
}
}
// String comparison
else if (normal == sub.expr) {
returned = exec(sub.handler, this, args);
// Discontinue if a handler returned false
if (returned === false) {
return this;
}
}
}
// Discontinue if a handler returned false
if (returned === false) {
return this;
}
// Break after processing '/'
if (needle.length === 1) {
break;
}
// For each run we pop a part of the needle
// 'foo/bar/baz'.substr(0, 7) => foo/bar
// 'foo/bar'
// 'foo'
// ''
//
// By looping it backwards we let the most explicit listeners
// have a running chance to break the loop by returning false.
//
// They are also guaranteed to be executed before a less explicit
// listener breaks the loop.
needle = needle.substr(0, needle.lastIndexOf('/')) || '/';
}

@@ -479,0 +477,0 @@

{
"name": "qbus",
"description": "Minimalistic and fast isomorphic mediator with dynamic queries",
"version": "v0.9.5",
"version": "v0.9.6",
"author": "Pehr Boman <unkelpehr@gmail.com>",

@@ -16,3 +16,3 @@ "homepage": "https://github.com/unkelpehr/qbus",

"testling": {
"files": "test/*.js",
"files": "test/tests/*.js",
"browsers": [

@@ -19,0 +19,0 @@ "ie/6..latest",

@@ -59,7 +59,8 @@ if (typeof require === 'function') {

(function () {
var calls = 0,
var h1calls = 0,
h2calls = 0,
handler1 = function () {
calls++;
h1calls++;
}, handler2 = function () {
calls++;
h2calls++;
};

@@ -75,3 +76,3 @@

assert.equal(calls, qbuses().length, '.off(str) should only remove the subs with the specified handler');
assert.equal(h1calls, 0, '.off(str) should only remove the subs with the specified handler');
}());

@@ -124,7 +125,8 @@

(function () {
var calls = 0,
var h1calls = 0,
h2calls = 0,
handler1 = function () {
calls++;
h1calls++;
}, handler2 = function () {
calls++;
h2calls++;
};

@@ -140,3 +142,3 @@

assert.equal(calls, qbuses().length, '.off(expression) should only remove the subs with the specified handler');
assert.equal(h1calls, 0, '.off(expression) should only remove the subs with the specified handler');
}());

@@ -189,7 +191,8 @@

(function () {
var calls = 0,
var h1calls = 0,
h2calls = 0,
handler1 = function () {
calls++;
h1calls++;
}, handler2 = function () {
calls++;
h2calls++;
};

@@ -205,3 +208,3 @@

assert.equal(calls, qbuses().length, '.off(RegExp) should only remove the subs with the specified handler');
assert.equal(h1calls, 0, '.off(RegExp) should only remove the subs with the specified handler');
}());

@@ -208,0 +211,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc