Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' into feature/socket.io-mvc

  • Loading branch information...
commit 230c09b972bf912b876fb821b7c4324095acfcee 2 parents 5d0b8b9 + 784ea41
@Techwraith Techwraith authored
Showing with 4,249 additions and 9,969 deletions.
  1. +1 −0  .gitignore
  2. +25 −15 README.md
  3. +27 −23 bin/cli.js
  4. +13 −0 changelog.md
  5. +5 −2 deps/templato/lib/engines/ejs.js
  6. +5 −2 deps/templato/lib/engines/handlebars.js
  7. +5 −2 deps/templato/lib/engines/jade.js
  8. +4 −2 deps/templato/lib/engines/mustache.js
  9. +72 −0 docs/1-architecture.md
  10. +110 −0 docs/2-router.md
  11. +210 −0 docs/3-controllers.md
  12. +548 −0 docs/4-models.md
  13. +333 −0 docs/5-templates.md
  14. +83 −0 docs/6-CLI.md
  15. +55 −0 docs/7-sessions.md
  16. +59 −0 docs/8-deployment.md
  17. +3 −3 examples/todo_app/app/controllers/todos.js
  18. +1 −5 examples/todo_app/config/init.js
  19. +0 −60 examples/todo_app/lib/model_adapters/todo.js
  20. +6 −14 examples/todo_app_coffee/app/controllers/todos.coffee
  21. +0 −5 examples/todo_app_coffee/app/models/todo.coffee
  22. +3 −6 examples/todo_app_coffee/config/development.coffee
  23. +15 −0 examples/todo_app_coffee/config/development.coffee.mongo
  24. +0 −5 examples/todo_app_coffee/config/init.coffee
  25. +1 −1  lib/app.js
  26. +18 −5 lib/cluster/worker.js
  27. +2 −2 lib/config.js
  28. +0 −31 lib/i18n/index.js
  29. +3 −5 lib/init/i18n.js
  30. +2 −1  lib/model/datatypes.js
  31. +1 −1  lib/model/index.js
  32. +1 −1  lib/model/validators.js
  33. +10 −0 lib/template/helpers/utils.js
  34. +2 −2 package.json
  35. +0 −3,363 site-old/css/bootstrap.css
  36. +0 −610 site-old/css/bootstrap.min.css
  37. +0 −3  site-old/css/bootstrap.min.responsive.css
  38. +0 −567 site-old/css/bootstrap.responsive
  39. +0 −176 site-old/docs.html
  40. +0 −459 site-old/features.html
  41. BIN  site-old/img/glyphicons-halflings-white.png
  42. BIN  site-old/img/glyphicons-halflings.png
  43. +0 −153 site-old/index.html
  44. +0 −1,722 site-old/js/bootstrap.js
  45. +0 −1  site-old/js/bootstrap.min.js
  46. +0 −2  site-old/js/google-code-prettify/lang-apollo.js
  47. +0 −18 site-old/js/google-code-prettify/lang-clj.js
  48. +0 −2  site-old/js/google-code-prettify/lang-css.js
  49. +0 −1  site-old/js/google-code-prettify/lang-go.js
  50. +0 −2  site-old/js/google-code-prettify/lang-hs.js
  51. +0 −3  site-old/js/google-code-prettify/lang-lisp.js
  52. +0 −2  site-old/js/google-code-prettify/lang-lua.js
  53. +0 −2  site-old/js/google-code-prettify/lang-ml.js
  54. +0 −4 site-old/js/google-code-prettify/lang-n.js
  55. +0 −1  site-old/js/google-code-prettify/lang-proto.js
  56. +0 −2  site-old/js/google-code-prettify/lang-scala.js
  57. +0 −2  site-old/js/google-code-prettify/lang-sql.js
  58. +0 −1  site-old/js/google-code-prettify/lang-tex.js
  59. +0 −2  site-old/js/google-code-prettify/lang-vb.js
  60. +0 −3  site-old/js/google-code-prettify/lang-vhdl.js
  61. +0 −2  site-old/js/google-code-prettify/lang-wiki.js
  62. +0 −3  site-old/js/google-code-prettify/lang-xq.js
  63. +0 −2  site-old/js/google-code-prettify/lang-yaml.js
  64. +0 −53 site-old/js/google-code-prettify/prettify.css
  65. +0 −28 site-old/js/google-code-prettify/prettify.js
  66. +0 −648 site-old/tutorial.html
  67. +175 −1 site/app/controllers/main.js
  68. +26 −12 site/app/views/layouts/application.html.jade
  69. +13 −0 site/app/views/main/changelog.html.jade
  70. +39 −30 site/app/views/main/community.html.jade
  71. +19 −0 site/app/views/main/documentation.html.jade
  72. +46 −0 site/app/views/main/faq.html.jade
  73. +11 −0 site/app/views/main/tutorial.html.jade
  74. +5 −24 site/config/router.js
  75. 0  site/log/access.2012-10-03T13:14:59.log
  76. 0  site/log/access.2012-10-03T13:15:46.log
  77. +0 −914 site/log/access.2012-10-03T16:35:18.log
  78. +0 −15 site/log/access.2012-10-03T16:44:21.log
  79. +0 −616 site/log/access.2012-10-04T01:57:01.log
  80. +0 −27 site/log/access.log
  81. +0 −1  site/log/stderr.2012-10-03T13:14:59.log
  82. +0 −1  site/log/stderr.2012-10-03T13:15:46.log
  83. 0  site/log/stderr.2012-10-03T16:35:18.log
  84. 0  site/log/stderr.2012-10-03T16:44:21.log
  85. +0 −2  site/log/stderr.2012-10-04T01:57:01.log
  86. +0 −1  site/log/stderr.log
  87. +0 −35 site/log/stdout.2012-10-03T13:14:59.log
  88. +0 −35 site/log/stdout.2012-10-03T13:15:46.log
  89. +0 −40 site/log/stdout.2012-10-03T16:35:18.log
  90. +0 −55 site/log/stdout.2012-10-03T16:44:21.log
  91. +0 −35 site/log/stdout.2012-10-04T01:57:01.log
  92. +0 −35 site/log/stdout.log
  93. +1 −0  site/node_modules/.bin/marked
  94. +1 −1  site/node_modules/jade/lib/jade.js
  95. +3 −2 site/node_modules/jade/lib/parser.js
  96. +16 −1 site/node_modules/jade/lib/utils.js
  97. +0 −3  site/node_modules/jade/node_modules/commander/package.json
  98. +0 −3  site/node_modules/jade/node_modules/mkdirp/package.json
  99. +3 −3 site/node_modules/jade/package.json
  100. +2 −0  site/node_modules/marked/.npmignore
  101. +19 −0 site/node_modules/marked/LICENSE
  102. +9 −0 site/node_modules/marked/Makefile
  103. +125 −0 site/node_modules/marked/README.md
  104. +127 −0 site/node_modules/marked/bin/marked
  105. +1 −0  site/node_modules/marked/index.js
  106. +791 −0 site/node_modules/marked/lib/marked.js
  107. +49 −0 site/node_modules/marked/man/marked.1
  108. +40 −0 site/node_modules/marked/package.json
  109. +262 −14 site/public/css/style.css
  110. BIN  site/public/img/changelog-dark-72.png
  111. BIN  site/public/img/changelog-light-72.png
  112. BIN  site/public/img/community-dark-72.png
  113. BIN  site/public/img/community-light-72.png
  114. BIN  site/public/img/docs-dark-72.png
  115. BIN  site/public/img/docs-light-72.png
  116. BIN  site/public/img/faq-dark-72.png
  117. BIN  site/public/img/faq-light-72.png
  118. BIN  site/public/img/home-dark-72.png
  119. BIN  site/public/img/home-light-72.png
  120. BIN  site/public/img/tuts-dark-72.png
  121. BIN  site/public/img/tuts-light-72.png
  122. +1 −1  site/public/js/jquery.min.js
  123. +94 −0 site/public/js/site.js
  124. +42 −20 templates/Jakefile
  125. +1 −1  templates/base/public/js/jquery.min.js
  126. +10 −5 templates/resource/model.ejs
  127. +5 −6 templates/scaffold/model.ejs
  128. +10 −0 test/templates/helpers/helpers.js
  129. +680 −0 tutorial.md
