Permalink
Browse files

Added res.locals.use(). Closes #1120

  • Loading branch information...
1 parent f3a32f2 commit dd33ef2eb6570881262105a7f73442759039c46e @tj tj committed May 3, 2012
Showing with 150 additions and 25 deletions.
  1. +4 −19 lib/application.js
  2. +8 −5 lib/middleware.js
  3. +1 −1 lib/response.js
  4. +33 −0 lib/utils.js
  5. +104 −0 test/res.locals.use.js
View
23 lib/application.js
@@ -14,6 +14,7 @@ var connect = require('connect')
, methods = Router.methods.concat('del', 'all')
, middleware = require('./middleware')
, debug = require('debug')('express:application')
+ , locals = require('./utils').locals
, View = require('./view')
, url = require('url')
, utils = connect.utils
@@ -64,25 +65,6 @@ app.defaultConfiguration = function(){
this.use(connect.query());
this.use(middleware.init(this));
- // app locals
- this.locals = function(obj){
- for (var key in obj) self.locals[key] = obj[key];
- return self;
- };
-
- // response locals
- this.locals.use = function(fn){
- if (3 == fn.length) {
- self.viewCallbacks.push(fn);
- } else {
- self.viewCallbacks.push(function(req, res, done){
- fn(req, res);
- done();
- });
- }
- return this;
- };
-
// inherit view callbacks
this.on('mount', function(parent){
this.request.__proto__ = parent.request;
@@ -101,6 +83,9 @@ app.defaultConfiguration = function(){
return this._router.middleware;
});
+ // setup locals
+ this.locals = locals(this);
+
// default locals
this.locals.settings = this.settings;
View
13 lib/middleware.js
@@ -1,11 +1,17 @@
/*!
* Express - middleware
- * Copyright(c) 2010-2011 TJ Holowaychuk <tj@vision-media.ca>
+ * Copyright(c) 2010-2012 TJ Holowaychuk <tj@vision-media.ca>
* MIT Licensed
*/
/**
+ * Module dependencies.
+ */
+
+var utils = require('./utils');
+
+/**
* Initialization middleware, exposing the
* request and response to eachother, as well
* as defaulting the X-Powered-By header field.
@@ -26,10 +32,7 @@ exports.init = function(app){
req.__proto__ = app.request;
res.__proto__ = app.response;
- res.locals = function(obj){
- for (var key in obj) res.locals[key] = obj[key];
- return res;
- };
+ res.locals = utils.locals(res);
next();
}
View
2 lib/response.js
@@ -627,7 +627,7 @@ res.render = function(view, options, fn){
}
// invoke view callbacks
- var callbacks = app.viewCallbacks
+ var callbacks = app.viewCallbacks.concat(self.viewCallbacks)
, pending = callbacks.length
, len = pending
, done;
View
33 lib/utils.js
@@ -12,6 +12,39 @@
var mime = require('mime');
/**
+ * Make `locals()` bound to the given `obj`.
+ *
+ * This is used for `app.locals` and `res.locals`.
+ *
+ * @param {Object} obj
+ * @return {Function}
+ * @api private
+ */
+
+exports.locals = function(obj){
+ obj.viewCallbacks = obj.viewCallbacks || [];
+
+ function locals(obj){
+ for (var key in obj) locals[key] = obj[key];
+ return obj;
+ };
+
+ locals.use = function(fn){
+ if (3 == fn.length) {
+ obj.viewCallbacks.push(fn);
+ } else {
+ obj.viewCallbacks.push(function(req, res, done){
+ fn(req, res);
+ done();
+ });
+ }
+ return obj;
+ };
+
+ return locals;
+};
+
+/**
* Check if `path` looks absolute.
*
* @param {String} path
View
104 test/res.locals.use.js
@@ -0,0 +1,104 @@
+
+var express = require('../')
+ , request = require('./support/http');
+
+describe('res', function(){
+ describe('.locals.use(fn)', function(){
+ it('should run in parallel on res.render()', function(done){
+ var app = express();
+ var calls = [];
+ app.set('views', __dirname + '/fixtures');
+
+ app.locals.first = 'tobi';
+
+ app.use(function(req, res, next){
+ res.locals.use(function(req, res, done){
+ process.nextTick(function(){
+ calls.push('one');
+ res.locals.last = 'holowaychuk';
+ done();
+ });
+ });
+ next();
+ });
+
+ app.use(function(req, res, next){
+ res.locals.use(function(req, res, done){
+ process.nextTick(function(){
+ calls.push('two');
+ res.locals.species = 'ferret';
+ done();
+ });
+ });
+ next();
+ });
+
+ app.use(function(req, res){
+ calls.push('render');
+ res.render('pet.jade');
+ });
+
+ request(app)
+ .get('/')
+ .end(function(res){
+ calls.should.eql(['render', 'one', 'two']);
+ res.body.should.equal('<p>tobi holowaychuk is a ferret</p>');
+ done();
+ })
+ })
+
+ describe('with arity < 3', function(){
+ it('should done() for you', function(done){
+ var app = express();
+
+ app.set('views', __dirname + '/fixtures');
+ app.locals.first = 'tobi';
+
+ app.use(function(req, res, next){
+ app.locals.use(function(req, res){
+ res.locals.last = 'holowaychuk';
+ res.locals.species = 'ferret';
+ });
+ next();
+ });
+
+ app.use(function(req, res){
+ res.render('pet.jade');
+ });
+
+ request(app)
+ .get('/')
+ .end(function(res){
+ res.body.should.equal('<p>tobi holowaychuk is a ferret</p>');
+ done();
+ })
+ })
+ })
+
+ it('should not override res.render() locals', function(done){
+ var app = express();
+
+ app.set('views', __dirname + '/fixtures');
+ app.locals.first = 'tobi';
+
+ app.use(function(req, res, next){
+ app.locals.use(function(req, res){
+ res.locals.last = 'holowaychuk';
+ res.locals.species = 'ferret';
+ });
+ next();
+ });
+
+ app.use(function(req, res){
+ res.render('pet.jade', { last: 'ibot' });
+ });
+
+ request(app)
+ .get('/')
+ .end(function(res){
+ res.body.should.equal('<p>tobi ibot is a ferret</p>');
+ done();
+ })
+ })
+ })
+})

0 comments on commit dd33ef2

Please sign in to comment.