From f8b954bcd9a6aeaa5d445a1ea1bbcb37e089f3ef Mon Sep 17 00:00:00 2001 From: Roman Shtylman Date: Wed, 26 Feb 2014 19:57:11 -0500 Subject: [PATCH] make express.Router() return a Router function instance Similar to how express() returns an express `app` instance which is also a function, express.Router() returns the Router instance which is also a function and can be easily used via another router or the app. app.use(express.Router()); --- lib/router/index.js | 50 +++++++++++++++++++++++---------------------- test/Router.js | 26 ++++++++++++++++++++++- test/app.options.js | 2 +- 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/lib/router/index.js b/lib/router/index.js index 2d7596d3..755ef96f 100644 --- a/lib/router/index.js +++ b/lib/router/index.js @@ -9,31 +9,32 @@ var Route = require('./route') , debug = require('debug')('express:router') , parseUrl = utils.parseUrl; -/** - * Expose `Router` constructor. - */ - -exports = module.exports = Router; - /** * Initialize a new `Router` with the given `options`. * * @param {Object} options - * @api private + * @return {Router} which is an callable function + * @api public */ -function Router(options) { +var proto = module.exports = function(options) { options = options || {}; - var self = this; - self.params = {}; - self._params = []; - self.caseSensitive = options.caseSensitive; - self.strict = options.strict; - self.stack = []; + function router(req, res, next) { + router.handle(req, res, next); + }; - self.middleware = self.handle.bind(self); -} + // mixin Router class functions + router.__proto__ = proto; + + router.params = {}; + router._params = []; + router.caseSensitive = options.caseSensitive; + router.strict = options.strict; + router.stack = []; + + return router; +}; /** * Map the given param placeholder `name`(s) to the given callback. @@ -69,7 +70,7 @@ function Router(options) { * @api public */ -Router.prototype.param = function(name, fn){ +proto.param = function(name, fn){ // param logic if ('function' == typeof name) { this._params.push(name); @@ -107,7 +108,7 @@ Router.prototype.param = function(name, fn){ * @api private */ -Router.prototype.handle = function(req, res, done) { +proto.handle = function(req, res, done) { var self = this; debug('dispatching %s %s', req.method, req.url); @@ -127,7 +128,7 @@ Router.prototype.handle = function(req, res, done) { var options = []; // middleware and routes - var stack = this.stack; + var stack = self.stack; // for options requests, respond with a default if nothing else responds if (method === 'options') { @@ -242,7 +243,7 @@ Router.prototype.handle = function(req, res, done) { * @api private */ -Router.prototype.process_params = function(route, req, res, done) { +proto.process_params = function(route, req, res, done) { var self = this; var params = this.params; @@ -317,7 +318,7 @@ Router.prototype.process_params = function(route, req, res, done) { * @api public */ -Router.prototype.use = function(route, fn){ +proto.use = function(route, fn){ // default route to '/' if ('string' != typeof route) { @@ -356,7 +357,7 @@ Router.prototype.use = function(route, fn){ * @api public */ -Router.prototype.route = function(path){ +proto.route = function(path){ var route = new Route(path); var layer = Layer(path, { @@ -381,7 +382,7 @@ Router.prototype.route = function(path){ * @api public */ -Router.prototype.all = function(path, fn) { +proto.all = function(path, fn) { var route = this.route(path); methods.forEach(function(method){ route[method](fn); @@ -390,9 +391,10 @@ Router.prototype.all = function(path, fn) { // create Router#VERB functions methods.forEach(function(method){ - Router.prototype[method] = function(path, fn){ + proto[method] = function(path, fn){ var self = this; self.route(path)[method](fn); return self; }; }); + diff --git a/test/Router.js b/test/Router.js index 28ca0670..30d8b5a4 100644 --- a/test/Router.js +++ b/test/Router.js @@ -6,7 +6,31 @@ var express = require('../') describe('Router', function(){ - describe('.middleware', function(){ + it('should return a function with router methods', function() { + var router = Router(); + assert(typeof router == 'function'); + + var router = new Router(); + assert(typeof router == 'function'); + + assert(typeof router.get == 'function'); + assert(typeof router.handle == 'function'); + assert(typeof router.use == 'function'); + }); + + it('should support .use of other routers', function(done) { + var router = Router(); + var another = Router(); + + another.get('/bar', function(req, res) { + res.done(); + }); + router.use('/foo', another); + + router.handle({ url: '/foo/bar', method: 'GET' }, { done: done }); + }); + + describe('.handle', function(){ it('should dispatch', function(done){ var router = new Router(); diff --git a/test/app.options.js b/test/app.options.js index 8b4bdc1c..6678b6cd 100644 --- a/test/app.options.js +++ b/test/app.options.js @@ -31,7 +31,7 @@ describe('OPTIONS', function(){ var router = new express.Router(); router.get('/users', function(req, res){}); - app.use(router.middleware); + app.use(router); app.get('/other', function(req, res){}); request(app)