Permalink
Browse files

Initial commit

  • Loading branch information...
s3u committed Dec 6, 2010
0 parents commit c1bfb46bab0475633da289b86b71dae3bc37c1a9
Showing with 225 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +23 −0 LICENSE
  3. 0 README.md
  4. +107 −0 examples/ex.js
  5. +91 −0 lib/middleware/resource.js
@@ -0,0 +1,4 @@
+*.iml
+.DS_Store
+.idea
+temp
23 LICENSE
@@ -0,0 +1,23 @@
+// (The MIT License)
+//
+// Copyright (c) 2010 Sencha Inc.
+//
+// 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.
+//
No changes.
@@ -0,0 +1,107 @@
+
+var users = [
+ { name: 'tj' },
+ { name: 'tim' }
+];
+
+function user(app) {
+ app.resource('/.:format?', {
+ 'get' : function(req, res, next) {
+ switch (req.params.format) {
+ case 'json':
+ var body = JSON.stringify(users);
+ res.writeHead(200, {
+ 'Content-Type': 'application/json',
+ 'Content-Length': body.length
+ });
+ res.end(body);
+ break;
+ default:
+ var body = '<ul>'
+ + users.map(function(user) {
+ return '<li>' + user.name + '</li>';
+ }).join('\n')
+ + '</ul>';
+ res.writeHead(200, {
+ 'Content-Type': 'text/html',
+ 'Content-Length': body.length
+ });
+ res.end(body);
+ }
+ }
+ });
+
+ app.resource('/:id.:format', {
+ 'get' : function(req, res, next) {
+ var user = users[req.params.id];
+ if (user && req.params.format === 'json') {
+ user = JSON.stringify(user);
+ res.writeHead(200, {
+ 'Content-Type': 'application/json',
+ 'Content-Length': user.length
+ });
+ res.end(user);
+ } else {
+ // When true is passed, provide control
+ // back to middleware, skipping route
+ // match attemps
+ next(true);
+ }
+ }
+ })
+
+ app.resource('/:id/:op?', {
+ 'get' : function(req, res) {
+ var body = users[req.params.id]
+ ? users[req.params.id].name
+ : 'User ' + req.params.id + ' does not exist';
+ body = (req.params.op || 'view') + 'ing ' + body;
+ res.writeHead(200, {
+ 'Content-Type': 'text/html',
+ 'Content-Length': body.length
+ });
+ res.end(body, 'utf8');
+ }
+ })
+}
+
+
+function main(app) {
+ app.resource('/', {
+ 'get' : function(req, res) {
+ var examples = [
+ '/users',
+ '/users.json',
+ '/users/0 (or /users/0/view)',
+ '/users/0/edit',
+ '/users/0.json'
+ ];
+ var body = 'Visit one of the following: <ul>'
+ + examples.map(function(str) {
+ return '<li>' + str + '</li>'
+ }).join('\n')
+ + '</ul>';
+ res.writeHead(200, {
+ 'Content-Type': 'text/html',
+ 'Content-Length': body.length
+ });
+ res.end(body, 'utf8');
+ }
+ });
+}
+
+
+var connect = require('connect');
+var resource = require('lib/middleware/resource');
+
+var server = connect.createServer(
+// connect.logger({ buffer: true }),
+// connect.cache(),
+// connect.gzip(),
+// resource
+);
+
+server.use('/users', resource(user));
+server.use(resource(main));
+server.listen(3000);
+console.log('Connect server listening on port 3000');
@@ -0,0 +1,91 @@
+var sys = require('sys');
+var parse = require('url').parse,
+ querystring = require('querystring');
+
+module.exports = function resource(fn) {
+ var routes, self = this;
+ var paths;
+
+ if (fn == undefined) {
+ throw new Error('No handler provider requires a callback function');
+ }
+
+ paths = [];
+
+ var app = {
+ resource: function(path, obj) {
+ obj.keys = [];
+ obj.path = normalizePath(path, obj.keys);
+ paths.push(obj);
+ }
+ }
+
+ // fn is the main app
+ sys.log(sys.inspect(fn));
+ fn.call(this, app);
+
+ sys.log(sys.inspect(paths));
+
+ return function resource(req, res, next) {
+ // Match to a resource - i.e., match to each path regexp
+ var method = req.method.toLowerCase();
+ var url = parse(req.url);
+ sys.log(sys.inspect(url));
+ var pathname = url.pathname;
+ for(var i = 0; i < paths.length; i++) {
+ var path = paths[i].path;
+ var keys = paths[i].keys;
+ sys.log(path);
+ var captures = path.exec(pathname);
+ sys.log(sys.inspect(paths[i]));
+ if(captures) {
+ // There is a match. Execute the handler
+ sys.log("match found");
+
+ // Prepare params
+ var params = [];
+ for(var j = 1, len = captures.length; j < len; ++j) {
+ var key = keys[j - 1],
+ val = typeof captures[j] === 'string'
+ ? querystring.unescape(captures[j])
+ : captures[j];
+ if (key) {
+ params[key] = val;
+ } else {
+ params.push(val);
+ }
+ }
+ req.params = params;
+
+ if(paths[i][method]) {
+ return paths[i][method](req, res, next);
+ }
+ else {
+ res.writeHead(405);
+ res.end();
+ }
+ }
+ }
+ next();
+ };
+}
+
+function normalizePath(path, keys) {
+ path = path
+ .concat('/?')
+ .replace(/\/\(/g, '(?:/')
+ .replace(/(\/)?(\.)?:(\w+)(\?)?/g, function(_, slash, format, key, optional) {
+ keys.push(key);
+ slash = slash || '';
+ return ''
+ + (optional ? '' : slash)
+ + '(?:'
+ + (optional ? slash : '')
+ + (format || '') + '([^/.]+))'
+ + (optional || '');
+ })
+ .replace(/([\/.])/g, '\\$1')
+ .replace(/\*/g, '(.+)');
+ return new RegExp('^' + path + '$', 'i');
+}
+

0 comments on commit c1bfb46

Please sign in to comment.