Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

overhaul item matching, resolves #4

  • Loading branch information...
commit fab29cbce4c5c0e4d0151383524e10d555844c10 1 parent dd4a671
Carlos Rodriguez authored December 13, 2012
3  Makefile
... ...
@@ -1,7 +1,6 @@
1 1
 test:
2 2
 	@./node_modules/.bin/mocha \
3 3
 		--reporter spec \
4  
-		--bail \
5 4
 		--require test/common.js
6 5
 
7 6
 bench: install-bench bench-middleware bench-routing
@@ -30,4 +29,4 @@ bench-routing: install-bench
30 29
 		--path bench/paths.txt \
31 30
 		bench/routing/*.js
32 31
 
33  
-.PHONY: test bench
  32
+.PHONY: test bench
133  lib/item.js
... ...
@@ -1,84 +1,127 @@
1 1
 var currentId = 0
2  
-  , parseUrl = require('./parseUrl')
  2
+  , parseUrl = require('../').parseUrl
3 3
   , pathRegExp = require('../').pathRegExp
  4
+  , Middler
4 5
 
5 6
 function Item (args) {
6 7
   this.weight = 0;
7  
-  
  8
+
  9
+  this.paths = [];
  10
+  this.methods = [];
  11
+  this.fns = [];
  12
+
8 13
   var self = this;
9 14
 
10 15
   Array.prototype.slice.call(args).forEach(function (arg) {
11 16
     if (typeof arg === 'object') {
12 17
       // Item properties
13  
-      Object.keys(arg).forEach(function (k) {
14  
-        self[k] = arg[k];
  18
+      arg = Object.keys(arg).map(function (k) {
  19
+        return arg[k];
15 20
       });
16 21
     }
17  
-    else if (arg instanceof RegExp || (typeof arg === 'string' && arg[0] === '/')) {
18  
-      // Implied path string/regex
19  
-      self.path = arg;
20  
-    }
21  
-    else if (typeof arg === 'number') {
22  
-      // Implied weight
23  
-      self.weight = arg;
24  
-    }
25  
-    else if (typeof arg === 'string') {
26  
-      // Implied HTTP method
27  
-      self.method = arg;
28  
-    }
29  
-    else if (typeof arg === 'function') {
30  
-      // middleware handler
31  
-      self.fn = arg;
  22
+    if (!Array.isArray(arg)) {
  23
+      arg = [arg];
32 24
     }
  25
+    arg.forEach(function (arg) {
  26
+      if (arg instanceof RegExp || (typeof arg === 'string' && arg[0] === '/')) {
  27
+        // Implied path string/regex
  28
+        self.paths.push(arg);
  29
+      }
  30
+      else if (typeof arg === 'number') {
  31
+        // Implied weight
  32
+        self.weight = arg;
  33
+      }
  34
+      else if (typeof arg === 'string') {
  35
+        // Implied HTTP method
  36
+        self.methods.push(arg);
  37
+      }
  38
+      else if (typeof arg === 'function') {
  39
+        // middleware handler
  40
+        self.fns.push(arg);
  41
+      }
  42
+    });
33 43
   });
34 44
 
35  
-  if (!this.fn) {
  45
+  if (!this.fns.length) {
36 46
     throw new Error('middler expected a middleware callback of some kind');
37 47
   }
38 48
 
39  
-  if (this.method) {
40  
-    this.method = this.method.toUpperCase();
41  
-  }
42  
-  if (this.path) {
43  
-    this.params = [];
44  
-    this.regex = pathRegExp(this.path, this.params, true, true);
  49
+  this.methods = this.methods.map(function (method) {
  50
+    return method.toUpperCase();
  51
+  });
  52
+
  53
+  if (this.paths.length) {
  54
+    this.paramses = [];
  55
+    this.regexes = this.paths.map(function (p) {
  56
+      var params = [];
  57
+      self.paramses.push(params);
  58
+      return pathRegExp(p, params, true, true);
  59
+    });
45 60
   }
46 61
 
47 62
   this.id = currentId++;
  63
+
  64
+  if (this.fns.length === 1) {
  65
+    this.fn = this.fns[0];
  66
+  }
  67
+  else {
  68
+    // Embed a middler instance to handle the chaining!
  69
+    if (typeof Middler === 'undefined') {
  70
+      Middler = require('../').Middler;
  71
+    }
  72
+    this.chain = new Middler();
  73
+    this.fns.forEach(function (fn) {
  74
+      self.chain.add(fn);
  75
+    });
  76
+    this.fn = this.chain.handler;
  77
+  }
48 78
 }
49 79
 module.exports = Item;
50 80
 
  81
+function inArray (val, arr) {
  82
+  if (!arr || !arr.length) return false;
  83
+  for (var i in arr) {
  84
+    if (arr[i] === val) return true;
  85
+  }
  86
+  return false;
  87
+}
  88
+
51 89
 Item.prototype.match = function(req) {
52  
-  if (this.method && this.method !== req.method && req.method !== 'HEAD') {
  90
+  if (this.methods.length && req.method !== 'HEAD' && !inArray(req.method, this.methods)) {
53 91
     return false;
54 92
   }
55  
-  if (!this.path) {
  93
+  if (!this.paths.length) {
56 94
     return true;
57 95
   }
58 96
 
59 97
   var reqPath = parseUrl(req).pathname;
60 98
 
61 99
   // Exact match
62  
-  if (reqPath === this.path) return {};
  100
+  if (inArray(reqPath, this.paths)) return {};
63 101
 
64  
-  // Try the regex
65  
-  var matches = this.regex.exec(reqPath)
  102
+  var self = this;
66 103
 
67  
-  if (!matches) return false;
68  
-  matches.shift();
  104
+  for (var i in this.regexes) {
  105
+    // Try the regex
  106
+    var matches = this.regexes[i].exec(reqPath);
69 107
 
70  
-  var self = this
71  
-    , params = []
  108
+    if (!matches) continue;
  109
+    matches.shift();
72 110
 
73  
-  matches.forEach(function (val, idx) {
74  
-    var key = self.params[idx];
  111
+    var params = [];
75 112
 
76  
-    if (key) {
77  
-      params[key.name] = val;
78  
-    }
79  
-    else {
80  
-      params.push(val);
81  
-    }
82  
-  });
83  
-  return params;
  113
+    matches.forEach(function (val, idx) {
  114
+      var key = self.paramses[i][idx];
  115
+
  116
+      if (key) {
  117
+        params[key.name] = val;
  118
+      }
  119
+      else {
  120
+        params.push(val);
  121
+      }
  122
+    });
  123
+    return params;
  124
+  }
  125
+
  126
+  return false;
84 127
 };
35  lib/middler.js
... ...
@@ -1,5 +1,4 @@
1  
-var matcher = require('../').matcher
2  
-  , parseUrl = require('./parseUrl')
  1
+var parseUrl = require('../').parseUrl
3 2
   , pathRegExp = require('../').pathRegExp
4 3
   , Item = require('../').Item
5 4
   , inherits = require('util').inherits
@@ -87,39 +86,23 @@ Middler.prototype.handler = function middlerKernel (req, res, next) {
87 86
  * Adds item(s) onto the stack.
88 87
  */
