Permalink
Browse files

overhaul item matching, resolves #4

  • Loading branch information...
1 parent dd4a671 commit fab29cbce4c5c0e4d0151383524e10d555844c10 @carlos8f committed Dec 14, 2012
Showing with 103 additions and 76 deletions.
  1. +1 −2 Makefile
  2. +88 −45 lib/item.js
  3. +9 −26 lib/middler.js
  4. +5 −3 test/{add-dupe.js → dupe.js}
View
3 Makefile
@@ -1,7 +1,6 @@
test:
@./node_modules/.bin/mocha \
--reporter spec \
- --bail \
--require test/common.js
bench: install-bench bench-middleware bench-routing
@@ -30,4 +29,4 @@ bench-routing: install-bench
--path bench/paths.txt \
bench/routing/*.js
-.PHONY: test bench
+.PHONY: test bench
View
133 lib/item.js
@@ -1,84 +1,127 @@
var currentId = 0
- , parseUrl = require('./parseUrl')
+ , parseUrl = require('../').parseUrl
, pathRegExp = require('../').pathRegExp
+ , Middler
function Item (args) {
this.weight = 0;
-
+
+ this.paths = [];
+ this.methods = [];
+ this.fns = [];
+
var self = this;
Array.prototype.slice.call(args).forEach(function (arg) {
if (typeof arg === 'object') {
// Item properties
- Object.keys(arg).forEach(function (k) {
- self[k] = arg[k];
+ arg = Object.keys(arg).map(function (k) {
+ return arg[k];
});
}
- else if (arg instanceof RegExp || (typeof arg === 'string' && arg[0] === '/')) {
- // Implied path string/regex
- self.path = arg;
- }
- else if (typeof arg === 'number') {
- // Implied weight
- self.weight = arg;
- }
- else if (typeof arg === 'string') {
- // Implied HTTP method
- self.method = arg;
- }
- else if (typeof arg === 'function') {
- // middleware handler
- self.fn = arg;
+ if (!Array.isArray(arg)) {
+ arg = [arg];
}
+ arg.forEach(function (arg) {
+ if (arg instanceof RegExp || (typeof arg === 'string' && arg[0] === '/')) {
+ // Implied path string/regex
+ self.paths.push(arg);
+ }
+ else if (typeof arg === 'number') {
+ // Implied weight
+ self.weight = arg;
+ }
+ else if (typeof arg === 'string') {
+ // Implied HTTP method
+ self.methods.push(arg);
+ }
+ else if (typeof arg === 'function') {
+ // middleware handler
+ self.fns.push(arg);
+ }
+ });
});
- if (!this.fn) {
+ if (!this.fns.length) {
throw new Error('middler expected a middleware callback of some kind');
}
- if (this.method) {
- this.method = this.method.toUpperCase();
- }
- if (this.path) {
- this.params = [];
- this.regex = pathRegExp(this.path, this.params, true, true);
+ this.methods = this.methods.map(function (method) {
+ return method.toUpperCase();
+ });
+
+ if (this.paths.length) {
+ this.paramses = [];
+ this.regexes = this.paths.map(function (p) {
+ var params = [];
+ self.paramses.push(params);
+ return pathRegExp(p, params, true, true);
+ });
}
this.id = currentId++;
+
+ if (this.fns.length === 1) {
+ this.fn = this.fns[0];
+ }
+ else {
+ // Embed a middler instance to handle the chaining!
+ if (typeof Middler === 'undefined') {
+ Middler = require('../').Middler;
+ }
+ this.chain = new Middler();
+ this.fns.forEach(function (fn) {
+ self.chain.add(fn);
+ });
+ this.fn = this.chain.handler;
+ }
}
module.exports = Item;
+function inArray (val, arr) {
+ if (!arr || !arr.length) return false;
+ for (var i in arr) {
+ if (arr[i] === val) return true;
+ }
+ return false;
+}
+
Item.prototype.match = function(req) {
- if (this.method && this.method !== req.method && req.method !== 'HEAD') {
+ if (this.methods.length && req.method !== 'HEAD' && !inArray(req.method, this.methods)) {
return false;
}
- if (!this.path) {
+ if (!this.paths.length) {
return true;
}
var reqPath = parseUrl(req).pathname;
// Exact match
- if (reqPath === this.path) return {};
+ if (inArray(reqPath, this.paths)) return {};
- // Try the regex
- var matches = this.regex.exec(reqPath)
+ var self = this;
- if (!matches) return false;
- matches.shift();
+ for (var i in this.regexes) {
+ // Try the regex
+ var matches = this.regexes[i].exec(reqPath);
- var self = this
- , params = []
+ if (!matches) continue;
+ matches.shift();
- matches.forEach(function (val, idx) {
- var key = self.params[idx];
+ var params = [];
- if (key) {
- params[key.name] = val;
- }
- else {
- params.push(val);
- }
- });
- return params;
+ matches.forEach(function (val, idx) {
+ var key = self.paramses[i][idx];
+
+ if (key) {
+ params[key.name] = val;
+ }
+ else {
+ params.push(val);
+ }
+ });
+ return params;
+ }
+
+ return false;
};
View
35 lib/middler.js
@@ -1,5 +1,4 @@
-var matcher = require('../').matcher
- , parseUrl = require('./parseUrl')
+var parseUrl = require('../').parseUrl
, pathRegExp = require('../').pathRegExp
, Item = require('../').Item
, inherits = require('util').inherits
@@ -87,39 +86,23 @@ Middler.prototype.handler = function middlerKernel (req, res, next) {
* Adds item(s) onto the stack.
*/
Middler.prototype.add = function addItem () {
- var args = [].slice.call(arguments)
- , self = this
- , divs = []
-
- // If arrays are passed, push an item for every permutation.
- // Credit: http://stackoverflow.com/a/4331713
- var arrs = args.map(function (val) {
- return Array.isArray(val) ? val : [val];
- });
- for (var i = arrs.length - 1; ~i; i--) {
- divs[i] = divs[i + 1] ? divs[i + 1] * arrs[i + 1].length : 1;
- }
- var numPerms = divs.reduce(function (prev, curr) {
- return prev * curr;
- }, 1);
-
- for (var n = 0; n < numPerms; n++) {
- self.items.push(new Item(arrs.map(function (arr, idx) {
- return arr[Math.floor(n / divs[idx]) % arr.length];
- })));
- }
+ var args = [].slice.call(arguments);
+ this.items.push(new Item(args));
this.sort();
return this;
-};
+}
/**
* Removes item from the stack.
*/
Middler.prototype.remove = function (fn) {
for (var idx in this.items) {
- if (this.items[idx].fn === fn) {
- this.items.splice(idx, 1);
+ for (var idx2 in this.items[idx].fns) {
+ if (this.items[idx].fns[idx2] === fn) {
+ this.items.splice(idx, 1);
+ return this;
+ }
}
}
return this;
View
8 test/add-dupe.js → test/dupe.js
@@ -1,4 +1,4 @@
-describe('add dupe', function () {
+describe('dupe', function () {
var server, port;
before(function (done) {
listen(function (s, p) {
@@ -11,12 +11,14 @@ describe('add dupe', function () {
var ran = [];
function mw1 (req, res, next) { ran.push('mw1'); next(); };
function mw2 (req, res, next) { ran.push('mw2'); next(); };
+ function mw3 (req, res, next) { ran.push('mw3'); next(); };
+ function mw4 (req, res, next) { ran.push('mw4'); next(); };
it('does not dupe', function (done) {
middler(server)
- .add(['get', 'post'], '/services/*', [mw1, mw2])
+ .add(['get', 'post'], '/services/*', [mw1, mw2, mw3, mw4])
.add(function (req, res) {
- assert.deepEqual(ran, ['mw1', 'mw2']);
+ assert.deepEqual(ran, ['mw1', 'mw2', 'mw3', 'mw4']);
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('ok');
})

0 comments on commit fab29cb

Please sign in to comment.