commit 2a0f68e4347002a6520db14b90f27cf6723265be Author: Ritchie Martori Date: Tue Apr 9 09:02:36 2013 -0700 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..6af74074 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +*.seed +*.log +*.csv +*.dat +*.out +*.pid +*.swp +*.swo +node_modules/ diff --git a/README.md b/README.md new file mode 100644 index 00000000..54e386f1 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# asteroid +v0.0.1 + +## Install + + slnode install asteroid + +## Example + + var Asteroid = require('asteroid'); + var asteroid = Asteroid.create(); + + asteroid.myMethod(); \ No newline at end of file diff --git a/example/hello-world/app.js b/example/hello-world/app.js new file mode 100644 index 00000000..41ddc901 --- /dev/null +++ b/example/hello-world/app.js @@ -0,0 +1,8 @@ +var asteroid = require('../../'); +var app = asteroid(); + +app.get('/', function (req, res) { + res.send('hello world'); +}); + +app.listen(3000); \ No newline at end of file diff --git a/example/simple-resource/app.js b/example/simple-resource/app.js new file mode 100644 index 00000000..3bd67aa8 --- /dev/null +++ b/example/simple-resource/app.js @@ -0,0 +1,7 @@ +var asteroid = require('../../'); +var app = asteroid(); + +app.use(asteroid.configure()); +app.use(asteroid.resources()); + +app.listen(3000); \ No newline at end of file diff --git a/example/simple-resource/resources/example-resource/config.json b/example/simple-resource/resources/example-resource/config.json new file mode 100644 index 00000000..cd47866a --- /dev/null +++ b/example/simple-resource/resources/example-resource/config.json @@ -0,0 +1,8 @@ +{ + "module": "resource", + "options": { + "path": "/example-resource", + "msg": "my message?" + }, + "main": "example.js" +} \ No newline at end of file diff --git a/example/simple-resource/resources/example-resource/example.js b/example/simple-resource/resources/example-resource/example.js new file mode 100644 index 00000000..e7319e5c --- /dev/null +++ b/example/simple-resource/resources/example-resource/example.js @@ -0,0 +1,14 @@ +// any module instance can be required by its directory +var exampleResource = require('.'); + +// exampleResource.app is an express sub app +// anything registered (routes, middleware) +// will only run relative to the defined root +// '/' resolves to '/example-resource' +exampleResource.app.get('/', function (req, res) { + res.send(exampleResource.options.msg + '??????'); +}); + +exampleResource.app.get('/foo', function (req, res) { + res.send('foo!!!'); +}); \ No newline at end of file diff --git a/example/todos/app.js b/example/todos/app.js new file mode 100644 index 00000000..3bd67aa8 --- /dev/null +++ b/example/todos/app.js @@ -0,0 +1,7 @@ +var asteroid = require('../../'); +var app = asteroid(); + +app.use(asteroid.configure()); +app.use(asteroid.resources()); + +app.listen(3000); \ No newline at end of file diff --git a/example/todos/db/config.env.json b/example/todos/db/config.env.json new file mode 100644 index 00000000..402157a4 --- /dev/null +++ b/example/todos/db/config.env.json @@ -0,0 +1,12 @@ +{ + "production": { + "module": "mongo", + "options": { + "database": "todos", + "port": 5555, + "host": "remote.db.com", + "username": "foo", + "password": "bar" + } + } +} \ No newline at end of file diff --git a/example/todos/db/config.json b/example/todos/db/config.json new file mode 100644 index 00000000..a6fd9aa3 --- /dev/null +++ b/example/todos/db/config.json @@ -0,0 +1,11 @@ +{ + "module": "data-store", + "options": { + "database": "asteroid-examples-todos", + "port": 27017, + "host": "127.0.0.1" + }, + "dependencies": { + "db": "memory" + } +} \ No newline at end of file diff --git a/example/todos/todos/config.json b/example/todos/todos/config.json new file mode 100644 index 00000000..51925213 --- /dev/null +++ b/example/todos/todos/config.json @@ -0,0 +1,9 @@ +{ + "module": "collection", + "options": { + "path": "/todos" + }, + "dependencies": { + "model": "todos-model" + } +} \ No newline at end of file diff --git a/example/todos/todos/todos-model/config.json b/example/todos/todos/todos-model/config.json new file mode 100644 index 00000000..1ffe0275 --- /dev/null +++ b/example/todos/todos/todos-model/config.json @@ -0,0 +1,22 @@ +{ + "module": "model", + "options": { + "properties": [ + { + "name": "title", + "type": "string" + }, + { + "name": "done", + "type": "boolean" + }, + { + "name": "order", + "type": "number" + } + ] + }, + "dependencies": { + "data-store": "db" + } +} \ No newline at end of file diff --git a/example/todos/todos/todos.js b/example/todos/todos/todos.js new file mode 100644 index 00000000..fcf8582d --- /dev/null +++ b/example/todos/todos/todos.js @@ -0,0 +1,43 @@ +var todos = require('.'); + +todos.app.get('/completed', function (req, res) { + todos.store.all({where: {creator: req.me, done: true}}, todos.done); +}); + +todos.on('before:validate', function (todo, ctx) { + if(!todo.name) { + throw new Error('name is required'); + } + + if(todo.name.length > 144) { + ctx.error('name must be shorter than 144 characters'); + } +}); + +todos.on('before:create', function (todo, ctx, done) { + ctx.errorUnless(ctx.isEmail(todos.creator)); + + todos.model.count({owner: todo.owner}, function (err) { + if(err) { + done(err); + } else { + ctx.errorIf(count > 100, 'each user can only have 100 todos'); + + done(); + } + }); +}); + +todos.on('query', function (query, ctx) { + ctx.cancelUnless(query.creator); + query.$limit = query.$limit || 16; + ctx.errorIf(query.$limit > 16, 'todos can only include a maximum of 16 results'); +}); + +todos.on('modify', function (todo, ctx) { + ctx.cancelUnless(ctx.isMe(todo.creator)); +}); + +todos.on('request', function (ctx) { + ctx.cancelUnless(ctx.me); +}); \ No newline at end of file diff --git a/example/todos/users/config.json b/example/todos/users/config.json new file mode 100644 index 00000000..5ba02f38 --- /dev/null +++ b/example/todos/users/config.json @@ -0,0 +1,20 @@ +{ + "module": "users-collection", + "options": { + "root": "/users", + "name": "users", + "properties": [ + { + "name": "email", + "type": "string" + }, + { + "name": "password", + "type": "password" + } + ] + }, + "dependencies": { + "store": "store" + } +} \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 00000000..b465aeec --- /dev/null +++ b/index.js @@ -0,0 +1,5 @@ +/** + * asteroid ~ public api + */ + +module.exports = require('./lib/asteroid'); \ No newline at end of file diff --git a/lib/asteroid.js b/lib/asteroid.js new file mode 100644 index 00000000..1990713d --- /dev/null +++ b/lib/asteroid.js @@ -0,0 +1,76 @@ +/** + * Module dependencies. + */ + +var express = require('express') + , fs = require('fs') + , path = require('path') + , utils = express.utils; + +/** + * Expose `createApplication()`. + */ + +var asteroid = exports = module.exports = createApplication; + +/** + * Framework version. + */ + +asteroid.version = require('../package.json').version; + +/** + * Expose mime. + */ + +asteroid.mime = express.mime; + +/** + * Create an asteroid application. + * + * @return {Function} + * @api public + */ + +function createApplication() { + var app = express(); + + app.disuse = function (route) { + if(this.stack) { + for (var i = 0; i < this.stack.length; i++) { + if(this.stack[i].route === route) { + this.stack.splice(i, 1); + } + } + } + } + + return app; +} + +/** + * Expose express.middleware as asteroid.* + * for example `asteroid.errorHandler` etc. + */ + +for (var key in express) { + Object.defineProperty( + asteroid + , key + , Object.getOwnPropertyDescriptor(express, key)); +} + +/** + * Expose additional asteroid middleware + * for example `asteroid.configure` etc. + */ + +fs.readdirSync(path.join(__dirname, 'middleware')).forEach(function (m) { + asteroid[m.replace(/\.js$/, '')] = require('./middleware/' + m); +}); + +/** + * Error handler title + */ + +asteroid.errorHandler.title = 'Asteroid'; diff --git a/lib/middleware/configure.js b/lib/middleware/configure.js new file mode 100644 index 00000000..340ebcf1 --- /dev/null +++ b/lib/middleware/configure.js @@ -0,0 +1,25 @@ +/** + * Module dependencies. + */ + +var ModuleLoader = require('module-loader'); + +/** + * Export the middleware. + */ + +module.exports = configure; + +/** + * Load application modules based on the current directories configuration files. + */ + +function configure(root) { + var moduleLoader = ModuleLoader.create(root || '.'); + + return function configureMiddleware(req, res, next) { + req.modules = res.modules = moduleLoader; + moduleLoader.load(next); + } +} + diff --git a/lib/middleware/middleware.js b/lib/middleware/middleware.js new file mode 100644 index 00000000..76670614 --- /dev/null +++ b/lib/middleware/middleware.js @@ -0,0 +1,25 @@ +/** + * Module dependencies. + */ + +var ModuleLoader = require('module-loader'); + +/** + * Export the middleware. + */ + +module.exports = middleware; + +/** + * Load application modules based on the current directories configuration files. + */ + +function middleware() { + var modules = this.modules; + + return function executeAsteroidMiddleware(req, res, next) { + // TODO implement asteroid specific middleware stack + next(); + } +} + diff --git a/lib/middleware/resources.js b/lib/middleware/resources.js new file mode 100644 index 00000000..9b1a5498 --- /dev/null +++ b/lib/middleware/resources.js @@ -0,0 +1,32 @@ +/** + * Module dependencies. + */ + +var asteroid = require('../asteroid'); + +/** + * Export the middleware. + */ + +module.exports = resources; + +/** + * Build a temp app for mounting resources. + */ + +function resources() { + return function (req, res, next) { + // xxx - cache the temp app and only build when modules change? + var tempApp = asteroid(); + var resources = req.modules.instanceOf('Resource'); + + // mount all resources + resources.forEach(function (r) { + r.mount(tempApp); + }); + + tempApp.handle(req, res, next); + } +} + + diff --git a/package.json b/package.json new file mode 100644 index 00000000..3dca2bec --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "asteroid", + "description": "asteroid", + "version": "0.0.1", + "scripts": { + "test": "mocha" + }, + "dependencies": { + "debug": "latest", + "express": "~3.1.1" + }, + "devDependencies": { + "mocha": "latest" + } +} diff --git a/test/asteroid.test.js b/test/asteroid.test.js new file mode 100644 index 00000000..99bcfe2a --- /dev/null +++ b/test/asteroid.test.js @@ -0,0 +1,24 @@ +var Asteroid = require('../'); + +describe('Asteroid', function(){ + var asteroid; + + beforeEach(function(){ + asteroid = new Asteroid; + }); + + describe('.myMethod', function(){ + // example sync test + it('should ', function() { + asteroid.myMethod(); + }); + + // example async test + it('should ', function(done) { + setTimeout(function () { + asteroid.myMethod(); + done(); + }, 0); + }); + }); +}); \ No newline at end of file diff --git a/test/support.js b/test/support.js new file mode 100644 index 00000000..2a007e24 --- /dev/null +++ b/test/support.js @@ -0,0 +1,5 @@ +/** + * asteroid test setup and support. + */ + +assert = require('assert'); \ No newline at end of file