89 88
 Middler.prototype.add = function addItem () {
90  
-  var args = [].slice.call(arguments)
91  
-    , self = this
92  
-    , divs = []
93  
-
94  
-  // If arrays are passed, push an item for every permutation.
95  
-  // Credit: http://stackoverflow.com/a/4331713
96  
-  var arrs = args.map(function (val) {
97  
-    return Array.isArray(val) ? val : [val];
98  
-  });
99  
-  for (var i = arrs.length - 1; ~i; i--) {
100  
-    divs[i] = divs[i + 1] ? divs[i + 1] * arrs[i + 1].length : 1;
101  
-  }
102  
-  var numPerms = divs.reduce(function (prev, curr) {
103  
-    return prev * curr;
104  
-  }, 1);
105  
-
106  
-  for (var n = 0; n < numPerms; n++) {
107  
-    self.items.push(new Item(arrs.map(function (arr, idx) {
108  
-      return arr[Math.floor(n / divs[idx]) % arr.length];
109  
-    })));
110  
-  }
  89
+  var args = [].slice.call(arguments);
111 90
 
  91
+  this.items.push(new Item(args));
112 92
   this.sort();
113 93
   return this;
114  
-};
  94
+}
115 95
 
116 96
 /**
117 97
  * Removes item from the stack.
118 98
  */
119 99
 Middler.prototype.remove = function (fn) {
120 100
   for (var idx in this.items) {
121  
-    if (this.items[idx].fn === fn) {
122  
-      this.items.splice(idx, 1);
  101
+    for (var idx2 in this.items[idx].fns) {
  102
+      if (this.items[idx].fns[idx2] === fn) {
  103
+        this.items.splice(idx, 1);
  104
+        return this;
  105
+      }
123 106
     }
124 107
   }
125 108
   return this;
8  test/add-dupe.js → test/dupe.js
... ...
@@ -1,4 +1,4 @@
1  
-describe('add dupe', function () {
  1
+describe('dupe', function () {
2 2
   var server, port;
3 3
   before(function (done) {
4 4
     listen(function (s, p) {
@@ -11,12 +11,14 @@ describe('add dupe', function () {
11 11
   var ran = [];
12 12
   function mw1 (req, res, next) { ran.push('mw1'); next(); };
13 13
   function mw2 (req, res, next) { ran.push('mw2'); next(); };
  14
+  function mw3 (req, res, next) { ran.push('mw3'); next(); };
  15
+  function mw4 (req, res, next) { ran.push('mw4'); next(); };
14 16
 
15 17
   it('does not dupe', function (done) {
16 18
     middler(server)
17  
-      .add(['get', 'post'], '/services/*', [mw1, mw2])
  19
+      .add(['get', 'post'], '/services/*', [mw1, mw2, mw3, mw4])
18 20
       .add(function (req, res) {
19  
-        assert.deepEqual(ran, ['mw1', 'mw2']);
  21
+        assert.deepEqual(ran, ['mw1', 'mw2', 'mw3', 'mw4']);
20 22
         res.writeHead(200, {'Content-Type': 'text/plain'});
21 23
         res.end('ok');
22 24
       })

0 notes on commit fab29cb

Please sign in to comment.
Something went wrong with that request. Please try again.