Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
s3u committed Dec 6, 2010
0 parents commit c1bfb46
Show file tree
Hide file tree
Showing 5 changed files with 225 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
@@ -0,0 +1,4 @@
*.iml
.DS_Store
.idea
temp
23 changes: 23 additions & 0 deletions 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.
//
Empty file added README.md
Empty file.
107 changes: 107 additions & 0 deletions examples/ex.js
@@ -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');
91 changes: 91 additions & 0 deletions lib/middleware/resource.js
@@ -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.