Permalink
Browse files

init

  • Loading branch information...
kilianc committed Apr 30, 2012
0 parents commit 9ea9db17b98a9e8f84366ca455e41718549faf8c
Showing with 493 additions and 0 deletions.
  1. +3 −0 .travis.yml
  2. +22 −0 LICENSE
  3. +18 −0 Makefile
  4. +138 −0 README.md
  5. +3 −0 index.js
  6. +131 −0 lib-cov/router.js
  7. +56 −0 lib/router.js
  8. +24 −0 package.json
  9. +17 −0 test/fixtures/router-module.js
  10. +1 −0 test/mocha.opts
  11. +80 −0 test/router-test.js
@@ -0,0 +1,3 @@
+language: node_js
+node_js:
+ - 0.6
22 LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2011 Kilian Ciuffolo, me@nailik.org
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,18 @@
+REPORTER = spec
+
+test:
+ @NODE_ENV=test ./node_modules/.bin/mocha test/*-test.js $(OPT) --reporter $(REPORTER)
+
+test-bail:
+ $(MAKE) test OPT=--bail
+
+test-cov:
+ $(MAKE) lib-cov
+ @APISERVER_ROUTER_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html
+ @open -g coverage.html
+
+lib-cov:
+ @rm -rf lib-cov
+ @jscoverage lib lib-cov
+
+.PHONY: test test-ba test-cov lib-cov
138 README.md
@@ -0,0 +1,138 @@
+# apiserver-router [![build status](https://secure.travis-ci.org/kilianc/node-apiserver-router.png?branch=master)](http://travis-ci.org/kilianc/node-apiserver-router)
+
+A fast API router with integrated caching system bundled with [ApiServer](https://github.com/kilianc/node-apiserver)
+
+## Installation
+
+ ⚡ npm install apiserver-router
+
+```javascript
+var Router = require('apiserver-router')
+```
+
+## Example
+
+```javascript
+var UserModule = function (options) {
+ this.options = options
+}
+
+// will be translated into /1/random_photo_module/create_album
+UserModule.prototype.createAlbum = function (request, response) { ... }
+
+// will be translated into /1/random_photo_module/upload_photo
+UserModule.prototype.uploadPhoto = function (request, response) { ... }
+
+// private method, skipped
+UserModule.prototype._checkFileExtension = function (request, response) { ... }
+
+```
+
+```javascript
+router.update({ '1': { randomPhotoModule: UserModule } })
+router.get('/1/random_photo_module/upload_photo') // returns the associated chain
+```
+
+## Class Method: constructor
+
+### Syntax:
+
+```javascript
+new Router()
+```
+
+## Class Method: update
+
+Builds and caches the routes. You must call it every time a middleware or a module changes.
+
+### Syntax:
+
+```javascript
+Router.prototype.update(modules[, middlewareList])
+```
+
+### Arguments:
+
+* __modules__ - (`Object`) an hashtable of [API modules](https://github.com/kilianc/node-apiserver/tree/master#modules)
+* __middlewareList__ - (`Array`) a list of [middleware](https://github.com/kilianc/node-apiserver/tree/master#middleware)
+
+### Example:
+
+```javascript
+...
+var router = new Router()
+router.update({
+ v1: {
+ user: {
+ signin: function (request, response) { /* function body */ },
+ signout: function (request, response) { /* function body */ },
+ signup: function (request, response) { /* function body */ }
+ }
+ }
+}, [
+ { route: /signup/, handle: randomMiddleware1 },
+ { route: /sign/, handle: randomMiddleware2 }
+])
+...
+```
+
+## Class Method: get
+
+This method returns a list of functions that will be executed with [fnchain](https://github.com/kilianc/node-fnchain). The list will contain all the middleware active for the API endpoint reached by `pathname` and as last ring of the chain the API method to execute.
+
+### Syntax:
+
+```javascript
+Router.prototype.get(pathname)
+```
+
+### Arguments:
+
+* __pathname__ - (`String`)
+
+### Example:
+
+```javascript
+...
+router.get('/v1/users/signup')
+...
+```
+
+# How to contribute
+
+This repository follows (more or less) the [Felix's Node.js Style Guide](http://nodeguide.com/style.html), your contribution must be consistent with this style.
+
+The test suite is written on top of [visionmedia/mocha](http://visionmedia.github.com/mocha/) and it took hours of hard work. Please use the tests to check if your contribution breaks some part of the library and add new tests for each new feature.
+
+ ⚡ npm test
+
+and for your test coverage
+
+ ⚡ make test-cov
+
+## License
+
+_This software is released under the MIT license cited below_.
+
+ Copyright (c) 2010 Kilian Ciuffolo, me@nailik.org. All Rights Reserved.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the 'Software'), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,3 @@
+module.exports = process.env.APISERVER_ROUTER_COV
+ ? require('./lib-cov/router')
+ : require('./lib/router')
@@ -0,0 +1,131 @@
+/* automatically generated by JSCoverage - do not edit */
+if (typeof _$jscoverage === 'undefined') _$jscoverage = {};
+if (! _$jscoverage['router.js']) {
+ _$jscoverage['router.js'] = [];
+ _$jscoverage['router.js'][1] = 0;
+ _$jscoverage['router.js'][2] = 0;
+ _$jscoverage['router.js'][5] = 0;
+ _$jscoverage['router.js'][6] = 0;
+ _$jscoverage['router.js'][7] = 0;
+ _$jscoverage['router.js'][8] = 0;
+ _$jscoverage['router.js'][9] = 0;
+ _$jscoverage['router.js'][10] = 0;
+ _$jscoverage['router.js'][11] = 0;
+ _$jscoverage['router.js'][12] = 0;
+ _$jscoverage['router.js'][13] = 0;
+ _$jscoverage['router.js'][15] = 0;
+ _$jscoverage['router.js'][16] = 0;
+ _$jscoverage['router.js'][17] = 0;
+ _$jscoverage['router.js'][20] = 0;
+ _$jscoverage['router.js'][21] = 0;
+ _$jscoverage['router.js'][22] = 0;
+ _$jscoverage['router.js'][23] = 0;
+ _$jscoverage['router.js'][24] = 0;
+ _$jscoverage['router.js'][25] = 0;
+ _$jscoverage['router.js'][27] = 0;
+ _$jscoverage['router.js'][33] = 0;
+ _$jscoverage['router.js'][36] = 0;
+ _$jscoverage['router.js'][37] = 0;
+ _$jscoverage['router.js'][40] = 0;
+ _$jscoverage['router.js'][41] = 0;
+ _$jscoverage['router.js'][42] = 0;
+ _$jscoverage['router.js'][43] = 0;
+ _$jscoverage['router.js'][46] = 0;
+ _$jscoverage['router.js'][47] = 0;
+ _$jscoverage['router.js'][48] = 0;
+ _$jscoverage['router.js'][49] = 0;
+ _$jscoverage['router.js'][50] = 0;
+ _$jscoverage['router.js'][51] = 0;
+ _$jscoverage['router.js'][55] = 0;
+}
+_$jscoverage['router.js'][1]++;
+var Router = module.exports = (function () {
+ _$jscoverage['router.js'][2]++;
+ this.routes = {};
+});
+_$jscoverage['router.js'][5]++;
+Router.prototype.update = (function (modules, middlewareList) {
+ _$jscoverage['router.js'][6]++;
+ var routes = Object.create(null);
+ _$jscoverage['router.js'][7]++;
+ var map = Object.create(null);
+ _$jscoverage['router.js'][8]++;
+ Object.keys(modules).forEach((function (version) {
+ _$jscoverage['router.js'][9]++;
+ Object.keys(modules[version]).forEach((function (moduleName) {
+ _$jscoverage['router.js'][10]++;
+ var module_name = moduleName.replace(/([A-Z][a-z][^A-Z]*)/g, "_$1").toLowerCase();
+ _$jscoverage['router.js'][11]++;
+ Object.keys(modules[version][moduleName]).forEach((function (methodName) {
+ _$jscoverage['router.js'][12]++;
+ if (methodName[0] === "_") {
+ _$jscoverage['router.js'][13]++;
+ return;
+ }
+ _$jscoverage['router.js'][15]++;
+ var route = getRoutePath(version, module_name, methodName);
+ _$jscoverage['router.js'][16]++;
+ if (routes[route]) {
+ _$jscoverage['router.js'][17]++;
+ throw new Error("Routing conflict on \"" + route + "\": " + map[route].version + "." + map[route].moduleName + "." + map[route].methodName + " is anbiguous with " + version + "." + moduleName + "." + methodName);
+ }
+ _$jscoverage['router.js'][20]++;
+ map[route] = {version: version, moduleName: moduleName, methodName: methodName};
+ _$jscoverage['router.js'][21]++;
+ var chain = routes[route] = getChain(middlewareList, route);
+ _$jscoverage['router.js'][22]++;
+ chain.push((function (request, response, callback) {
+ _$jscoverage['router.js'][23]++;
+ try {
+ _$jscoverage['router.js'][24]++;
+ modules[version][moduleName][methodName](request, response);
+ _$jscoverage['router.js'][25]++;
+ callback();
+ }
+ catch (err) {
+ _$jscoverage['router.js'][27]++;
+ callback(err);
+ }
+}));
+}));
+}));
+}));
+ _$jscoverage['router.js'][33]++;
+ this.routes = routes;
+});
+_$jscoverage['router.js'][36]++;
+Router.prototype.get = (function (pathname) {
+ _$jscoverage['router.js'][37]++;
+ return this.routes[pathname];
+});
+_$jscoverage['router.js'][40]++;
+function getRoutePath(version, module_name, methodName) {
+ _$jscoverage['router.js'][41]++;
+ var words = [];
+ _$jscoverage['router.js'][42]++;
+ methodName.replace(/([A-Za-z][^A-Z]*)/g, (function (match) {
+ _$jscoverage['router.js'][42]++;
+ words.push(match);
+}));
+ _$jscoverage['router.js'][43]++;
+ return ["", version, module_name, words.join("_")].join("/").toLowerCase();
+}
+_$jscoverage['router.js'][46]++;
+function getChain(middlewareList, route) {
+ _$jscoverage['router.js'][47]++;
+ var chain = [];
+ _$jscoverage['router.js'][48]++;
+ if (middlewareList) {
+ _$jscoverage['router.js'][49]++;
+ middlewareList.forEach((function (middleware) {
+ _$jscoverage['router.js'][50]++;
+ if (route.match(middleware.route)) {
+ _$jscoverage['router.js'][51]++;
+ chain.push(middleware.handle);
+ }
+}));
+ }
+ _$jscoverage['router.js'][55]++;
+ return chain;
+}
+_$jscoverage['router.js'].source = ["var Router = module.exports = function () {"," this.routes = {}","}","","Router.prototype.update = function (modules, middlewareList) {"," var routes = Object.create(null)"," var map = Object.create(null)"," Object.keys(modules).forEach(function (version) {"," Object.keys(modules[version]).forEach(function (moduleName) {"," var module_name = moduleName.replace(/([A-Z][a-z][^A-Z]*)/g, '_$1').toLowerCase()"," Object.keys(modules[version][moduleName]).forEach(function (methodName) {"," if (methodName[0] === '_') {"," return"," }"," var route = getRoutePath(version, module_name, methodName)"," if (routes[route]) {"," throw new Error('Routing conflict on \"' + route + '\": ' + map[route].version + '.' + map[route].moduleName + '.' + map[route].methodName +"," ' is anbiguous with ' + version + '.' + moduleName + '.' + methodName)"," }"," map[route] = { version: version, moduleName: moduleName, methodName: methodName }"," var chain = routes[route] = getChain(middlewareList, route)"," chain.push(function (request, response, callback) {"," try {"," modules[version][moduleName][methodName](request, response)"," callback()"," } catch (err) {"," callback(err)"," }"," })"," })"," })"," })"," this.routes = routes","}","","Router.prototype.get = function (pathname) {"," return this.routes[pathname]","}","","function getRoutePath(version, module_name, methodName) {"," var words = []"," methodName.replace(/([A-Za-z][^A-Z]*)/g, function (match) { words.push(match) })"," return ['', version, module_name, words.join('_')].join('/').toLowerCase()","}","","function getChain(middlewareList, route) {"," var chain = []"," if (middlewareList) {"," middlewareList.forEach(function (middleware) {"," if (route.match(middleware.route)) {"," chain.push(middleware.handle)"," }"," })"," }"," return chain","}"];
@@ -0,0 +1,56 @@
+var Router = module.exports = function () {
+ this.routes = {}
+}
+
+Router.prototype.update = function (modules, middlewareList) {
+ var routes = Object.create(null)
+ var map = Object.create(null)
+ Object.keys(modules).forEach(function (version) {
+ Object.keys(modules[version]).forEach(function (moduleName) {
+ var module_name = moduleName.replace(/([A-Z][a-z][^A-Z]*)/g, '_$1').toLowerCase()
+ Object.keys(modules[version][moduleName]).forEach(function (methodName) {
+ if (methodName[0] === '_') {
+ return
+ }
+ var route = getRoutePath(version, module_name, methodName)
+ if (routes[route]) {
+ throw new Error('Routing conflict on "' + route + '": ' + map[route].version + '.' + map[route].moduleName + '.' + map[route].methodName +
+ ' is anbiguous with ' + version + '.' + moduleName + '.' + methodName)
+ }
+ map[route] = { version: version, moduleName: moduleName, methodName: methodName }
+ var chain = routes[route] = getChain(middlewareList, route)
+ chain.push(function (request, response, callback) {
+ try {
+ modules[version][moduleName][methodName](request, response)
+ callback()
+ } catch (err) {
+ callback(err)
+ }
+ })
+ })
+ })
+ })
+ this.routes = routes
+}
+
+Router.prototype.get = function (pathname) {
+ return this.routes[pathname]
+}
+
+function getRoutePath(version, module_name, methodName) {
+ var words = []
+ methodName.replace(/([A-Za-z][^A-Z]*)/g, function (match) { words.push(match) })
+ return ['', version, module_name, words.join('_')].join('/').toLowerCase()
+}
+
+function getChain(middlewareList, route) {
+ var chain = []
+ if (middlewareList) {
+ middlewareList.forEach(function (middleware) {
+ if (route.match(middleware.route)) {
+ chain.push(middleware.handle)
+ }
+ })
+ }
+ return chain
+}
Oops, something went wrong.

0 comments on commit 9ea9db1

Please sign in to comment.