Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/nrstott/bogart
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin committed Jan 31, 2013
2 parents df5e1ed + f425c90 commit ed3afb4
Show file tree
Hide file tree
Showing 14 changed files with 187 additions and 80 deletions.
4 changes: 4 additions & 0 deletions .travis.yml
@@ -0,0 +1,4 @@
language: node_js
node_js:
- 0.6
- 0.8
3 changes: 2 additions & 1 deletion README.md
@@ -1,3 +1,4 @@
[![build status](https://secure.travis-ci.org/nrstott/bogart.png)](http://travis-ci.org/nrstott/bogart)
# Bogart

A blazing fast rapid application development web framework using JSGI for [node](http://nodejs.org/).
Expand Down Expand Up @@ -48,7 +49,7 @@ If you can't run on 8080, change the `app.start` call e.g. `app.start(9090, '127

## Routing

Routing in Bogart is simple and intuitive. A route is a HTTP method paried with a
Routing in Bogart is simple and intuitive. A route is a HTTP method paired with a
URL matching pattern and a handler function.

var router = bogart.router();
Expand Down
13 changes: 0 additions & 13 deletions examples/haml-view/app.js

This file was deleted.

13 changes: 0 additions & 13 deletions examples/haml-view/package.json

This file was deleted.

2 changes: 0 additions & 2 deletions examples/haml-view/views/index.haml

This file was deleted.

4 changes: 2 additions & 2 deletions examples/task-list/app.js
Expand Up @@ -48,10 +48,10 @@ router.post("/", function(req) {
return bogart.redirect("/");
});

router.del("/:name", function(req, name) {
router.del("/:name", function(req) {
console.log('deleting '+req.params.name);
console.log(tasks);
delete tasks[name];
delete tasks[req.params.name];

return bogart.redirect("/");
});
Expand Down
42 changes: 17 additions & 25 deletions lib/bogart.js
Expand Up @@ -11,7 +11,7 @@ var
inherits = require('util').inherits,
EventEmitter = require('events').EventEmitter;

exports.version = [0,3,40];
exports.version = [0,3,45];

exports.q = Q;

Expand Down Expand Up @@ -56,11 +56,6 @@ exports.promisify = function(nodeAsyncFn, context) {
exports.middleware = middleware;
exports.batteries = middleware.batteries;

/**
* A request to a bogart router
*/
function Request() {}

/**
* Creates a request object given a router and a jsgi request.
* This function is primarily intended to be used internally by bogart; however, it could be
Expand All @@ -69,22 +64,19 @@ function Request() {}
* @type Request
*/
exports.request = function(router, jsgiReq) {
var
search = util.extractSearch(jsgiReq),
requestedWith = jsgiReq.headers['x-requested-with'],
isxhr = !util.no(requestedWith), parsedBody,
contentType = jsgiReq.headers['content-type'],
req = Object.create(new Request(), {
router: { value: router, enumerable: true, readonly: true },
search: { value: search, enumerable: true, readonly: true },
isXMLHttpRequest: { value: isxhr, enumerable: true, readonly: true }
});

for (var k in jsgiReq) {
Object.defineProperty(req, k, { value: jsgiReq[k], readonly: true, enumerable: true });
}

return req;
return Object.create(jsgiReq, {
router: { value: router },
search: {
get: function() {
return util.extractSearch(jsgiReq);
}
},
isXMLHttpRequest: {
get: function() {
return !util.no(this.headers['x-requested-with']);
}
}
});
};

/**
Expand Down Expand Up @@ -157,9 +149,9 @@ App.prototype.start = function(port, host, jsgiOptions) {
if (Router.isRouter(descriptor.middleware)) {
descriptor.middleware.nextApp = app;
app = descriptor.middleware;
} else {
app = descriptor.middleware.apply(descriptor.middleware, descriptor.args.concat([ app ]));
}

app = descriptor.middleware.apply(descriptor.middleware, descriptor.args.concat([ app ]));
});
}
jsgiOptions = jsgiOptions || {
Expand Down Expand Up @@ -240,7 +232,7 @@ exports.router = function(config, notFoundApp) {
return {
status: 404,
body: [body],
headers: { 'Content-Length': body.length, 'Content-Type': 'text/html' }
headers: { 'Content-Length': Buffer.byteLength(body, 'utf-8'), 'Content-Type': 'text/html' }
};
},
router = new Router(config),
Expand Down
41 changes: 33 additions & 8 deletions lib/middleware.js
Expand Up @@ -6,7 +6,8 @@ var Q = require('promised-io/promise'),
util = require('./util'),
merge = util.merge,
EventEmitter = require('events').EventEmitter,
_ = require('underscore');
_ = require('underscore'),
Router = require('./router').Router;

function join(forEachable) {
var body = '',
Expand Down Expand Up @@ -90,6 +91,9 @@ exports.gzip = exports.Gzip = function(nextApp) {
if (resp.headers['content-length']) {
delete resp.headers['content-length'];
}
if (resp.headers['Content-Length']) {
delete resp.headers['Content-Length'];
}

bogart.pump(resp.body, gzip);

Expand Down Expand Up @@ -723,37 +727,58 @@ exports.binary = function(conditional, appTrue, appFalse) {
*/
exports.cascade = function(accept /*, apps */) {
var args = Array.prototype.slice.call(arguments)
, apps = [];
, middlewareQueue = [];

accept = args.shift();

args.forEach(function(x) {
apps.push(x);
middlewareQueue.push(x);
});

return function(req) {
var cascadeApp = function(req) {
var deferred = Q.defer();

function next(apps) {
var nextAction = apps.shift();
function next() {
var nextAction = middlewareQueue.shift();

this.started = true;

if (Router.isRouter(nextAction)) {
nextAction.nextApp = next;
}

if (nextAction) {
Q.whenCall(function() { return nextAction(req); }, function(resp) {
if (accept(resp)) {
return deferred.resolve(resp);
} else {
return next(apps);
return next();
}
}, deferred.reject);
} else {
deferred.reject('No suitable Response found by cascade.');
}
}

next(apps.concat());
next();

return deferred.promise;
};

cascadeApp.use = function(middleware /*, parameters */) {
if (this.started) {
throw {
message: 'Cascade has already been started. The middleware may only be configured before it is started.',
code: 'BOGART_CASCADE_ALREADY_STARTED'
};
}

var args = Array.prototype.slice.call(arguments);

middlewareQueue.push(middleware);
};

return cascadeApp;
};

/**
Expand Down
1 change: 1 addition & 0 deletions lib/mimetypes.js
Expand Up @@ -98,6 +98,7 @@ exports.mimeTypes = {
".m3u" : "audio/x-mpegurl",
".m4v" : "video/mp4",
".man" : "text/troff",
".manifest": "text/cache-manifest",
".mathml" : "application/mathml+xml",
".mbox" : "application/mbox",
".mdoc" : "text/troff",
Expand Down
31 changes: 19 additions & 12 deletions lib/view.js
Expand Up @@ -10,6 +10,8 @@ var
settings = {},
_ = require('underscore'),
events = require('events'),
async = require('async'),
q = require('promised-io/promise'),
util = require('util');

// TODO: Figure out how to make this work x-platform using the nodules 'engines' overlay
Expand Down Expand Up @@ -221,27 +223,32 @@ exports.viewEngine.engine = function(engineName) {
};

exports.viewEngine.addEngine('mustache', function(str, opts, cache, viewEngine) {
var partialPromises = []
, partials = {}
var partials = {}
, viewPath;

opts = _.extend({}, opts);

if (opts.partials) {
for (var k in opts.partials) {
var defer = q.defer();

async.forEach(Object.keys(opts.partials), function(k, callback) {
viewPath = path.join(viewEngine.views, opts.partials[k]);

partialPromises.push(when(viewEngine.viewCache[viewPath] || viewEngine.cacheView(viewPath), function(str) {
when(viewEngine.viewCache[viewPath] || viewEngine.cacheView(viewPath), function(str) {
partials[k] = str;
return str;
}));
}

return promise.all(partialPromises).then(function() {
delete opts.partials;
callback();
});
}, function(err) {
delete opts.partials;

return require('mustache').to_html(str, opts.locals, partials);
if (err) {
defer.reject(err);
} else {
defer.resolve(require('mustache').to_html(str, opts.locals, partials));
}
});

return defer.promise;
}

return require('mustache').to_html(str, opts.locals);
Expand Down
8 changes: 5 additions & 3 deletions package.json
@@ -1,7 +1,7 @@
{
"name": "bogart",
"description": "Fast JSGI web framework taking inspiration from Sinatra",
"version": "0.3.40",
"version": "0.3.45",
"keywords": ["bogart", "framework", "sinatra", "REST"],
"author": "Nathan Stott <nrstott@gmail.com>",
"email": "nathan.stott@whiteboard-it.com",
Expand All @@ -19,14 +19,16 @@
"dependencies": {
"promised-io": "v0.3.0",
"jsgi": ">=v0.2.2",
"mustache": "0.3.1-dev",
"mustache": "0.7.2",
"underscore": ">=0.0.0",
"node-uuid": ">=1.2.0",
"parted": "=0.0.8",
"oauth": "=0.9.5",
"request": "=2.2.9",
"commander": "*",
"mkdirp": "*"
"mkdirp": "*",
"async": "0.1.22",
"promised-io": "0.2.3"
},
"devDependencies": {
"haml": ">=0.4.2",
Expand Down
58 changes: 57 additions & 1 deletion test/middleware.test.js
Expand Up @@ -5,7 +5,8 @@ var bogart = require('../lib/bogart')
, security = require("../lib/security")
, util = require('util')
, test = require('tap').test
, plan = require('tap').plan;
, plan = require('tap').plan
, mockRequest = require('./test-util').mockRequest;

test("test parses JSON", function(t) {
var forEachDeferred = Q.defer()
Expand Down Expand Up @@ -402,6 +403,61 @@ test("test bodyAdapter adapts Stream", function(t) {
});
});

test("test cascade works with a router", function(t){
var cascade = bogart.middleware.cascade(function() { return true; })
, router = bogart.router()
, txt = 'Hello World';

router.get('/', function(req){
return bogart.text(txt);
});

cascade.use(router);

var resPromise = cascade(mockRequest('/'));

resPromise.then(function(res){
t.equal(txt, res.body.join());
}, function(err){
t.ok(false, err, 'found error');
});

t.plan(1);
});

test("test cascade passes to second router", function(t){
var router1 = bogart.router()
, router2 = bogart.router()
, txt = 'Hello World'
, cascade = bogart.middleware.cascade(function(res) {
return res.status != 404;
});

router1.get('/', function(req) {
return {
status: 404,
body: []
};
});

router2.get('/', function(req) {
return bogart.text(txt);
});

cascade.use(router1);
cascade.use(router2);

var resPromise = cascade(mockRequest('/'));

resPromise.then(function(res) {
t.equal(txt, res.body.join());
}, function(err) {
t.ok(false, err, 'found error');
});

t.plan(1);
});

/**
* Create a mock request
*
Expand Down

0 comments on commit ed3afb4

Please sign in to comment.