Skip to content

Commit

Permalink
Refactored router. Closes expressjs#639
Browse files Browse the repository at this point in the history
  • Loading branch information
tj committed May 23, 2011
1 parent 610fc92 commit 80e9ffb
Show file tree
Hide file tree
Showing 7 changed files with 460 additions and 307 deletions.
3 changes: 2 additions & 1 deletion Makefile
@@ -1,12 +1,13 @@

DOCS = $(shell find docs/*.md)
HTMLDOCS =$(DOCS:.md=.html)
TESTS = $(shell find test/*.test.js)

test:
@NODE_ENV=test ./node_modules/.bin/expresso \
-I lib \
$(TESTFLAGS) \
test/*.test.js
$(TESTS)

test-cov:
@TESTFLAGS=--cov $(MAKE) test
Expand Down
139 changes: 87 additions & 52 deletions lib/http.js
Expand Up @@ -12,8 +12,10 @@
var qs = require('qs')
, connect = require('connect')
, router = require('./router')
, methods = router.methods.concat('del', 'all')
, Router = require('./router')
, view = require('./view')
, toArray = require('./utils').toArray
, methods = router.methods.concat('del', 'all')
, url = require('url')
, utils = connect.utils;

Expand Down Expand Up @@ -86,11 +88,11 @@ app.init = function(middleware){
// apply middleware
if (middleware) middleware.forEach(self.use.bind(self));

// use router, expose as app.get(), etc
var fn = router(function(app){ self.routes = app; }, this);
// router
this.routes = new Router(this);
this.__defineGetter__('router', function(){
this.__usedRouter = true;
return fn;
return self.routes.middleware;
});

// default locals
Expand All @@ -113,38 +115,62 @@ app.init = function(middleware){
// so that they disregard definition position.
this.on('listening', this.registerErrorHandlers.bind(this));

// route lookup methods
this.remove = function(url){
return self.remove.all(url);
};

this.match = function(url){
return self.match.all(url);
};

this.lookup = function(url){
return self.lookup.all(url);
};

// route manipulation methods
methods.forEach(function(method){
self.match[method] = function(url){
return self.router.match(url, 'all' == method
? null
: method);
self.lookup[method] = function(path){
return self.routes.lookup(method, path);
};

self.remove[method] = function(url){
return self.router.remove(url, 'all' == method
? null
: method);
self.match[method] = function(path){
return self.routes.match(method, path);
};

self.lookup[method] = function(path){
return self.router.lookup(path, 'all' == method
? null
: method);
self.remove[method] = function(path){
return self.routes.lookup(method, path).remove();
};
});

// del -> delete
self.lookup.del = self.lookup.delete;
self.match.del = self.match.delete;
self.remove.del = self.remove.delete;
};

/**
* Remove routes matching the given `path`.
*
* @param {Route} path
* @return {Boolean}
* @api public
*/

app.remove = function(path){
return this.routes.lookup('all', path).remove();
};

/**
* Lookup routes defined with a path
* equivalent to `path`.
*
* @param {Stirng} path
* @return {Array}
* @api public
*/

app.lookup = function(path){
return this.routes.lookup('all', path);
};

/**
* Lookup routes matching the given `url`.
*
* @param {Stirng} url
* @return {Array}
* @api public
*/

app.match = function(url){
return this.routes.match('all', url);
};

/**
Expand Down Expand Up @@ -464,37 +490,46 @@ app.redirect = function(key, url){
*/

app.configure = function(env, fn){
if ('function' == typeof env) {
fn = env, env = 'all';
}
if ('all' == env || env == this.settings.env) {
fn.call(this);
}
if ('function' == typeof env) fn = env, env = 'all';
if ('all' == env || env == this.settings.env) fn.call(this);
return this;
};

// Generate routing methods
/**
* Delegate `.VERB(...)` calls to `.route(VERB, ...)`.
*/

methods.forEach(function(method){
app[method] = function(path){
var self = this;

// Lookup
if (1 == arguments.length) {
return this.router.lookup(path, 'all' == method
? null
: method);
}

// Ensure router is mounted
if (1 == arguments.length) return this.routes.lookup(method, path);
var args = [method].concat(toArray(arguments));
if (!this.__usedRouter) this.use(this.router);

// Generate the route
this.routes[method].apply(this, arguments);
return this;
};
return this.routes._route.apply(this.routes, args);
}
});

// Alias delete as "del"
/**
* Special-cased "all" method, applying the given route `path`,
* middleware, and callback to _every_ HTTP method.
*
* @param {String} path
* @param {Function} ...
* @return {Server} for chaining
* @api public
*/

app.all = function(path){
var args = arguments;
if (1 == args.length) return this.routes.lookup('all', path);
methods.forEach(function(method){
if ('all' == method) return;
app[method].apply(this, args);
}, this);
return this;
};

// del -> delete alias

app.del = app.delete;


53 changes: 53 additions & 0 deletions lib/router/collection.js
@@ -0,0 +1,53 @@

/*!
* Express - router - Collection
* Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/

/**
* Expose `Collection`.
*/

module.exports = Collection;

/**
* Initialize a new route `Collection`
* with the given `router`.
*
* @param {Router} router
* @api private
*/

function Collection(router) {
Array.apply(this, arguments);
this.router = router;
}

/**
* Inherit from `Array.prototype`.
*/

Collection.prototype.__proto__ = Array.prototype;

/**
* Remove the routes in this collection.
*
* @return {Collection} of routes removed
* @api public
*/

Collection.prototype.remove = function(){
var router = this.router
, len = this.length
, ret = new Collection(this.router);

for (var i = 0; i < len; ++i) {
if (router.remove(this[i])) {
ret.push(this[i]);
}
}

return ret;
};

0 comments on commit 80e9ffb

Please sign in to comment.