Permalink
Browse files

Merge remote branch 'maritz/master'

  • Loading branch information...
2 parents 8ec5002 + bfec7d9 commit 84af6180bbded6fb4a0ac57ed9504f2e198fdff5 @chetan51 committed Dec 21, 2010
Showing with 117 additions and 2 deletions.
  1. +37 −0 README.md
  2. +80 −2 lib/ni.js
View
@@ -49,6 +49,43 @@ If no controller is specified (`http://myapp.com/`), it loads the `home` control
If no function is specified (http://yourapp.com/[controller]), it loads the `[controller]`'s `index` function.
+You can define custom routes using Ni.addRoute(source, destination[, method]);
+
+Some examples:
+
+With this custom route calling myapp.com will internally redirect to use your News controller and call the index function on it:
+ Ni.addRoute('/', '/News/index');
+
+You can use regular expressions as well. This leads myapp.com/register to your User controller and its "register" function:
+ Ni.addRoute(/^\/register/i, '/User/register');
+
+If you want to use arguments with custom routes, you can do that as well:
+ Ni.addRoute(/^\/details\/(.*)$/i, '/User/details/$1');
+
+You can also define functions to test the path. For example:
+Calling myapp.com/add/1/2 will internally redirect to use the "Number" controller and call the "positive" function, while calling
+myapp.com/add/1/-2 will call the "negative" function.
+ Ni.addRoute(function(path) {
+ var args = path.split('/'),
+ firstNum = parseInt(args[2]),
+ secondNum = parseInt(args[3]),
+ result = firstNum + secondNum;
+ if (args[1] !== 'add')
+ return false; // this leaves the path untouched and prevents this function from sucking in all other requests as well
+ return result > 0 ? '/Number/positive' : '/Number/negative';
+ });
+
+You can limit the allowed HTTP methods by using custom routes.
+This will internally redirect myapp.com/comment to use your "Comments" controler and its "new" function - but only if the used HTTP Method is POST or PUT:
+
+ Ni.addRoute('/comment', '/Comments/new', ['POST', 'PUT']);
+
+And this will redirect all GET requests to myapp.com/comment to use your "Comments" controllers index function.
+ Ni.addRoute('/comment', '/Comments/', 'GET');
+
+This way you can disallow methods for some routes as well:
+ Ni.addRoute('/Comments/update', '/Home/method_not_allowed', 'GET');
+
Can I see an example?
---------------------
View
@@ -60,6 +60,9 @@ var Ni = function() {
// default view directory name
this.config('view_dir', 'views');
+ // default view directory name
+ this.config('custom_routes', []);
+
/*
* Loads controllers, models, views, templates and helpers from the root
* directory, and makes them all available to the Ni object.
@@ -105,11 +108,18 @@ var Ni = function() {
this.router = function(req, res, next) {
var parsedUrl = require('url').parse(req.url, true),
- pathArr = parsedUrl.pathname.split('/'),
- args = pathArr.slice(3),
+ pathArr,
+ args,
controller,
fn;
+ parsedUrl = Ni.checkCustomRoutes(parsedUrl.pathname, req.method);
+ if (parsedUrl.indexOf('/') !== 0) {
+ parsedUrl = '/' + parsedUrl;
+ }
+ pathArr = parsedUrl.split('/');
+ args = pathArr.slice(3);
+
res.Ni = { view: Ni.config('automatic_views') };
args.unshift(next);
@@ -169,6 +179,74 @@ var Ni = function() {
}
+ /*
+ * Add a custom route with a source (can be string, regex or function) and destination (string).
+ *
+ * If a route matches, the path is rewritten to the specified destination.
+ *
+ * A string route matches if it is exactly the same as the path. It rewrites to exactly the given destination.
+ * A regex route matches if it matches the path. It rewrites to path.replace(source, destination).
+ * A function matches if - given the path and custom route object - it returns a non-falsy value. It rewrites to the return of the function if that is a string or to the given destination.
+ */
+ this.addRoute = function (src, dest, method) {
+ if (arguments.length < 2 && typeof(src) !== 'function') {
+ throw new Error('Ni.addRoute expects 2 arguments if the first is not a function - '+arguments.length+' were given.');
+ }
+ var routes = Ni.config('custom_routes') || [];
+ routes.push({
+ src: src,
+ dest: dest || '/',
+ method: method || false
+ });
+ Ni.config('custom_routes', routes);
+ }
+
+ /*
+ * Checks the given url for the first matching custom route.
+ */
+ this.checkCustomRoutes = function (path, method) {
+ var routes = Ni.config('custom_routes');
+ if (!Array.isArray(routes) || routes.length === 0)
+ return path;
+ for (var i = 0, len = routes.length; i < len; i++) {
+ var route = routes[i]
+ , type = typeof(route.src),
+ methodMatch = !route.method; // if no method is specified in the route, automatically set to matched
+
+ if (!methodMatch && Array.isArray(route.method)) {
+ for (var n = 0, lenn = route.method.length; n < lenn; n++) {
+ if (route.method[n].toUpperCase() === method)
+ methodMatch = true;
+ }
+ } else if (!methodMatch) {
+ methodMatch = route.method === method;
+ }
+ if (methodMatch && type !== 'undefined') {
+ switch(type) {
+ case 'string':
+ if (path === route.src) {
+ return route.dest;
+ }
+ break;
+ case 'function':
+ if (typeof(route.src.exec) !== 'undefined') {
+ // regex
+ if (route.src.exec(path)) {
+ return path.replace(route.src, route.dest);
+ }
+ } else {
+ // function
+ var result = route.src(path, route);
+ if (result) {
+ return typeof(result) === 'string' ? result : route.dest;
+ }
+ }
+ }
+ }
+ }
+ return path;
+ }
+
this.renderView = function (renderer) {
if (typeof(renderer) === 'function') {

0 comments on commit 84af618

Please sign in to comment.