locomotive
Advanced tools
Comparing version 0.3.3 to 0.3.4
@@ -6,2 +6,4 @@ /** | ||
, util = require('util') | ||
, methods = require('methods') | ||
, handle = require('./middleware/handle') | ||
, utils = require('./utils') | ||
@@ -132,7 +134,10 @@ , Namespace = require('./namespace') | ||
*/ | ||
Router.prototype.match = function(pattern, shorthand, options) { | ||
if (!options && typeof shorthand === 'object') { | ||
Router.prototype.match = function(pattern, shorthand, opts) { | ||
var options = opts || {}; | ||
if (!opts && typeof shorthand === 'object') { | ||
options = shorthand; | ||
} | ||
options = options || {}; | ||
if (typeof opts == 'function' && typeof arguments[arguments.length - 1] == 'object') { | ||
options = arguments[arguments.length - 1]; | ||
} | ||
@@ -156,5 +161,13 @@ if (typeof shorthand === 'string') { | ||
if (typeof shorthand === 'function' || Array.isArray(shorthand)) { | ||
var callbacks = utils.flatten([].slice.call(arguments, 1)); | ||
// pop off any final options argument | ||
if (typeof callbacks[callbacks.length - 1] != 'function') { callbacks.pop(); } | ||
// Mount functions or arrays of functions directly as Express route | ||
// handlers/middleware. | ||
this._http[method](path, shorthand); | ||
if (callbacks.length == 1) { | ||
this._http[method](path, callbacks[0]); | ||
} else { | ||
this._http[method](path, callbacks); | ||
} | ||
} else { | ||
@@ -166,3 +179,64 @@ this._route(method, path, controller, action, { helper: helper }); | ||
/** | ||
* Create a verb route matching `pattern`. | ||
* | ||
* A POST request that will be handled by `BandsController.create()` can be | ||
* specified using shorthand notation: | ||
* | ||
* this.post('bands', 'bands#create'); | ||
* | ||
* which is equivalent to using `controller` and `action` options. | ||
* | ||
* this.post('bands', { controller: 'bands', action: 'create' }); | ||
* | ||
* Verb routes are syntactic sugar for `match` routes. | ||
* | ||
* | ||
* Verb routes also mean Locomotive's router implements support for the complete | ||
* API exposed by Express for routing, making it easy to migrate routes from | ||
* Express to Locomotive. | ||
* | ||
* For example, reusing existing middleware for a user API. | ||
* | ||
* this.get('/user/:id', user.load, function(req, res) { | ||
* res.json(req.locals.user); | ||
* }); | ||
* | ||
* | ||
* Options: | ||
* | ||
* - 'controller' the route's controller | ||
* - 'action' the route's action | ||
* - `as` name used to declare routing helpers | ||
* | ||
* @param {String} pattern | ||
* @param {String|Object} shorthand | ||
* @param {Object} options | ||
* @api public | ||
*/ | ||
methods.forEach(function(method) { | ||
if (method == 'delete') { method = 'del' }; | ||
Router.prototype[method] = function(pattern, shorthand, options) { | ||
var args = [].slice.call(arguments) | ||
, opts = {} | ||
, la = arguments[arguments.length - 1]; | ||
if (typeof la == 'object' && typeof la != 'function' && !Array.isArray(la)) { | ||
args = [].slice.call(arguments, 0, arguments.length - 1); | ||
opts = arguments[arguments.length - 1]; | ||
} | ||
opts.via = method; | ||
args.push(opts); | ||
this.match.apply(this, args); | ||
}; | ||
}); | ||
// delete -> del alias | ||
Router.prototype.delete = Router.prototype.del; | ||
/** | ||
* Create resourceful routes for singleton resource `name`. | ||
@@ -221,3 +295,4 @@ * | ||
var ns = this._ns[this._ns.length - 1] | ||
var actions = [ 'new', 'create', 'show', 'edit', 'update', 'destroy' ] | ||
, ns = this._ns[this._ns.length - 1] | ||
, path = ns.qpath(name) | ||
@@ -227,9 +302,29 @@ , controller = ns.qcontroller(name) | ||
this._route('get' , path + '/new.:format?' , controller, 'new' , { helper: utils.helperize('new', helper) }); | ||
this._route('post', path , controller, 'create' ); | ||
this._route('get' , path + '.:format?' , controller, 'show' , { helper: helper }); | ||
this._route('get' , path + '/edit.:format?', controller, 'edit' , { helper: utils.helperize('edit', helper) }); | ||
this._route('put' , path , controller, 'update' ); | ||
this._route('del' , path , controller, 'destroy'); | ||
if (options.only) { | ||
actions = Array.isArray(options.only) ? options.only : [ options.only ]; | ||
} else if (options.except) { | ||
var except = Array.isArray(options.except) ? options.except : [ options.except ]; | ||
actions = actions.filter(function(a) { | ||
return except.indexOf(a) == -1; | ||
}); | ||
} | ||
var self = this; | ||
actions.forEach(function(action) { | ||
switch (action) { | ||
case 'new': self._route('get' , path + '/new.:format?' , controller, 'new' , { helper: utils.helperize('new', helper) }); | ||
break; | ||
case 'create': self._route('post', path , controller, 'create' ); | ||
break; | ||
case 'show': self._route('get' , path + '.:format?' , controller, 'show' , { helper: helper }); | ||
break; | ||
case 'edit': self._route('get' , path + '/edit.:format?', controller, 'edit' , { helper: utils.helperize('edit', helper) }); | ||
break; | ||
case 'update': self._route('put' , path , controller, 'update' ); | ||
break; | ||
case 'destroy': self._route('del' , path , controller, 'destroy'); | ||
break; | ||
} | ||
}); | ||
this.namespace(name, { module: options.namespace ? name : null, helper: name }, function() { | ||
@@ -291,3 +386,4 @@ fn && fn.call(this); | ||
var ns = this._ns[this._ns.length - 1] | ||
var actions = [ 'index', 'new', 'create', 'show', 'edit', 'update', 'destroy' ] | ||
, ns = this._ns[this._ns.length - 1] | ||
, singular = lingo.en.singularize(name) | ||
@@ -300,10 +396,31 @@ , path = ns.qpath(name) | ||
this._route('get' , path + '.:format?' , controller, 'index' , { helper: collectionHelper }); | ||
this._route('get' , path + '/new.:format?' , controller, 'new' , { helper: utils.helperize('new', helper) }); | ||
this._route('post', path , controller, 'create' ); | ||
this._route('get' , path + '/:id.:format?' , controller, 'show' , { helper: helper }); | ||
this._route('get' , path + '/:id/edit.:format?', controller, 'edit' , { helper: utils.helperize('edit', helper) }); | ||
this._route('put' , path + '/:id' , controller, 'update' ); | ||
this._route('del' , path + '/:id' , controller, 'destroy'); | ||
if (options.only) { | ||
actions = Array.isArray(options.only) ? options.only : [ options.only ]; | ||
} else if (options.except) { | ||
var except = Array.isArray(options.except) ? options.except : [ options.except ]; | ||
actions = actions.filter(function(a) { | ||
return except.indexOf(a) == -1; | ||
}); | ||
} | ||
var self = this; | ||
actions.forEach(function(action) { | ||
switch (action) { | ||
case 'index': self._route('get' , path + '.:format?' , controller, 'index' , { helper: collectionHelper }); | ||
break; | ||
case 'new': self._route('get' , path + '/new.:format?' , controller, 'new' , { helper: utils.helperize('new', helper) }); | ||
break; | ||
case 'create': self._route('post', path , controller, 'create' ); | ||
break; | ||
case 'show': self._route('get' , path + '/:id.:format?' , controller, 'show' , { helper: helper }); | ||
break; | ||
case 'edit': self._route('get' , path + '/:id/edit.:format?', controller, 'edit' , { helper: utils.helperize('edit', helper) }); | ||
break; | ||
case 'update': self._route('put' , path + '/:id' , controller, 'update' ); | ||
break; | ||
case 'destroy': self._route('del' , path + '/:id' , controller, 'destroy'); | ||
break; | ||
} | ||
}); | ||
placeholder = ':' + utils.helperize(singular) + '_id'; | ||
@@ -406,31 +523,4 @@ this.namespace(name + '/' + placeholder, { module: options.namespace ? name : null, helper: singular }, function() { | ||
/** | ||
* Builds a function to handle a route with given `controller` and `action`. | ||
* | ||
* @param {String} controller | ||
* @param {String} action | ||
* @return {Function} | ||
* @api private | ||
*/ | ||
function handle(controller, action) { | ||
return function(req, res, next){ | ||
var prototype = this.controller(controller); | ||
if (!prototype) { | ||
return next(new RouterError('No controller for ' + controller + '#' + action)); | ||
} | ||
// Create a new instance of the controller from the prototype. The | ||
// prototype acts as a "factory" from which an instance is created for each | ||
// request. This allows request-specific properties to be assigned to each | ||
// instance, without causing conflicts due to concurrency. | ||
var instance = Object.create(prototype); | ||
instance._init(req, res, next); | ||
instance._invoke(action); | ||
} | ||
} | ||
/** | ||
* Expose `Router`. | ||
*/ | ||
exports = module.exports = Router; |
@@ -504,2 +504,24 @@ /** | ||
/** | ||
* Flatten the given `arr`. | ||
* | ||
* @param {Array} arr | ||
* @return {Array} | ||
* @api private | ||
*/ | ||
exports.flatten = function(arr, ret){ | ||
var ret = ret || [] | ||
, len = arr.length; | ||
for (var i = 0; i < len; ++i) { | ||
if (Array.isArray(arr[i])) { | ||
exports.flatten(arr[i], ret); | ||
} else { | ||
ret.push(arr[i]); | ||
} | ||
} | ||
return ret; | ||
}; | ||
/** | ||
* Forward `functions` from `from` to `to`. | ||
@@ -506,0 +528,0 @@ * |
{ | ||
"name": "locomotive", | ||
"version": "0.3.3", | ||
"version": "0.3.4", | ||
"description": "Powerful MVC web framework for Node.js.", | ||
@@ -22,2 +22,3 @@ "author": { "name": "Jared Hanson", "email": "jaredhanson@gmail.com", "url": "http://www.jaredhanson.net/" }, | ||
"express": "3.x.x", | ||
"methods": "0.0.1", | ||
"async": "0.1.x", | ||
@@ -24,0 +25,0 @@ "lingo": "0.0.x", |
Sorry, the diff of this file is not supported yet
94093
27
2898
9
+ Addedmethods@0.0.1
+ Addedmethods@0.0.1(transitive)