View
1  .gitignore
@@ -11,6 +11,7 @@ node_modules
tmtags
*.DS_Store
examples/*/log/*
+site/log/*
.log
npm-debug.log
doc/
View
40 README.md
@@ -1,8 +1,21 @@
-## Geddy web framework for Node.js
-- - -
+# Geddy
+####A simple, structured web framework for Node
+
+```
+$ npm install -g geddy
+$ geddy app my_app
+$ cd my_app
+$ geddy
+// app now running on localhost:4000
+```
+
[![build status](https://secure.travis-ci.org/mde/geddy.png)](http://travis-ci.org/mde/geddy)
+### Documentation
+
+Docs are located on the GeddyJS website: http://geddyjs.org/documentation
+
### Goals
* Easy to use
@@ -16,6 +29,7 @@ but still let you get under the hood and tinker if you want.
* Powerful, flexible router
* Easy resource-based routing
+ * Database adapters for Postgres, MongoDB, Riak, and in-memory
* App, resource and scaffold generators
* Content-negotiation
* Session support (in-memory, cookie)
@@ -33,6 +47,15 @@ Apache License, Version 2
Geddy requires version 0.6.x of Node.js or higher, and the
[Jake](https://github.com/mde/jake) JavaScript build-tool.
+### Installing with [NPM](http://npmjs.org/)
+
+```
+[sudo] npm -g install geddy
+```
+
+Note: Geddy (specifically, the generators) is a system-level
+tool, and wants to be installed globally.
+
### Installing from Github
To get Geddy from Github and install it do:
@@ -57,15 +80,6 @@ If you do install Geddy somewhere special, you'll need to add the
"bin" directory in the install target to your PATH to get access
to the `geddy` executable.
-### Installing with [NPM](http://npmjs.org/)
-
-```
-[sudo] npm -g install geddy
-```
-
-Note: Geddy (specifically, the generators) is a system-level
-tool, and wants to be installed globally.
-
### Creating a Geddy application
To create Geddy applications simply run `geddy app <name>`.
@@ -356,10 +370,6 @@ In the geddy project directory, run `jake test`. The tests simply
use NodeJS's `assert` library, which throws an error on failure.
If there are no errors, the tests all ran successfully.
-## API Docs
-
-API docs [can be found here](http://mde.github.com/geddy/doc/).
-
- - -
Geddy Web-app development framework copyright 2112
mde@fleegix.org.
View
50 bin/cli.js
@@ -21,6 +21,9 @@ var cwd = process.cwd()
, filepath
, die
, jake
+ , jakeArgs
+ , jakeProgram
+ , jakeLoader
, start;
// Usage dialog
@@ -46,6 +49,7 @@ usage = [
, ' --version, -v Output the version of Geddy that\'s installed'
, ''
, 'Commands:'
+ , ' console Start up the Geddy REPL'
, ' app <name> Create a new Geddy application'
, ' resource <name> [attrs] Create a new resource. A resource includes'
, ' a model, controller and route'
@@ -53,7 +57,7 @@ usage = [
, ' the views, a model, controller and route'
, ' secret Generate a new application secret in'
, ' `congig/environment`'
- , ' controller <name> Generate a new controller including an index view'
+ , ' controller <name> Generate a new controller including an index view'
, ' and and a route'
, ' model <name> [attrs] Generate a new model'
, ''
@@ -126,9 +130,9 @@ if (cmds.length) {
cmd = '';
// Some commands take only one arg
- if (!(cmds[0] == 'secret' ||
+ if (!(cmds[0] == 'jake' ||
+ cmds[0] == 'secret' ||
cmds[0] == 'db:init' ||
- cmds[0].indexOf('test') === 0 ||
cmds[0] == 'console')
&& !cmds[1]) {
throw new Error(cmds[0] + ' command requires another argument.');
@@ -150,6 +154,10 @@ if (cmds.length) {
// Add Jake argument based on commands
switch (cmds[0]) {
+ case 'jake':
+ cmd = 'jake';
+ jakeArgs = cmds.slice(1);
+ break;
case 'console':
// Create DBs
cmd += 'console:start[' + (cmds[1] || 'development') + ']';
@@ -158,12 +166,6 @@ if (cmds.length) {
// Create DBs
cmd += 'db:init';
break;
- case 'test':
- cmd = 'test';
- if (cmds[1]) {
- cmd += '[' + cmds[1] + ']'
- }
- break;
case 'db:createTable':
// Create DBs
cmd += 'db:createTable[' + cmds[1] + ']';
@@ -197,23 +199,26 @@ if (cmds.length) {
}
jake = require('jake');
- jake.loader.loadFile(filepath);
- if (cmd.indexOf('test') === 0) {
- jake.loader.loadFile(path.join(process.cwd(), 'Jakefile'));
- // Load up the Geddy env before running
- jake.program.setTaskNames(['env:init', cmd]);
- jake.program.init({
- trace: true
- });
+ jakeProgram = jake.program;
+ jakeLoader = jake.loader;
+ // Load Geddy's bundled Jakefile
+ jakeLoader.loadFile(filepath);
+ if (cmd == 'jake') {
+ jakeProgram.parseArgs(jakeArgs);
+ // Load Jakefile and jakelibdir files for app
+ jakeLoader.loadFile(jakeProgram.opts.jakefile);
+ jakeLoader.loadDirectory(jakeProgram.opts.jakelibdir);
+ // Prepend env:init to load Geddy env
+ jakeProgram.taskNames.unshift('env:init');
}
else {
- jake.program.init({
+ jakeProgram.init({
quiet: !opts.debug
, trace: true
});
- jake.program.setTaskNames([cmd]);
+ jakeProgram.setTaskNames([cmd]);
}
- jake.program.run();
+ jakeProgram.run();
}
// Just `geddy` -- start the server
else {
@@ -222,8 +227,7 @@ else {
if (err) {
die(usage);
}
- else {
- start();
- }
+
+ start();
});
}
View
13 changelog.md
@@ -0,0 +1,13 @@
+### 0.5
++ Brand new Web site with extensive docs
++ Removed models from geddy core, moved into Model project
++ Removed utilities from geddy core, moved into Utilities project
++ Removed router from geddy core, replaced with Barista
++ Added view helpers
++ Added [model](https://github.com/mde/model) as a dependency
++ Added [utilities](https://github.com/mde/utilities) as a dependency
++ Added [barista](https://github.com/kieran/barista) as a dependency
++ Added the `geddy console` command for CLI access to apps
++ Added the `geddy jake` command to run Jake tasks in the app environment
++ Added a ton of tests
++ Fixed a ton of bugs
View
7 deps/templato/lib/engines/ejs.js
@@ -1,8 +1,11 @@
-var TemplatoEJS = (function() {
+var path = require('path')
+ , TemplatoEJS;
+
+TemplatoEJS = (function() {
function TemplatoEJS() {
try {
- this.engine = this.engine || require('ejs');
+ this.engine = this.engine || require(path.join(process.cwd(), 'node_modules', 'ejs'));
} catch(err) {
throw "To use EJS you will need to install it: [sudo] npm install [-g] ejs";
}
View
7 deps/templato/lib/engines/handlebars.js
@@ -1,8 +1,11 @@
-var TemplatoHandlebars = (function() {
+var path = require('path')
+ , TemplatoHandlebars;
+
+TemplatoHandlebars = (function() {
function TemplatoHandlebars() {
try {
- this.engine = this.engine || require('handlebars');
+ this.engine = this.engine || require(path.join(process.cwd(), 'node_modules', 'handlebars'));
} catch(err) {
throw "To use Handlebars you will need to install it: [sudo] npm install [-g] handlebars";
}
View
7 deps/templato/lib/engines/jade.js
@@ -1,8 +1,11 @@
-var TemplatoJade = (function() {
+var path = require('path')
+ , TemplatoJade;
+
+TemplatoJade = (function() {
function TemplatoJade() {
try {
- this.engine = this.engine || require('jade');
+ this.engine = this.engine || require(path.join(process.cwd(), 'node_modules', 'jade'));
} catch(err) {
throw "To use Jade you will need to install it: [sudo] npm install [-g] jade";
}
View
6 deps/templato/lib/engines/mustache.js
@@ -1,10 +1,12 @@
require('../../color');
+var path = require('path')
+ , TemplatoMustache;
-var TemplatoMustache = (function() {
+TemplatoMustache = (function() {
function TemplatoMustache() {
try {
- this.engine = this.engine || require('handlebars');
+ this.engine = this.engine || require(path.join(process.cwd(), 'node_modules', 'mustache'));
} catch(err) {
throw [
"To use Handlebars you will need to install it: [sudo] npm install [-g] handlebars"
View
72 docs/1-architecture.md
@@ -0,0 +1,72 @@
+Geddy is built on the same MVC principles that many popular frameworks are based on. Every Geddy app has its models, controllers, and views as well as config files and routes.
+
+* * *
+
+#### structure
+
+```
+├── app
+│   ├── controllers
+│   │   ├── application.js
+│   │   └── main.js
+│   ├── helpers
+│   ├── models
+│   └── views
+│   ├── layouts
+│   │   └── application.html.ejs
+│   └── main
+│   └── index.html.ejs
+├── config
+ ├── development.js
+ ├── environment.js
+ ├── init.js
+ ├── production.js
+ └── router.js
+├── lib
+├── log
+├── node_modules
+└── public
+```
+
+* * *
+
+#### config
+`geddy.config`
+
+Geddy has built in configuration management. Global config options should go in your 'config/environments.js` file. Likewise, your production and development config options should go in their respective files
+
+If you want to start up your app in a specific environment, use the `-e` option:
+
+```
+$ geddy -e production
+```
+
+* * *
+
+#### logger
+`geddy.log[level]`
+
+Geddy automatically logs requests to an access log, and you can log anything you'd like to stdout or a file. It supports 9 different log levels from debug to emergency.
+
+##### levels
+- `access`: outputs to the access log and stdout
+- `debug`: debug level logging
+- `info`: info level logging
+- `notice`: notice level logging
+- `warning`: warning level logging
+- `error`: error level logging, prints to stdout and stderr
+- `critical`: critical level logging
+- `alert`: alert level logging
+- `emergency`: emergency level logging
+
+##### examples
+```
+geddy.log.debug('someting to debug')
+// prints `something to debug` to the console
+
+
+geddy.log.error('something went wrong')
+// prints 'something went wrong' to stderr and the console
+```
+
+* * *
View
110 docs/2-router.md
@@ -0,0 +1,110 @@
+Geddy uses [Barista](http://github.com/kieran/barista) as its router. Its API is very similar to rails routes. Both general-purpose resource-based routes and individually defined routes are possible.
+
+* * *
+
+#### .match
+`router.match(path [, method])`
+
+defines the url to match to a controller action.
+
+##### path
+- `path [string]`: the url to match to an action
+
+##### method
+- `method [string]`: the http method to match
+
+##### examples
+```
+router.match('/').to('Main.index');
+// will route any request to '/' to the Main controller's index action
+
+
+router.match('/products/:id', 'GET').to('products.show')
+// will route '/products/5' to Products.show()
+// and set the id paramer to be 5
+
+
+router.match('/profiles/:username', 'GET').to('users.show')
+// will route '/products/dan' to Users.show()
+// and set the username paramer to be dan
+
+
+router.match('/products/:id(.:format)', 'GET').to('products.show')
+// things enclosed in parentheses are optional
+```
+
+* * *
+
+#### .to
+`router.match(path).to(action)`
+
+defines the action to map the path to.
+
+##### action
+- `action [string]`: a controller name plus an action name as a string
+- `action [object]`: an object that defines a controller and action property
+
+##### examples
+```
+router.match('/').to('Main.index');
+// will route any request to '/' to the Main controller's index action
+
+
+router.match('/').to({controller: 'Main', action: 'index'});
+// will route any request to '/' to the Main controller's index action
+```
+
+* * *
+
+#### .get
+`router.get(path)`
+
+Equivalent to `router.match(path, 'GET')`
+
+* * *
+
+#### .post
+`router.post(path)`
+
+Equivalent to `router.match(path, 'POST')`
+
+* * *
+
+#### .put
+`router.put(path)`
+
+Equivalent to `router.match(path, 'PUT')`
+
+* * *
+
+#### .del
+`router.del(path)`
+
+Equivalent to `router.match(path, 'DELETE')`
+
+* * *
+
+#### .resource
+`router.resource(controller)`
+
+generates standard resource routes for a controller name
+
+##### controller
+- `controller [string]`: the camelCased controller name that needs resourceful routes
+
+##### examples
+```
+router.resource('products')
+
+// is equivalent to:
+
+router.get('/products(.:format)').to('products.index')
+router.get('/products/add(.:format)').to('products.add')
+router.get('/products/:id(.:format)').to('products.show')
+router.get('/products/:id/edit(.:format)').to('products.edit')
+router.post('/products(.:format)').to('products.create')
+router.put('/products/:id(.:format)').to('products.update')
+router.del('/products/:id(.:format)').to('products.destroy')
+```
+
+* * *
View
210 docs/3-controllers.md
@@ -0,0 +1,210 @@
+Controllers define the different actions that your users can interact with.
+
+* * *
+
+#### .request
+`this.request`
+
+The raw `http.ServerRequest` object for this request/response cycle.
+
+* * *
+
+#### .response
+`this.response`
+
+The raw `http.ServerResponse` object for this request/response cycle.
+
+* * *
+
+#### .params
+`this.params`
+
+The parsed params for the request. `params` is also passed as an argument to the action, it was added as an instance field for convenience.
+
+* * *
+
+#### .cookies
+`this.cookies`
+
+Cookies collection from the request
+
+* * *
+
+#### .name
+`this.name`
+
+The name of the controller constructor function, in CamelCase with uppercase initial letter.
+
+* * *
+
+#### .respondsWith
+`this.respondsWith`
+
+Content-type the controller can respond with.
+
+##### example
+```
+this.respondsWith = ['txt','json','html'];
+```
+
+* * *
+
+#### .before
+`before(filter, [options])`
+
+Adds an action to be performed before a response is rendered.
+
+##### filter
+- `filter [function]` Action to add to the beforeFilter list. If the action is asynchronous, takes a single callback parameter to call when the action is finished.
+
+##### options
+- `except [array]` List of actions where the before-filter should not be performed.
+- `only [array]` List of actions where the before-filter should only be performed.
+- `async` [boolean] When set to true, the before-filter is asynchronous, and requires a callback
+
+##### examples
+```
+this.before(someFunction);
+// runs someFunction before the response is rendered
+
+
+this.before(someFunction, {except: ['index', 'home']});
+// won't run someFunction if this is the index or home action
+
+
+this.before(someFunction, {only: ['add', 'update', 'remove']}
+// will only run someFunction if this is the add, update, or remove action
+```
+
+* * *
+
+#### .after
+`after(filter, [options])`
+
+Adds an action to be performed after a response is rendered.
+
+##### filter
+- `filter [function]` Action to add to the afterFilter list. If the action is asynchronous, takes a single callback parameter to call when the action is finished.
+
+##### options
+- `except [array]` List of actions where the after-filter should not be performed.
+- `only [array]` List of actions where the after-filter should only be performed.
+- `async` [boolean] When set to true, the before-filter is asynchronous, and requires a callback
+
+##### examples
+```
+this.after(someFunction);
+// runs someFunction after the response is rendered
+
+
+this.after(someFunction, {except: ['index', 'home']});
+// won't run someFunction if this is the index or home action
+
+
+this.after(someFunction, {only: ['add', 'update', 'remove']}
+// will only run someFunction if this is the add, update, or remove action
+```
+
+* * *
+
+#### .protectFromForgery
+`protectFromForgery()`
+
+Prevents cross-site requests by requiring a same-origin token for destructive HTTP methods (PUT, POST, DELETE)
+
+* * *
+
+#### .redirect
+`redirect(to)`
+
+##### to [string]
+- if `to` is a string, it will redirect to the url in that string
+
+##### to [object]
+- `controller [string]`: a controller name
+- `action [string]`: an action name
+- `format [string]`: the file extension
+
+Sends a 302 redirect to the client, based on either a simple string-URL, or a controller/action/format combination.
+
+##### examples
+```
+this.redirect('/users/1');
+// will redirect the browser to /users/1
+
+
+this.redirect({controller: 'users', action: 'show', id: 1});
+// will redirect the browser to /users/1
+```
+
+* * *
+
+#### .error
+`error(err)`
+
+Respond to a request with an appropriate HTTP error-code. If a status-code is set on the error object, uses that as the error's status-code. Otherwise, responds with a 500 for the status-code.
+
+##### err
+- `statusCode [number]` the code to send to the client
+- `msg [string]` the message to send to the client
+
+##### examples
+```
+this.error()
+// sends a 500
+
+
+this.error({statusCode: 501})
+// sends a 501
+```
+
+* * *
+
+#### .transfer
+```
+transfer(action)
+```
+
+Transfer a request from its original action to a new one. The entire request cycle is repeated, including before-filters.
+
+##### action
+- `action [string]`: name of the new action designated to handle the request.
+- `action [object]`: The new action designated to handle the request.
+
+* * *
+
+#### .respond
+```
+respond(data, options)
+```
+
+Performs content-negotiation, and renders a response.
+
+##### data
+- `data [object]`: an object with properties to send to the view
+
+##### options
+- `layout [string]`: the path to the layout file to use
+- `layout [false]`: a flag to not use a layout file
+- `format [string]`: the format to render
+- `template [string]`: The path (without file extensions) to the template to use to render this response
+
+##### examples
+```
+this.respond(params);
+// send the params object to the view, then send the response
+
+
+this.respond({posts: posts});
+// send the passed in object to the view, then send the response
+
+
+this.respond(params, {template: 'path/to/template'});
+// send params to path/to/template, render it, then send the response
+
+
+this.respond(params, {format: 'json'});
+// send the params object as the response in json format
+```
+
+* * *
View
548 docs/4-models.md
@@ -0,0 +1,548 @@
+Geddy uses the [Model](http://github.com/mde/model) module for its model layer. Model is an abstract ORM that is compatible with many different types of databases, including Postgres, in-memory, MongoDB and Riak.
+
+* * *
+
+#### summary
+Model uses a pretty simple syntax for defining a model. (It should look familiar to anyone who has used an ORM like ActiveRecord, DataMapper, Django's models, or SQLAlchemy.)
+
+* * *
+
+#### .defineProperties
+`defineProperties(properties)`
+
+defines the properties for your model.
+
+##### properties
+- `properties [object]`: an object keyed by name of properties to define
+
+##### example
+```
+var User = function () {
+ this.defineProperties({
+ login: {type: 'string', required: true}
+ , password: {type: 'string', required: true}
+ , lastName: {type: 'string'}
+ , firstName: {type: 'string'}
+ });
+}
+```
+
+* * *
+
+#### .property
+`property(name, type, options)`
+
+defines a single property
+
+##### name
+- `name [string]`: the name of the property
+
+##### type
+- `type [string]`: the type of the property
+ - `'string'`
+ - `'text'`
+ - `'number'`
+ - `'int'`
+ - `'boolean'`
+ - `'object'`
+ - `'array'`
+ - `'datetime'`
+ - `'date'`
+ - `'time'`
+
+##### options
+- `required [boolean]`: sets the property to be required
+
+##### examples
+```
+this.property('login', 'string', {required: true});
+this.property('password', 'string', {required: true});
+this.property('joined', 'datetime);
+this.property('premium', 'boolean);
+```
+
+* * *
+
+#### .validatesPresent
+`validatesPresent(property)`
+
+Sets up a validation to make sure that the property is present.
+
+##### property
+- `property [string]`: the name of the property to validate
+
+##### example
+```
+this.validatesPresent('login');
+// makes sure that the login property is present
+```
+
+* * *
+
+#### .validatesFormat
+`validatesFormat(property, regex, options)`
+
+Sets up a validation to make sure that the property is formatted correctly.
+
+##### property
+- `property [string]`: the name of the property to validate
+
+##### regex
+- `regex [regex]`: a regular expression that the property value must pass
+
+##### options
+- `message [string]`: a message to give the use if the validation fails
+
+##### example
+```
+this.validatesFormat('login', /[a-z]+/, {message: 'cannot contain numbers'});
+// makes sure that the login property does not contain numbers
+```
+
+* * *
+
+#### .validatesLength
+`validatesLength(property, options)`
+
+Sets up a validation to make sure that the property meets certain lenght requirements.
+
+##### property
+- `property [string]`: the name of the property to validate
+
+##### options
+- `min [number]`: the minimum length of the property
+- `max [number]`: the maximum length of the property
+
+##### example
+```
+this.validatesLength('login', {min: '3'});
+// makes sure that the login property is at least 3 characters long
+
+
+this.validatesLength('login', {min: '20'});
+// makes sure that the login property is not longer than 20 characters
+```
+
+* * *
+
+#### .validatesConfirmed
+`validatesConfirmed(property, param)`
+
+Sets up a validation to make sure that the property has been confirmed.
+
+##### property
+- `property [string]`: the name of the property to validate
+
+##### param
+- `param [string]`: the param required to match
+
+##### example
+```
+this.validatesConfirmed('password', 'confirmPassword');
+// confirms that password and confirmPassword are equal
+```
+
+* * *
+
+#### .validatesWithFunction
+`validatesWithFunction(property, fn)`
+
+Sets up a validation to make sure that the property has been confirmed.
+
+##### property
+- `property [string]`: the name of the property to validate
+
+##### fn
+- `fn [function]`: a function which, when passed the value of the property, will return true or false
+
+##### example
+```
+this.validatesWithFunction('password', function (val) {
+ // Something that returns true or false
+ return val.length > 0;
+});
+// uses the function to see if th length of password is greater than 0
+```
+
+* * *
+
+#### .hasOne
+`hasOne(model)`
+
+Sets up a has one relationship between this model and another.
+
+##### model
+- `model [string]`: the name of the model that this model has one of.
+
+##### example
+```
+this.hasOne('Profile');
+// sets up a has one relationship
+// user -> has one -> profile
+```
+
+* * *
+
+#### .hasMany
+`hasMany(model)`
+
+Sets up a has many relationship between this model and another.
+
+##### model
+- `model [string]`: the pluralized name of the model that this model has many of.
+
+##### example
+```
+this.hasMany('Friends');
+// sets up a has many relationship
+// user -> has many -> friends
+```
+
+* * *
+
+#### .adapter
+`this.adapter`
+
+Defines the database adapter for this model
+
+##### examples
+```
+this.adapter = 'mongo';
+// makes this model use mongo for it's database
+
+
+this.adapter = 'riak'
+
+
+this.adapter = 'postgres'
+
+
+this.adapter = 'memory'
+```
+
+* * *
+
+#### instance
+
+Instance methods can be defined in the model definition as well.
+
+##### example
+```
+var User = function () {
+...
+ this.someMethod = function () {
+ // Do some stuff
+ };
+ // sets up a someMethod method on each instance of this model
+...
+};
+```
+
+* * *
+
+#### .isValid
+`isValid()`
+
+Returns true if the model instance passes all validations, otherwise it returns false.
+
+##### example
+```
+user.isValid()
+```
+
+* * *
+
+#### .save
+`save(fn)`
+
+Saves the instance to the database.
+
+##### fn
+- `fn [function]`: the function to be called when saving is complete
+
+##### example
+```
+user.save(function (err, data) {
+// do things
+});
+// saves the user then calls the callback function
+```
+
+* * *
+
+#### .updateProperties
+`updateProperties(properties)`
+
+Updates the properties of a model and asserts that they are valid; This method will not call save on the instance.
+
+##### properties
+- `properties [object]`: an object who's keys are property names and its values are the values to change the property to.
+
+##### example
+```
+user.updateProperties({
+ login: 'alerxst'
+});
+// updates the login property and validates it
+```
+
+#### .add
+`.add{target_model_name}( instance )`
+
+If a model has a hasMany relationship established with another model, you can use this method to add instaces of one model to it’s “parent” model.
+
+##### target_model_name
+- The name of the model you’d like to add
+
+##### instance
+- `instace [modelInstance]`: The instance to add
+
+##### example
+```
+var user = geddy.model.User.create(userParams);
+var post = geddy.model.Post.create(postParams);
+user.addPost(post);
+```
+
+#### .set
+`.set{target_model_name}( instance )`
+
+If a model has a hasOne relationship established with another model, you can use this method to add an instace of one model to it’s “parent” model.
+
+##### target_model_name
+- The name of the model you’d like to set
+
+##### instance
+- `instace [modelInstance]`: The instance to set
+
+##### example
+```
+var user = geddy.model.User.create(userParams);
+var account = geddy.model.Account.create(accountParams);
+user.setAccount(account);
+```
+
+#### .get
+`.get{target_model_name}( fn )`
+
+If a model has a hasOne relationship established with another model, you can use this method to add an instace of one model to it’s “parent” model.
+
+##### target_model_name
+- `hasMany`: the plural name of the model you’d like to get a collection of
+- `hasOne`: the singular name of the model you like to get an instance of
+
+##### fn
+- `fn [function]`: The function to call once the models are retrieved.
+
+##### example
+```
+var user = geddy.model.User.create(params);
+
+// hasOne
+user.getAccount(function (err, account) {
+ // do stuff with the user’s account
+});
+
+// hasMany
+user.getPosts(function (err, posts) {
+ // do stuff with the user’s posts
+});
+```
+
+* * *
+
+#### static
+
+Static methods can be added by creating a method on the model definition object.
+
+```
+var User = function () {
+ this.property('login', 'string', {required: true});
+ this.property('password', 'string', {required: true});
+};
+
+User.findByLogin = function (login, callback) {
+ User.all({login: login}, callback);
+}
+```
+
+* * *
+
+#### .create
+`create(params)`
+
+Creates a new model instance and returns it.
+
+##### params
+- `params [object]`: an object whos keys are model properties
+
+##### example
+```
+var params = {
+ login: 'alex'
+, password: 'lerxst'
+, lastName: 'Lifeson'
+, firstName: 'Alex'
+};
+var user = User.create(params);
+```
+
+* * *
+
+#### .first
+`first(query, options, fn)`
+
+Use the `first` method to find a single item. You can pass it an id, or a set of query parameters in the form of an object-literal. In the case of a query, it will return the first item that matches, according to whatever sort you've specified.
+
+##### query [string]
+- `query [string]`: if the query is a string, it will be assumed that it's an id
+
+##### query [object]
+- `query [object]`: if the query is an object, it will be interpreted as a Query object
+
+##### example
+```
+User.first('sdfs-asd-1', function (err, user) {
+ // do stuff with user
+});
+
+
+User.first({login: 'alerxst'}, function (err, user) {
+ // do stuff with user
+});
+```
+
+* * *
+
+#### .all
+`all(query, options, fn)`
+
+Use the `all` method to find lots of items. Pass it a set of query parameters in the form of an object-literal, where each key is a field to compare, and the value is either a simple value for comparison (equal to), or another object-literal where the key is the comparison-operator, and the value is the value to use for the comparison.
+
+##### query [object]
+- `query [object]`: if the query is an object, it will be interpreted as a Query object
+
+##### options
+- `sort [object]`: each key is a property name, each value can either be `asc` or `desc`
+
+##### example
+```
+User.all({location: 'san francisco'}, function (err, users) {
+ // do stuff with users
+});
+
+
+User.all({location: 'san francisco'}, {sort: {createdAt: 'desc'}}, function (err, users) {
+ // do stuff with users
+});
+```
+
+* * *
+
+#### .remove
+`remove(id, fn)`
+
+Remove an instance from the database by id.
+
+##### id
+- `id [string]`: the id of the instance to be removed
+
+##### examples
+```
+User.remove('abc-123', function (err, data) {
+ // do something now that it's removed.
+});
+```
+
+* * *
+
+#### queries
+
+Model uses a simple API for finding and sorting items. Again, it should look
+familiar to anyone who has used a similar ORM for looking up records. The only
+wrinkle with Model is that the API is (as you might expect for a NodeJS library)
+asynchronous.
+
+##### comparison operators
+- `eql`: equal to
+- `ne`: not equal to
+- `gt`: greater than
+- `lt`: less than
+- `gte`: greater than or equal
+- `lte`: less than or equal
+- `like`: like
+
+A simple string-value for a query parameter is the same as 'eql'. `{foo: 'bar'}`
+is the same as `{foo: {eql: 'bar'}}`.
+
+##### combining queries
+Model supports combining queries with OR and negating queries with NOT.
+
+To perform an 'or' query, use an object-literal with a key of 'or', and an array
+of query-objects to represent each set of alternative conditions.
+
+To negate a query with 'not', simply use a query-object where 'not' is the key,
+and the value is the set of conditions to negate.
+
+
+##### examples
+```javascript
+{foo: 'BAR', bar: {ne: null}}
+// Where "foo" is 'BAR' and "bar" is not null
+
+{foo: {'like': 'B'}}
+// Where "foo" begins with 'B'
+
+{foo: {lt: 2112}, bar: 'BAZ'}
+// Where foo is less than 2112, and bar is 'BAZ'
+
+{or: [{foo: 'BAR'}, {bar: 'BAZ'}]}
+// Where "foo" is 'BAR' OR "bar" is 'BAZ'
+
+{or: [{foo {ne: 'BAR'}}, {bar: null}, {baz: {lt: 2112}}]}
+// Where "foo" is not 'BAR' OR "bar" is null OR "baz" is less than 2112
+
+{not: {foo: 'BAR', bar: 'BAZ'}}
+// Where NOT ("foo" is 'BAR' and "bar" is 'BAZ')
+
+{not: {foo: 'BAZ', bar: {lt: 1001}}}
+// Where NOT ("foo" is 'BAZ' and "bar" is less than 1001)
+
+{or: [{foo: {'like': 'b'}}, {foo: 'foo'}], not: {foo: 'baz'}}
+// Where ("foo" is like 'b' OR "foo" is 'foo') and NOT "foo" is 'baz'
+```
+
+* * *
+
+#### events
+
+Both the base model 'constructors,' and model instances are EventEmitters. The
+emit events during the create/update/remove lifecycle of model instances. In all
+cases, the plain-named event is fired after the event in question, and the
+'before'-prefixed event, of course happens before.
+
+The 'constructor' for a model emits the following events:
+
+ - beforeCreate
+ - create
+ - beforeValidate
+ - validate
+ - beforeUpdateProperties
+ - updateProperties
+ - beforeSave (new instances, single and bulk)
+ - save (new instances, single and bulk)
+ - beforeUpdate (existing single instances, bulk updates)
+ - update (existing single instances, bulk updates)
+ - beforeRemove
+ - remove
+
+Model-item instances emit these events:
+
+ - beforeUpdateProperties
+ - updateProperties
+ - beforeSave
+ - save
+ - beforeUpdate
+ - update
+
+* * *
View
333 docs/5-templates.md
@@ -0,0 +1,333 @@
+Geddy's view layer provides a versatile set of templating languages and helpers to get you started quickly.
+
+* * *
+
+#### engines
+The view layer supports these four templating engines:
+
++ EJS
++ Jade
++ Mustache
++ Handlebars
+
+To use them, just give your template the correct file extension. If you'd like to use a different templating engine when generating an app or scaffolds, use the corresponding command line option:
+
+```
+$ geddy app --mustach my_app
+$ geddy scaffold --mustache user
+
+
+$ geddy app --jade my_app
+$ geddy scaffold --jade user
+
+
+$ geddy app --handle my_app
+$ geddy scaffold --handle user
+```
+
+* * *
+
+#### yield
+Yield is a function that's only available on layout templates. It yields the template content, which is inserted in th place where the yield function is called.
+
+* * *
+
+#### partial
+`partial(partialURL<String>, data<Object>)`
+
+Partial takes a partialURL which is the location to a partial template and a data object which is the data to render the partial with(params, etc), then it renders the partial and puts the contents in place where the partial function was called.
+
+* * *
+
+#### truncate
+`truncate(string<String>, options<Integer/Object>)`
+
+Truncates a given `string` after a specified `length` if `string` is longer than `length`. The last character will be replace with an `omission` for a total length not exceeding `length`.
+
+#####Options [Integer]:
+- If an `options` is an integer it will be assumed that is the desired `length`
+
+#####Options [Object]:
+- `length [Integer]` Length the output string will be(Default: 30)
+- `len [Integer]` Alias for `length`
+- `omission [String]` Replace the last letters with an omission(Default: '...')
+- `ellipsis [String]` Alias for `omission`
+- `seperator [String/RegExp]` Break the truncated text at the nearest `seperator`
+
+#####Warnings:
+- Please be aware that truncating HTML elements may result in malformed HTML returned. If you'd like safe HTML truncation look at `truncateHTML`
+
+#####Examples:
+```
+runcate('Once upon a time in a world', {length: 10})
+// => 'Once up...'
+
+
+truncate('Once upon a time in a world', {length: 20, omission: '...(continued)'})
+// => 'Once u...(continued)'
+
+
+truncate('Once upon a time in a world', {length: 15, seperator: /\s/})
+// => 'Once upon a...'
+// Normal Output: => 'Once upon a ...'
+
+
+truncate('Once upon a time in a world', {length: 15, seperator: ' '})
+// => 'Once upon a...'
+// Normal Output: => 'Once upon a ...'
+
+
+truncate('<p>Once upon a time</p>', {length: 20})
+// => '<p>Once upon a ti...'
+```
+
+* * *
+
+#### truncateHTML
+`truncateHTML(string<String>, options<Integer/Object>)`
+
+Truncates a given `string` after a specified `length` if `string` is longer than `length`. The lat character will be replace with an `omission` for a total length not exceeding `length`. If `once` is true, only the first string in the first HTML element will be truncated leaving others as they were.
+
+#####Options [Object]:
+- `once`[Boolean] If true only the first string in the first HTML element will be truncated(Default: false)
+
+#####Notes:
+- All options available to `truncate` are available for `truncateHTML`
+- HTML elements are not included with the length of the truncation
+- HTML elements will not be truncated, so return value will always be safe for rendering
+
+#####Examples:
+```
+truncateHTML('<p>Once upon a time in a world</p>', {length: 10})
+// => '<p>Once up...</p>'
+
+
+truncateHTML('<p>Once upon a time <small>in a world</small></p>', {length: 10})
+// => '<p>Once up...<small>in a wo...</small></p>'
+
+
+truncateHTML('<p>Once upon a time <small>in a world</small></p>', {length: 10, once: true})
+// => '<p>Once up...<small>in a world</small></p>'
+```
+
+* * *
+
+#### imageLink
+`imageLink(source<String>, link<String/Object>, imageOptions<Object>, linkOptions<Object>)`
+
+Returns an anchor element to a given `link` with the given `linkOptions`, with the content being a image element to the given `source` and includes its `imageOptions`
+
+#####Notes:
+- `linkto` is used on the backend so any `linkOption` will be used for `linkTo`
+- `imageTag` is used on the backend as well so any `imageOptions` will be used for `imageTag`
+
+#####Examples:
+```
+imageLink('images/google.png', 'http://google.com')
+// => '<a href="http://google.com"><img alt="images/google.png" src="images/google.png" /></a>'
+
+
+imageLink('images/google.png', 'http://google.com', {alt: ''}
+// => '<a href="http://google.com"><img alt="" src="images/google.png" /></a>'
+
+
+imageLink('images/google.png', 'http://google.com', {alt: '', size: '40x50'})
+// => '<a href="http://google.com"><img alt="" height="50" src="images/google.png" width="40" /></a>'
+```
+
+* * *
+
+#### imageTag
+`imageTag(source<String>, htmlOptions<Object>)`
+
+Returns an image tag with the src to a `source` and includes all the given `htmlOptions`
+
+#####Custom HTML options:
+- `size`[String] Takes a string including the width and height "{width}x{height}"(e,g: '40x50') or it can take a single string included an integer "{size}"(e,g: '40') The first being results in "height='50' width='40'" the second results in the height and width being the same value. _Note_: If the format doesn't comply, it will be ignored
+
+#####Examples:
+```
+imageTag('images/google.png')
+// => '<img alt="images/google.png" src="images/google.png" />'
+
+
+imageTag('images/google.png', {alt: ''})
+// => '<img alt="" src="images/google.png" />'
+
+
+imageTag('images/google.png', {alt: '', size: '40x50'})
+// => '<img alt="" height="50" src="images/google.png" width="40" />'
+
+
+imageTag('images/google.png', {alt: '', size: 'a string'})
+// => '<img alt="" src="images/google.png" />'
+```
+
+* * *
+
+#### styleLink
+`styleLink(source<String>, htmlOptions<Object>)`
+
+Generates a style element pointing to `source` and includes all the given `htmlOptions`
+
+#####Examples:
+```
+styleLink('/css/styles.css')
+// => '<link href="/css/style.css" />'
+
+
+styleLink('/css/styles.css', {type: 'text/javascript'})
+// => '<link href="/css/style.css" rel="stylesheet" />'
+```
+
+* * *
+
+#### scriptLink
+`scriptLink(source<String>, htmlOptions<Object>)`
+
+Generates a script element pointing to `source` and includes all the given `htmlOptions`
+
+#####Examples:
+```
+scriptLink('/js/script.js')
+// => '<script src="/js/script.js"></script>'
+
+
+scriptLink('/js/script.js', {type: 'text/javascript'})
+// => '<script src="/js/script.js" type="text/javascript"></script>'
+```
+
+* * *
+
+#### linkTo
+`linkTo(content<String>, options<String/Object>, htmlOptions<Object>)`
+
+Generates a link from the given `options`, then returns a anchor tag with the `content` and the `htmlOptions` provided
+
+#####Examples:
+```
+linkTo('some content', 'http://google.com')
+// => '<a href="http://google.com">some content</a>'
+
+
+linkTo('some content', 'http://google.com', {data: {goTo: 'http://google.com'}})
+// => '<a data-go-to="http://google.com" href="http://google.com">some content</a>'
+```
+
+* * *
+
+#### urlFor
+`urlFor(options<String/Object>)`
+
+Returns a URL based on the `options` provided
+
+#####Options [String]:
+- `'back'` [String] The 'back' string will return a URL that points to the last URL in history
+
+#####Options [Object]:
+- `relPath` [Boolean] If true, the relative URL is returned(Default: false)
+- `protocol` [String] The protocol to use(Default: What your Geddy instance is using('http' default))
+- `username` [String] Includes a username in the path. Requires `password` or it'll be ignored
+- `password` [String] Includes a username in the path. Requires `password` or it'll be ignored
+- `subdomain` [String] Specifies the subdomain to prepend to `domain`
+- `domain` [String] Specifies the domain to point to. Required if `relPath` is false
+- `host` [String] Alias for `host`
+- `port` [Integer] Specify the port to connect to
+- `controller` [String] Specifies the controller to use for the path
+- `action` [String] Specifies the action to use for the path
+- `id` [String] Specifies an ID to use for displaying specific items
+- `trailingSlash` [Boolean] If true, adds a trailing slash to the end of the path/domain
+- `fragment` [String] Appends a fragment to the end of the path/domain
+- `anchor` [String] Alias for `fragment`
+
+#####Notes:
+- If `options` is a String it will just be returned, unless the String is equal to 'back'
+- Any other `options` added will be considered as a query to be appended to the URL
+
+#####Examples:
+```
+urlFor('http://google.com')
+// => 'http://google.com'
+
+
+urlFor({controller: 'tasks', action: 'new', host: 'somehost.com'})
+// => 'http://somehost.com/tasks/new'
+
+
+urlFor({controller: 'tasks', action: 'new', relPath: true})
+// => '/tasks/new'
+
+
+urlFor({controller: 'tasks', action: 'new', relPath: true, trailingSlash: true})
+// => '/tasks/new/'
+
+
+urlFor({host: 'somehost.com', protocol: 'https', username: 'username', password: 'password'})
+// => 'https://username:password@somehost.com'
+
+
+urlFor({controller: 'tasks', action: 'new', host: 'somehost.com', protocol: 'https'})
+// => 'https://somehost.com/tasks/new'
+
+
+urlFor({controller: 'tasks', action: 'edit', id: 'IwTEf55ivH', host: 'somehost.com'})
+// => 'http://somehost.com/tasks/IwTEf55ivH/edit'
+
+
+urlFor({controller: 'tasks', action: 'new', host: 'somehost.com', anchor: 'submit'})
+// => 'http://somehost.com/tasks/new#submit'
+
+
+urlFor({controller: 'tasks', action: 'new', host: 'somehost.com', authToken: 'some_token'})
+// => 'http://somehost.com/tasks/new?authToken=some_token'
+```
+
+* * *
+
+#### contentTag
+`contentTag(tag<String>, content<String>, htmlOptions<Object>)`
+
+Returns an HTML element from a given `tag` and includes the `content` and all `htmlOptions`
+
+#####Custom HTML options:
+- `data`[Array] The data attribute takes an Array containing data attributes you want, when parsed they each get parsed as a full data attribute(e,g: `data: {goTo: 'google.com'}` will be `data-go-to="google.com"`).
+
+#####Examples:
+```
+contentTag('p', 'this is some content')
+// => '<p>this is some content</p>'
+
+
+contentTag('input', 'sample value')
+// => '<input value="sample value" />'
+
+
+contentTag('input', 'sample value', {value: 'override sample value'})
+// => '<input autofocus="autofocus" type="text" value="sample value" />'
+
+
+contentTag('input', 'sample value', {type: 'text', autofocus: true})
+// => '<input autofocus="autofocus" type="text" value="sample value" />'
+
+
+contentTag('a', 'http://google.com')
+// => '<a href="http://google.com">http://google.com</a>'
+
+
+contentTag('a', 'hey there', {href: 'http://google.com'})
+// => '<a href="http://google.com">hey there</a>'
+
+
+contentTag('a', 'hey there', {href: 'http://google.com', data: { goTo: 'http://google.com'} })
+// => '<a data-go-to="http://google.com" href="http://google.com">hey there</a>'
+
+
+contentTag('a', 'hey there', {href: 'http://google.com', data_go_to: 'http://google.com'})
+// => '<a data-go-to="http://google.com" href="http://google.com">hey there</a>'
+
+contentTag('select', ['geddy', 'alex', 'neil'])
+// => '<select><option value="geddy">geddy</option><option value="alex">alex</option><option value="neil">neil</option></select>'
+```
+
+* * *
+
View
83 docs/6-CLI.md
@@ -0,0 +1,83 @@
+Geddy has a robust CLI tool to help you generate apps, run your tests, or play with your app in a console.
+
+####Options:
+
+- `—environment, -e`: Environment to use
+- `—port, -p`: Port to connect server to
+- `—workers, -w`: Number of workers to use (default: 1)
+- `—debug, -d`: Sets the log level to output debug messages to console
+- `—jade, -j`: When generating views, use Jade templates(Default: EJS)
+- `—handle, -H`: When generating views, use Handlebars templates(Default: EJS)
+- `—mustache, -m`: When generating views, use Mustache templates(Default: EJS)
+- `—version, -v`: Output the version of Geddy installed
+- `—help, -h`: Output the list of commands and options
+
+#### geddy
+`geddy` takes no arguments, it will run the geddy app in the current directory.
+
+```
+$ cd path/to/app
+$ geddy
+// will run the app in path/to/app
+```
+
+#### app
+`app` takes a single argument being the name you'd like, then it will generate a base application. If no name is given the command will fail. If you include the `—jade`, `—handle`, or `—mustache` option you can substitute the templating language to your liking
+
+```
+$ geddy app app_name
+// creates a geddy app using EJS
+```
+
+#### resource
+`resource` takes one or more arguments, the first being a name and the others being a set of model properties. This will create a controller, a model including the given model properties and a resource route.
+
+```
+$ geddy resource user name description password
+// This will create a user model, users controller, and user routes
+```
+
+#### scaffold
+`scaffold` takes one or more arguments, the first being a name and the others being a set of model properties. Scaffolding includes a controller, a model including the given model properties as well as a default model adapter a resource route and will create all views. If you also include the options `—jade`, `—handle` or `—mustache` you can substitute the template language to your liking.
+
+```
+$geddy scaffold user name description password
+// This will create a user model, users controller, user views, and user routes
+```
+
+#### controller
+`controller` takes a single argument being a name. It will create a new controller, a route and an index view. If you also include the options `—jade`, `—handle` or `—mustache` you can substitute the template language to your liking.
+
+```
+$ geddy controller users
+```
+
+#### model
+`model` takes one or more arguments, the first being a name and the others being a set of model properties. This will create a new model including the model properties given.
+
+```
+$ geddy model user name description password
+// creates a user model with name, description and password properties
+```
+
+#### secret
+`secret` doesn't take any arguments, it will find your config/environment file and create a new secret in it deleting any other secret.
+
+```
+$ geddy secret
+```
+
+#### console
+`console` doesn't take any arguments, it will start a geddy console.
+
+```
+$ geddy console
+```
+
+#### jake
+`jake` takes a task name, it will run a jake command in your apps context from your app's Jakefile
+
+```
+$ geddy jake test
+// will run the test task in your app's Jakefile after loading up your app environment
+```
View
55 docs/7-sessions.md
@@ -0,0 +1,55 @@
+Sessions are used to keep track of current connections to the server.
+
+#### .get
+`get( key )`
+
+Gets a key from the current session.
+
+##### key
+- `key [string]`: the key to return the value of
+
+##### example
+```
+var user = this.session.get(‘user’);
+```
+
+#### .set
+`set( key, value )`
+
+Saves a value to the current session as a key
+
+##### key
+- `key [string]`: the key to set on the session
+
+##### value
+- `value [object]`: the value to save to the session
+
+##### example
+```
+this.session.set(‘user’, user);
+```
+
+#### .unset
+`unset( key )`
+
+Removes a key and value from the current session
+
+##### key
+- `key [string]`: the key to remove
+
+##### example
+```
+this.session.unset(‘user’);
+```
+
+#### .isExpired
+```
+isExpired()
+```
+
+Returns true if the current session has expired
+
+##### example
+```
+this.session.isExpired
+```
View
59 docs/8-deployment.md
@@ -0,0 +1,59 @@
+#### Heroku
+
+##### Pre-requisites
+1. Install [heroku toolbelt](https://devcenter.heroku.com/articles/quickstart#step-2-install-the-heroku-toolbelt)
+2. Install geddy. If you're new, you can start with the [tutorial](http://geddyjs.org/tutorial)
+3. Be familiar with GIT, the basic geddy commands, and heroku's deployment models
+4. Have an app ready to be deployed.
+
+Add a `package.json` file to your app's root folder
+
+```javascript
+{
+ "name": "node-example",
+ "version": "0.0.1",
+ "dependencies": {
+ "geddy": "0.5.x"
+ },
+ "engines": {
+ "node": "0.8.x",
+ "npm": "1.1.x"
+ }
+}
+```
+
+Edit the `config/production.js` file to use the port given by heroku
+```javascript
+var config = {
+ port: process.env.PORT
+ // Other properties removed for brevity
+};
+
+```
+
+Add a `Procfile` text file to your app's root folder
+
+```
+//web: node node_modules/geddy/bin/cli.js
+var geddy = require('geddy');
+
+if (geddy.isMaster) {
+ geddy.config({ environment: 'production' });
+}
+
+geddy.start();
+```
+
+Now it's time to create a heroku app.
+
+```
+$ heroku create --stack cedar
+```
+
+Add everything to git and push to heroku
+
+```
+$ git push heroku master
+```
+
+For more information about deploying and supporting Node Apps on Heroku see the [Getting Started with Node.js on Heroku](https://devcenter.heroku.com/articles/nodejs) article.
View
6 examples/todo_app/app/controllers/todos.js
@@ -47,8 +47,8 @@ var Todos = function () {
this.update = function (req, resp, params) {
var self = this;
geddy.model.Todo.first(params.id, function (err, todo) {
- todo.status = params.status;
- todo.title = params.title;
+ todo.updateAttributes(params);
+
todo.save(function (err, data) {
if (err) {
params.errors = err;
@@ -63,7 +63,7 @@ var Todos = function () {
this.remove = function (req, resp, params) {
var self = this;
- geddy.model.adapter.Todo.remove(params.id, function(err){
+ geddy.model.Todo.remove(params.id, function(err){
if (err) {
params.errors = err;
self.transfer('edit');
View
6 examples/todo_app/config/init.js
@@ -4,8 +4,4 @@ if (geddy.config.environment != 'development') {
process.addListener('uncaughtException', function (err) {
geddy.log.error(JSON.stringify(err));
});
-}
-geddy.todos = [];
-geddy.model.adapter = {};
-geddy.model.adapter.Todo = require(process.cwd() + '/lib/model_adapters/todo').Todo;
-
+}
View
60 examples/todo_app/lib/model_adapters/todo.js
@@ -1,60 +0,0 @@
-var Todo = new (function () {
-
- this.all = function (callback) {
- callback(null, geddy.todos);
- }
-
- this.load = function (id, callback) {
-
- for (var i in geddy.todos) {
- if (geddy.todos[i].id == id) {
- return callback(null, geddy.todos[i]);
- }
- }
- callback({message: "To Do not found"}, null);
-
- };
-
- this.save = function (todo, opts, callback) {
-
- if (typeof callback != 'function') {
- callback = function(){};
- }
-
- var todoErrors = null;
- for (var i in geddy.todos) {
-
- // if it's already there, save it
- if (geddy.todos[i].id == todo.id) {
- geddy.todos[i] = todo;
- todoErrors = geddy.model.Todo.create(todo).errors;
- return callback(todoErrors, todo);
- }
-
- }
- todo.saved = true;
- geddy.todos.push(todo);
- return callback(null, todo);
-
- }
-
- this.remove = function(id, callback) {
-
- if (typeof callback != 'function') {
- callback = function(){};
- }
-
- for (var i in geddy.todos) {
- if (geddy.todos[i].id == id) {
- geddy.todos.splice(i, 1);
- return callback(null);
- }
- }
-
- return callback({message: "To Do not found"});
-
- }
-
-})();
-
-exports.Todo = Todo;
View
20 examples/todo_app_coffee/app/controllers/todos.coffee
@@ -3,13 +3,7 @@ class Todos
index: (req, resp, params) ->
self = this
- geddy.model.adapter.Todo.all
- status:
- 'in': ['open', 'done']
- , sort:
- status: -1
- title: 1
- , (err, todos) ->
+ geddy.model.Todo.all (err, todos) ->
self.respond params: params, todos: todos
add: (req, resp, params) ->
@@ -19,7 +13,6 @@ class Todos
self = this
todo = geddy.model.Todo.create
title: params.title
- id: geddy.string.uuid(10)
status: 'open'
todo.save (err, data) ->
@@ -31,19 +24,18 @@ class Todos
show: (req, resp, params) ->
self = this
- geddy.model.adapter.Todo.load params.id, (err, todo) ->
+ geddy.model.Todo.load params.id, (err, todo) ->
self.respond params: params, todo: todo
edit: (req, resp, params) ->
self = this
- geddy.model.adapter.Todo.load params.id, (err, todo) ->
+ geddy.model.Todo.load params.id, (err, todo) ->
self.respond params: params, todo: todo
update: (req, resp, params) ->
self = this
- geddy.model.adapter.Todo.load params.id, (err, todo) ->
- todo.status = params.status
- todo.title = params.title
+ geddy.model.Todo.load params.id, (err, todo) ->
+ todo.updateAttributes params
todo.save (err, data) ->
if err
@@ -54,7 +46,7 @@ class Todos
remove: (req, resp, params) ->
self = this
- geddy.model.adapter.Todo.remove params.id, (err) ->
+ geddy.model.Todo.remove params.id, (err) ->
if err
params.errors = err
self.transfer 'edit'
View
5 examples/todo_app_coffee/app/models/todo.coffee
@@ -3,9 +3,6 @@ Todo = ->
title:
type: 'string'
required: true
- id:
- type: 'string'
- required: true
status:
type: 'string'
required: true
@@ -16,6 +13,4 @@ Todo = ->
@validatesWithFunction 'status', (status) ->
status == 'open' || status == 'done'
- @adapter = 'mongo'
-
Todo = geddy.model.register 'Todo', Todo
View
9 examples/todo_app_coffee/config/development.coffee
@@ -2,14 +2,11 @@ config =
detailedErrors: false
hostname: null
port: 4000
+ model:
+ defaultAdapter: 'memory'
sessions:
store: 'memory'
key: 'sid'
expiry: 14 * 24 * 60 * 60
- db:
- mongo:
- db: 'todo'
-
-module.exports = config
-
+module.exports = config
View
15 examples/todo_app_coffee/config/development.coffee.mongo
@@ -0,0 +1,15 @@
+config =
+ detailedErrors: false
+ hostname: null
+ port: 4000
+ model:
+ defaultAdapter: 'mongo'
+ db:
+ mongo:
+ dbname: 'model_test'
+ sessions:
+ store: 'memory'
+ key: 'sid'
+ expiry: 14 * 24 * 60 * 60
+
+module.exports = config
View
5 examples/todo_app_coffee/config/init.coffee
@@ -1,8 +1,3 @@
-mongo = require 'mongodb-wrapper'
-
-geddy.db = mongo.db 'localhost', 27017, 'todo'
-geddy.db.collection 'todos'
-
# Add uncaught-exception handler in prod-like environments
if geddy.config.environment != 'development'
process.addListener 'uncaughtException', (err) ->
View
2  lib/app.js
@@ -26,7 +26,6 @@ var fs = require('fs')
, errors = require('./response/errors')
, response = require('./response')
, utils = require('utilities')
- , i18n = require('./i18n')
, init = require('./init')
, helpers = require('./template/helpers')
, actionHelpers = require('./template/helpers/action')
@@ -35,6 +34,7 @@ var fs = require('fs')
, CookieCollection = require('./cookies').CookieCollection
, Request = require('./request').Request
, InFlight = require('./in_flight').InFlight
+ , i18n = utils.i18n
, usingCoffee; // Global variable for CoffeeScript
// Set up a bunch of aliases
View
23 lib/cluster/worker.js
@@ -71,15 +71,28 @@ Worker.prototype = new (function () {
this.startServer = function () {
if (this.config) {
var hostname = this.config.hostname || null
+ , self = this
+ , port = parseInt(this.config.port, 10)
, ssl = this.config.ssl ? ' (SSL)' : ''
, spdy = this.config.spdy ? '(SPDY)' : '';
- this.server.listen(parseInt(this.config.port, 10), hostname);
+ utils.network.isPortOpen(port, hostname, function (err, isOpen) {
+ if (err) {
+ self.log.error(err);
+ }
+ else if (isOpen) {
+ self.log.error("The port " + port + " is already in use.");
+ }
+ else {
+ self.server.listen(port, hostname, function () {
- this.log.info('Server worker running in ' + this.config.environment +
- ' on port ' + this.config.port + ssl + spdy + ' with a PID of: ' + process.pid);
- this.log.debug('LOGGING STARTED ============================================');
- this.log.debug('============================================================');
+ self.log.info('Server worker running in ' + self.config.environment +
+ ' on port ' + self.config.port + ssl + spdy + ' with a PID of: ' + process.pid);
+ self.log.debug('LOGGING STARTED ============================================');
+ self.log.debug('============================================================');
+ });
+ }
+ });
}
else {
this.log.error('Cannot start server without config.');
View
4 lib/config.js
@@ -39,10 +39,10 @@ config = new (function () {
if (fileBaseName === env || fileBaseName === 'environment') {
if (fileExt === '.coffee') {
// fileName is a CoffeeScript file so try to require it
- useCoffee = useCoffee || file.requireLocal('coffee-script');
+ useCoffee = useCoffee || utils.file.requireLocal('coffee-script');
}
appBaseConfig = require(dir + '/config/environment');
- appEnvConfig = require(dir + '/config/' + baseConfig.environment);
+ appEnvConfig = require(dir + '/config/' + env);
}
}
View
31 lib/i18n/index.js
@@ -1,31 +0,0 @@
-var i18n = new (function () {
- var _currentLocale = ''
- , _strings = {};
-
- this.getText = function (key, opts, locale) {
- var defaultLocale = geddy.config.i18n.defaultLocale
- , currentLocale = locale || defaultLocale
- , currentLocaleStrings = _strings[currentLocale] || {}
- , defaultLocaleStrings = _strings[defaultLocale] || {}
- , str = currentLocaleStrings[key]
- || defaultLocaleStrings[key] || "[[" + key + "]]";
- for (p in opts) {
- str = str.replace(new RegExp('\\{' + p + '\\}', 'g'), opts[p]);
- }
- return str;
- };
-
- this.loadLocale = function (locale, strings) {
- _strings[locale] = _strings[locale] || {};
- geddy.mixin(_strings[locale], strings);
- };
-
-})();
-
-i18n.I18n = function (controller) {
- this.t = function (key, opts) {
- return i18n.getText(key, opts || {}, controller.locale);
- };
-};
-
-module.exports = i18n;
View
8 lib/init/i18n.js
@@ -1,15 +1,12 @@
-var i18n = require('../i18n')
- , path = require('path')
+var path = require('path')
, fs = require('fs')
, utils = require('utilities')
+ , i18n = utils.i18n
, file = utils.file;
module.exports = new (function () {
var LOCALE_PAT = /([^\/]*).json$/;
- var _loadLocaleData = function (directory, callback) {
- };
-
this.init = function (app, callback) {
var localePaths = [
__dirname + '/../../templates/locales'
@@ -44,6 +41,7 @@ module.exports = new (function () {
};
localePaths = localePaths.concat(geddy.config.i18n.loadPaths || []);
+ i18n.setDefaultLocale(geddy.config.i18n.defaultLocale);
loadLocaleData();
};
View
3  lib/model/datatypes.js
@@ -16,7 +16,8 @@
*
*/
-var i18n = require('../i18n');
+
+var i18n = require('utilities').i18n;
/*
* Datatype verification -- may modify the value by casting
View
2  lib/model/index.js
@@ -43,7 +43,7 @@ User = geddy.model.register('User', User);
var model = {}
, utils = require('utilities')
- , i18n = require('../i18n');
+ , i18n = utils.i18n;
model.datatypes = require('./datatypes.js');
model.validators = require('./validators.js');
View
2  lib/model/validators.js
@@ -16,7 +16,7 @@
*
*/
-var i18n = require('../i18n');
+var i18n = require('utilities').i18n;
/*
* Basic validators -- name is the field name, params is the entire params
View
10 lib/template/helpers/utils.js
@@ -62,6 +62,16 @@ exports.tags = {
if (tag === 'img') {
htmlOptions.alt = htmlOptions.alt === '' ? htmlOptions.alt : htmlOptions.alt || content;
}
+ if (tag === 'select' && typeof content !== 'string') {
+ var tags = '';
+
+ for (var i = 0; i < content.length; i++) {
+ tags += this.contentTagString('option', content[i], {value: content[i]});
+ }