Skip to content

Instantly share code, notes, and snippets.

@amio
Last active August 29, 2015 14:01
Show Gist options
  • Save amio/4b1ad7c99dce73998930 to your computer and use it in GitHub Desktop.
Save amio/4b1ad7c99dce73998930 to your computer and use it in GitHub Desktop.
A simple router.

百姓一道题,粗糙的路由轮子

index.js 中测试代码:

router.add('/a/:id', fn1);
router.add('/a/b', fn2);

生成的路由结构为:

{
  a: {
    handlers: [],
    subs: {
      ':': {
        handlers: [fn1],
        subs: []
      },
      b: {
        handlers: [fn2],
        subs: []
      }
    }
  }
}
var router = require('./simple-router.js');
var a = false;
var b = '';
var c = {};
var route_a = router.add('/a/:id', function (id) {
b = id;
});
// Absolute-Route's priority are higher than Paramed-Route
var route_b = router.add('/a/b', function () {
a = true;
});
var route_c = router.add('/a/:name/info/:more', function (name, more) {
c.name = name;
c.more = more;
});
router.dispatch('/a/b/');
router.dispatch('/a/123/');
router.dispatch('/a/bob/info/home');
router.dispatch('/d/'); // Mismatch
console.assert(a === true);
console.assert(b === '123');
console.assert(c.name === 'bob' && c.more === 'home');
console.assert(route_a.generate({id: 123}) === '/a/123');
console.assert(route_b.generate({id: 123}) === '/a/b');
console.assert(route_c.generate({name: 'bob', less: 'eiyo'}) === '/a/bob/info/:more');
console.assert(route_c.generate({name: 'bob', more: 'home'}) === '/a/bob/info/home');
module.exports = new Router();
/**
* Router
* @constructor
*/
function Router() {
var routes = {};
// Register a route handler
this.add = function addRoute(route, fn) {
// Parse "/a/:id" to ["a", ":id"]
var segments = route.split('/').filter(function (item) { return item !== '' });
// Build the route tree of segments
var currentRoute = routes, segment, routeSegment;
while (segments.length) {
// Selected & Register routeSegment
segment = segments.shift();
routeSegment = /^:/.test(segment) ? ':' : segment;
if (!currentRoute[routeSegment]) {
currentRoute[routeSegment] = { handlers: [], subs: {} };
}
// Next
currentRoute = currentRoute[routeSegment];
segments.length && (currentRoute = currentRoute.subs);
}
// Register handler to final route
currentRoute.handlers.push(fn);
return new Route(route);
};
// Dispatch route handlers
this.dispatch = function dispatchRoutes(url) {
// Parse "/a/123" to ["a", "123"]
var segments = url.split('/').filter(function (item) { return item !== '' });
// Find a matched route
var route = routes, seg, args = [];
while (segments.length) {
seg = segments.shift();
if (route[seg]) {
route = route[seg];
} else if (route[':']) {
route = route[':'];
args.push(seg);
} else {
console.log('Unknown Request:', url);
return;
}
// Next
segments.length && (route = route.subs);
}
// Call handlers
if (route.handlers.length) {
route.handlers.forEach(function (fn) {
fn.apply(this, args);
});
} else {
console.log('Unknown Request:', url);
}
};
this.debug = function () {
return { routes: routes };
};
}
/**
* Route
* @param route
* @constructor
*/
function Route(route) {
this.route = route;
}
Route.prototype.generate = function generateUrlByRoute(args) {
return this.route.replace(/:(\w+)/g, function (match, name) {
return args[name] || match;
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment