geddy

Framework documentation

Architecture

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

Router

Geddy uses 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')

Controllers

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 after-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 [error]
  • statusCode [number] optional HTTP status code to send to the client, defaults to 500
  • message [string] the error message text to send to the client
examples
this.error();
// sends a 500

var err = new Error('Whoopsy daisy');
this.error(err);
// sends a 500 with a specific message

var err = new Error();
err.statusCode = 420;
this.error(err);
// sends a 420

.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
  • statusCode [number]: The HTTP status-code to use with 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(null, {statusCode: 201});
// send the params object as the response in json format

this.respond(params, {format: 'json'});
// send a 201/created with no body

.flash

The flash is a special part of the session which is cleared with each request. This means that values stored there will only be available in the next request. This is useful for storing error messages, etc. It is accessed in much the same way as the session, like a hash.

It also includes a few convenience methods for getting/setting commonly used types of flash-messages.


.flash.alert

flash.alert([message])

Gets or sets the alert flash-messages for a session. If the 'message' (value) parameter is included it sets the value. If the 'message' paramter is not included, it retrieves the value and returns it.

message
  • message [string|object]: The contents of the flash-message
examples
this.flash.alert('Check it out!');
// Sets the 'alert' flash-message to 'Check it out!'

this.flash.alert();
// Returns 'This is fantastic!'

.flash.error

flash.error([message])

Gets or sets the error flash-messages for a session. If the 'message' (value) parameter is included it sets the value. If the 'message' paramter is not included, it retrieves the value and returns it.

message
  • message [string|object]: The contents of the flash-message
examples
this.flash.error('Yikes! Something wrong wrong.');
// Sets the 'error' flash-message to 'Yikes! Something wrong wrong.'

this.flash.error();
// Returns 'This is fantastic!'

.flash.success

flash.success([message])

Gets or sets the success flash-messages for a session. If the 'message' (value) parameter is included it sets the value. If the 'message' paramter is not included, it retrieves the value and returns it.

message
  • message [string|object]: The contents of the flash-message
examples
this.flash.success('Whoa! It worked.');
// Sets the 'success' flash-message to 'Whoa! It worked.'

this.flash.success();
// Returns 'This is fantastic!'

.flash.info

flash.info([message])

Gets or sets the info flash-messages for a session. If the 'message' (value) parameter is included it sets the value. If the 'message' paramter is not included, it retrieves the value and returns it.

message
  • message [string|object]: The contents of the flash-message
examples
this.flash.info('FYI. Just sayin.');
// Sets the 'info' flash-message to 'FYI. Just sayin.'

this.flash.info();
// Returns 'This is fantastic!'

.flash.set

flash.set([type], message)

Sets the flash-messages for a session, for a custom type, or the entire flash-message object

type
  • type [string]: The flash-message type. If not included, this call sets the entire flash-message object
message
  • message [string|object]: The contents of the flash-message
examples
this.flash.set('foo', 'Foo bar baz');
// Sets the 'foo' flash-message to 'Foo bar baz'

this.flash.set({bar: 'Baz bar qux});
// Sets the entire flash-message object

.flash.get

flash.get([type])

Retrieves the flash-messages for a session, for a custom type, or the entire flash-message object

type
  • type [string]: The flash-message type. If not included, this call retrieves the entire flash-message object
examples
this.flash.set('foo', 'Foo bar baz');
this.flash.get('foo');
// Returns 'Foo bar baz'

this.flash.get();
// Returns an object: {foo: 'Foo bar baz'}

.flash.keep

flash.keep([type])

Normally flash-message are wiped out when they are used in the current request. keep makes them persist and be available to the next request.

type
  • type [string]: The type of message to preserve until the next request. If the type param is not included, preserves the entire flash-message object
examples
this.flash.keep('error');
// Keep the error flash around after a redirect

.flash.discard

flash.discard([type])

Mark a particular flash-message entry (or the entire object) to be discarded at the end of the current request.

type
  • type [string]: The type of message to discard at the end of the current request. If the type param is not included, discards the entire flash-message object
examples
this.flash.discard('error');
// Discard the current error flash-message

Models

Geddy uses the 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'
    • '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, options)

Sets up a validation to make sure that the property is present.

property
  • property [string]: the name of the property to validate
options
  • message [string]: a message to give the user if the validation fails
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 user 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, qualifier, options)

Sets up a validation to make sure that the property meets certain length requirements.

property
  • property [string]: the name of the property to validate
qualifier
  • min [number]: the minimum length of the property
  • max [number]: the maximum length of the property
  • [number]: the exact length of the property
options
  • message [string]: a message to give the user if the validation fails
example
this.validatesLength('login', {min: 3});
// makes sure that the login property is at least 3 characters long


this.validatesLength('login', {max: 20});
// makes sure that the login property is not longer than 20 characters

this.validatesLength('login', 3)
// makes sure that the login property is exactly 3 characters long

.validatesConfirmed

validatesConfirmed(property, param, options)

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
options
  • message [string]: a message to give the user if the validation fails
example
this.validatesConfirmed('password', 'confirmPassword');
// confirms that password and confirmPassword are equal

.validatesWithFunction

validatesWithFunction(property, fn, options)

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
options
  • message [string]: a message to give the user if the validation fails
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
// (something) -> 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
// (something) -> has many -> friends

.belongsTo

belongsTo(model)

Sets up a belongs-to relationship between this model and another. A belongs-to is often used as the inverse of a has-many or has-one. Note however that this is not required -- associations are unidirectional.

model
  • model [string]: the singular name of the model that this model belongs to.
example
this.belongsTo('User');
// sets up a belongs-to relationship
// (something) -> belongs to -> a user

.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
{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

Templates

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(.ejs)
  • Jade(.jade)
  • Mustache(.mu, .ms, .mustache)
  • Handlebars(.hbs, .handlebars)
  • Swig(.swig)

To use a certain template engine just give the view a corresponding extension listed above.

When using the Geddy CLI to generate parts of your application you can use different template languages by giving an argument to the command, here are some examples:

$ geddy app --mustache my_app
$ geddy scaffold -m user


$ geddy app --jade my_app
$ geddy scaffold -j user


$ geddy app --handle my_app
$ geddy scaffold -H user

$ geddy app --swig my_app
$ geddy scaffold --swig user

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>'

selectTag

`selectTagString(optionsArray, selectedOption, htmlOptions)

Creates a HTML select tag using the given optionsArray to create HTML option elements.

optionsArray could be an array of strings, numbers or an object with value and text properties to be used for the value attribute and option element content respectively, along with an attr object which will include any other html options. (you can even pass selected:true and 'value:VALUE' with the attr object as well, but the outer ones, if there is any, will take precedence)

Examples:
selectTag(['geddy', 'alex', 'neil'])
// => '<select><option value="geddy">geddy</option><option value="alex">alex</option><option value="neil">neil</option></select>'

selectTag(['open', 'close'], todo.status, { class:'span6', name:'status' })
// => '<select class="span6" name="status"><option selected="selected" value="open">open</option><option value="close">close</option></select>'

selectTag([{value: 1, text: "Text 1"}, {value: 2, text: "Text 2"}], 2)
// => <select><option value="1">Text 1</option><option selected="selected" value="2">Text 2</option></select>

selectTag([{text: "Text 1", attrs: {value: 1, class: 'anoption', data: {thing: 'vip', rate: '0.99'}}}, {value: 2, text: "Text 2", attrs: {value: 0, data: {thing: 'basic'}}}], 2)
// => <select><option data-thing="vip" data-rate="0.99" class="anoption" value="1">Text 1</option><option data-thing="basic" selected="selected" value="2">Text 2</option></select>

v0.7

Helpers

Along with flexible template system in Geddy you have access to various built in helpers and custom helpers.

custom helpers

When you create your application a helpers directory will be added to the app directory, all the files in this directory will be required when you start the server up.

The exported helpers, are available in your views and throughout your application.

For example, we have this script in a file in our app/helpers directory:

module.exports = function upperCase(str) {
  return str.toUpperCase();
};

Now when we start the server up we can access it in our views by doing:

<%= upperCase("some string") %>
// => "SOME STRING"

All the exported helpers are global to the templates, so any of them can be accessed from any template.

You can also access them from controllers/models and any other part of your application by using geddy.viewHelpers here's an example using our upperCase helper:

console.log(geddy.viewHelper.upperCase("some string"));
// => "SOME STRING"

yield

Yield is a function that's only available on layout templates. It yields the template content, which is inserted in the 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 replaced 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>'

selectTag

`selectTagString(optionsArray, selectedOption, htmlOptions)

Creates a HTML select tag using the given optionsArray to create HTML option elements.

optionsArray could be an array of strings, numbers or an object with value and text properties to be used for the value attribute and option element content respectively.

Examples:
selectTag(['geddy', 'alex', 'neil'])
// => '<select><option value="geddy">geddy</option><option value="alex">alex</option><option value="neil">neil</option></select>'

selectTag(['open', 'close'], todo.status, { class:'span6', name:'status' })
// => '<select class="span6" name="status"><option selected="selected" value="open">open</option><option value="close">close</option></select>'

selectTag([{value: 1, text: "Text 1"}, {value: 2, text: "Text 2"}], 2)
// => <select><option value="1">Text 1</option><option selected="selected" value="2">Text 2</option></select>

CLI

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)
  • —swig, -s: When generating views, use Swig 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, —mustache, or '-swig' 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, —mustache, or '-swig' 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, —mustache, or '-swig' 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

Sessions

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

Deployment

We use the following example as a reference. There will be some differences with other environments.

Nodejitsu

Pre-requisites
  1. Install the jitsu module
  2. Install Geddy. If you're new, you can start with the tutorial
  3. Create a Nodejitsu account(Not required: we'll go over creating one from the CLI)
  4. Have an app ready to be deployed
Notes
  • Nodejitsu reads the deployed .gitignore file, so if you have the config/secrets.json file in there(you should), then you'll encounter errors about needing to do geddy secret if you need the secrets for sessions, etc. To circumvent this, create a .npmignore file and include all the contents from the .gitignore except the config/secrets.json line. Nodejitsu ignores the .gitignore file only if a .npmignore file is included as well.

If you haven't already you'll need to sign up and log in to Nodejitsu which you can do from the jitsu executable.

jitsu signup
jitsu login

Now once you've created an account on Nodejitsu we need to prepare the application you have for deployment. First we'll edit(or create) a package.json file in the app's root directory

{
  "name": "node-example",
  "version": "0.0.1",
  "dependencies": {
    "geddy": "0.6.x"
  },
  "subdomain": "geddy-example",
  "scripts": {
    "start": "app.js"
  },
  "engines": {
    "node": "0.8.x"
  }
}

Here we have a subdomain key/value this tells Nodejitsu what subdomain to host the application on(e,g,. geddy-example.jit.su). We also have a start script pointing to app.js in the root directory, we'll go over what to put here in a second. Of course you should edit this to include anything else you want, like other dependences or an author.

Now we need to create a app.js file so that Nodejitsu can use it to boot the Geddy server, here's what it should look like

var geddy = require('geddy');

geddy.start({
  environment: 'production'
});

In the object we're giving to geddy.start you can use any other arguments you'd for the configuration files, these will override the ones loaded for the environment. For more information about this file you can go here

Now that our application is set up for deployment, we need to deploy it which is just a single command

jitsu deploy

Now you can go to http://geddy-example.jit.su and see your application!

Heroku

Pre-requisites
  1. Install heroku toolbelt
  2. Install Geddy. If you're new, you can start with the tutorial
  3. Be familiar with GIT, the basic geddy commands, and heroku's deployment models
  4. Have an app ready to be deployed.
Notes
  • Heroku is deployed via Git, which of course reads the .gitignore file which may include the config/secrets.json file(it should), if you need something that requires the secret such as sessions, etc. you'll encounter errors about doing geddy secret when you deploy. Currently there's no way to circumvent this other than removing it from your .gitignore file. More info here: https://github.com/mde/geddy/issues/309

Add a package.json file to your app's root directory

{
  "name": "node-example",
  "version": "0.0.1",
  "dependencies": {
    "geddy": "0.6.x"
  },
  "engines": {
    "node": "0.8.x",
    "npm": "1.1.x"
  }
}

Now we need to create a app.js file so that the Procfile can use it to boot the Geddy server, here's what it should look like

var geddy = require('geddy');

geddy.startCluster({
  hostname: '0.0.0.0',
  port: process.env.PORT || '3000',
  // you can manually set this to production, or set an environment variable via heroku..
  environment: 'production'
  // just uncomment the below line, and delete the above line.
  // you will need to set an environment variable in heroku by running
  // heroku config:set NODE_ENV=production
  //environment: process.env.NODE_ENV || 'development'
});

In the object we're giving to geddy.startCluster you can use any other arguments you'd for the configuration files, these will override the ones loaded for the environment. For more information about this file you can go here

Add a Procfile text file to your app's root directory, this is read by Heroku when booting the app

web: node app.js

Add a Procfile text file to your app's root directory

web: node app.js

remove the line for config\secrets.json in your .gitignore file - note: This is insecure, on public repo's as it exposes your cookie's secret hash.

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 article.

I18n

Geddy provides internationalization support out of the box, with localized error messages in the following languages:

  • Chinese (Simplified)
  • English (US)
  • German (Germany)
  • Japanese (Japan)
  • Portuguese (Brazil)
  • Spanish (Spain)

You can set a specific locale at the request level, or a default one for your entire app. The default locale if you don't set one is American English ('en-us').

Setting a locale for your app

Set a locale in your environment.js by setting the defaultLocale property on the i18n config option:

...
, i18n: {
    defaultLocale: 'ja-jp'
  }
...
Loading i18n data

Geddy will load i18n data according to the loadPaths property of your app's i18n config -- an array of paths to look in for JSON files containing i18n data. By default, it contains an entry for 'config/locales' in your app.

Geddy's i18n code loads the data into data structures based on the filename. (So the data in /foo/bar/en-uk.json gets loaded into the en-uk locale, etc.)

Data format

Internationalization data is loaded from JSON files in the following format:

{
  "model.validatesPresent": "「{name}」の入力が必要です。"
, "model.validatesAbsent": "「{name}」の入力は不要です。"
, "model.validatesConfirmed": "「{name}」と「{qual}」が一致しません。"
, "model.validatesFormat": "「{name}」のフォーマットが正しくありません。"
, "model.validatesExactLength": "「{name}」は{qual}文字でなければいけません。"
, "model.validatesMinLength": "「{name}」は{min}文字以上でなければいけません。"
, "model.validatesMaxLength": "「{name}」は{max}文字以内でなければいけません。"
, "model.validatesWithFunction": "「{name}」は有効ではありません。"
}

Using i18n text

Geddy controllers have an i18n property which has a getText method (shortcut alias t). Pass this method the desired key, and an optional data-object for parametric replacement, and an optional locale. If you don't pass a locale, it will fall back to the app's defaultLocale.

This i18n object is also available as a local variable in your templates.

Use it like this in a controller (assuming a defaultLocale of 'ja-jp'):

// Returns 「HOWDY」の入力が必要です。
this.i18n.t('model.validatesPresent', {name: 'HOWDY'});

// Returns "HOWDY" ist ein Pflichtfeld.
this.i18n.t('model.validatesPresent', {name: 'HOWDY'}, 'de-de');

Utilities

Geddy provides tons of useful utilities to make tasks easier, they are provided by the utilities module in NPM. All the utilities are availble through the geddy global object(e.g., geddy.array.humanize()).


xml

setIndentLevel

setIndentLevel(level<Number>)

SetIndentLevel changes the indent level for XML.stringify and returns it

Examples
setIndentLevel(6)
// => 6

stringify

stringify(obj<Object>, opts<Object>)

Options
  • whitespace [Boolean] Don't insert indents and newlines after xml entities(Default: true)
  • name [String] Use custom name as global namespace(Default: typeof obj)
  • fragment [Boolean] If true no header fragment is added to the top(Default: false)
  • level [Number] Remove this many levels from the output(Default: 0)
  • arrayRoot [Boolean] (Default: true)

Stringify returns an XML representation of the given obj

Examples
stringify({user: 'name'})
// => '<?xml version="1.0" encoding="UTF-8"?>\n<object>\n    <user>name</user>\n</object>\n'

stringify(['user'])
// => '<?xml version="1.0" encoding="UTF-8"?>\n<strings type="array">\n    <string>user</string>\n</strings>'

stringify({user: 'name'}, {fragment: true})
// => '<object>\n<user>name</user>\n</object>\n'

array

humanize

humanize(array<Array>)

Creates a string containing the array elements in a readable format

Examples
humanize(["array", "array", "array"])
// => "array, array and array"

humanize(["array", "array"])
// => "array and array"

include

include(array<Array>, item<Any>)

Checks if an item is included in an array

Examples
include(["array"], "array")
// => true

include(["array"], 'nope')
// => false

include(["array", false], false)
// => true

uri

getFileExtension

getFileExtension(path<String>)

Gets the file extension for a path and returns it

Examples
getFileExtension('users.json')
// => 'json'

paramify

paramify(obj<Object>, o<Object>)

Options
  • consolidate [Boolean] take values from elements that can return(Default: false)
  • includeEmpty [Boolean] include keys in the string for all elements, even(Default: false)
  • snakeize [Boolean] change param names from camelCase to snake_case.(Default: false)
  • escapeVals [Boolean] escape the values for XML entities.(Default: false)

Convert a JS Object to a querystring (key=val&key=val). Values in arrays

Examples
paramify({username: 'user', token: 'token', secret: 'secret'})
// => 'username=user&token=token&secret=secret'

paramify({username: 'user', auth: ['token', 'secret']}, {conslidate: true})
// => 'username=user&auth=token&auth=secret'

paramify({username: 'user', token: ''}, {includeEmpty: true})
// => 'username=user&token='

paramify({username: 'user', token: '<token'}, {escapeVals: true})
// => 'username=user&token=%26lt%3Btoken'

objectify

objectify(str<String>, o<Object>)

Options
  • consolidate [Boolean] Convert multiple instances of the same(Default: true)

Convert the values in a query string (key=val&key=val) to an Object

Examples
objectify('name=user')
// => {name: 'user'}

objectify('name=user&name=user2')
// => {name: ['user', 'user2']}

objectify('name=user&name=user2', {consolidate: false})
// => {name: 'user2'}

EventBuffer

proxyEmit

proxyEmit(name<String>, args<Array>)

Emit an event by name and arguments or add it to the buffer if no outlet is set

Examples
proxyEmit("close")
// => undefined

proxyEmit("data", "some content here")
// => undefined

emit

emit(name<String>, args<Array>)

Emit an event by name and arguments

Examples
emit("close")
// => undefined

emit("data", "some content here")
// => undefined

sync

sync(outlet<Object>)

Flush the buffer and continue piping new events to the outlet

Examples
sync(new EventEmitter())
// => undefined

SortedCollection

addItem

addItem(key<String>, val<Any>)

Adds a new key/value to the collection

Examples
addItem('testA', 'AAAA');
// => 'AAAA'

addItem('testV', 'VVVV');
// => 'VVVV'

getItem

getItem(p<String/Number>)

Retrieves the value for the given identifier that being a key or index

Examples
getItem('testA');
// => 'AAAA'

getItem(1);
// => 'VVVV'

setItem

setItem(p<String/Number>, val<Any>)

Sets the item in the collection with the given val, overwriting the existsing item

Examples
setItem('testA', 'aaaa');
// => 'aaaa'

setItem(1, 'vvvv');
// => 'vvvv'

removeItem

removeItem(p<String/Number>)

Removes the item for the given identifier

Examples
removeItem('testA')
// => true

removeItem(3)
// => false

getByKey

getByKey(key<String>)

Retrieves the value for the given key

Examples
getByKey('testA');
// => 'AAAA'

getByKey('testV');
// => 'VVVV'

setByKey

setByKey(key<String>, val<Any>)

Sets a item by key assigning the given val

Examples
setByKey('testA', 'aaaa');
// => 'aaaa'

setByKey('testV', 'vvvv');
// => 'vvvv'

removeByKey

removeByKey(key<String>)

Removes a collection item by key

Examples
removeByKey('testA')
// => true

removeByKey('testC')
// => false

getByIndex

getByIndex(ind<Number>)

Retrieves the value for the given index

Examples
getByIndex(0);
// => 'AAAA'

getByIndex(1);
// => 'VVVV'

setByIndex

setByIndex(ind<Number>, val<Any>)

Sets a item by index assigning the given val

Examples
setByIndex(0, 'aaaa');
// => 'aaaa'

setByIndex(1, 'vvvv');
// => 'vvvv'

removeByIndex

removeByIndex(ind<Number>)

Removes a collection item by index

Examples
removeByIndex(0)
// => true

removeByIndex(3)
// => false

hasKey

hasKey(key<String>)

Checks if a key item exists in the collection

Examples
hasKey('testA')
// => true

hasKey('testC')
// => false

hasValue

hasValue(val<Any>)

Checks if a key item in the collection has a given val

Examples
hasValue('aaaa')
// => true

hasValue('cccc')
// => false

allKeys

allKeys(str<String>)

Joins all the keys into a string

Examples
allKeys(", ")
// => "testA, testV"

replaceKey

replaceKey(oldKey<String>, newKey<String>)

Joins all the keys into a string

Examples
replaceKey("testV", "testC")
// => undefined

insertAtIndex

insertAtIndex(ind<Number>, key<String>, val<Any>)

Inserts a key/value at a specific index in the collection

Examples
insertAtIndex(1, "testB", "bbbb")
// => true

insertAfterKey

insertAfterKey(refKey<String>, key<String>, val<Any>)

Inserts a key/value item after the given reference key in the collection

Examples
insertAfterKey("testB", "testB1", "b1b1b1b1b1b1")
// => true

getPosition

getPosition(key<String>)

Retrieves the index of the key item

Examples
getPosition("testA")
// => 0

getPosition("testB1")
// => 2

each

each(func<Function>, opts<Object>)

Options
  • keyOnly [Boolean] Only give the function the key
  • valueOnly [Boolean] Only give the function the value

Loops through the collection and calls the given function

Examples
each(function (val, key) {
  console.log("Key: " + key + " Value: " + val);
})

each(function (key) {
  console.log("Key: " + key);
}, {keyOnly: true})

each(function (val) {
  console.log("Val: " + val);
}, {valueOnly: true})

eachKey

eachKey(func<Function>)

Loops through the collection and calls the given function

Examples
each(function (key) {
  console.log("Key: " + key);
}, {keyOnly: true})

eachValue

eachValue(func<Function>)

Loops through the collection and calls the given function

Examples
each(function (val) {
  console.log("Val: " + val);
}, {valueOnly: true})

clone

clone()

Creates a cloned version of the current collection and returns it

Examples
clone()
// => SortedCollection

concat

concat(hNew<Object>)

Join a given collection with the current one

Examples
concat(new SortedCollection())
// => undefined

push

push(key<String>, val<Any>)

Appends a new item to the collection

Examples
push("testZ", "zzzz")
// => 5

pop

pop()

Pops off the last item in the collection and returns it's value

Examples
pop()
// => "zzzz"

unshift

unshift(key<String>, val<Any>)

Prepends a new item to the beginning of the collection

Examples
unshift("testA0", "a0a0a0a0")
// => 6

shift

shift()

Removes the first item in the list and returns it's value

Examples
shift()
// => "a0a0a0a0"

splice

splice(index<Number>, numToRemove<Number>, hash<Object>)

Removes items from index to the given max and then adds the given collections items

Examples
splice(2, 1, new SortedCollection())
// => undefined

reverse

reverse()

Reverse the collection item list

Examples
reverse()
// => undefined

date

supportedFormats

supportedFormats

Object of supported strftime formats


getSupportedFormats

getSupportedFormats()

return the list of formats in a string

Examples
getSupportedFormats()
// => "aAbhBcCdDefFgGHI..."

strftime

strftime(dt<Date>, format<String>)

Formats the given date with the strftime formated

Examples
strftime(new Date(), "%w")
// => 3

calcCentury

calcCentury(year<Number>)

Find the century for the given year

Examples
calcCentury()
// => "21"

calcCentury(2000)
// => "20"

calcDays

calcDays(dt<Date>)

Calculate the day number in the year a particular date is on

Examples
calcDays(new Date())
// => 150

getMeridiem

getMeridiem(h<Number>)

Return 'AM' or 'PM' based on hour in 24-hour format

Examples
getMeridiem(14)
// => "PM"

getMeridiem(7)
// => "AM"

hrMil2Std

hrMil2Std(hour<String>)

Convert a 24-hour formatted hour to 12-hour format

Examples
hrMil2Std("14")
// => 2

hrMil2Std("7")
// => 7

hrStd2Mil

hrStd2Mil(hour<String>, pm<Boolean>)

Convert a 12-hour formatted hour with meridian flag to 24-hour format

Examples
hrStd2Mil("7", true)
// => 14

hrStd2Mil("7")
// => 7

add

add(dt<Date>, interv<String>, incr<Number>)

Add to a Date in intervals of different size, from milliseconds to years

Examples
add(new Date(), "hour", 1)
// => Date

add(new Date(), "minute", 10)
// => Date

diff

diff(date1<Date>, date2<Date>, interv<String>)

Get the difference in a specific unit of time (e.g., number of months, weeks, days, etc.) between two dates.

Examples
diff(new Date(), new Date(), "hour")
// => 0

diff(new Date(), new Date(), "minute")
// => 0

parse

parse(val<String>)

Convert various sorts of strings to JavaScript Date objects

Examples
parse("12:00 March 5 1950")
// => Sun Mar 05 1950 12:00:00 GMT-0500 (EST)

relativeTime

relativeTime(dt<Date>, opts<Object>)

Options
  • abbreviated [Boolean] Use short strings(Default: false)

Convert a Date to an English sentence representing

Examples
relativeTime(new Date())
// => 'less than a minute ago'

toISO8601

toISO8601(dt<Date>)

Convert a Date to an ISO8601-formatted string

Examples
toISO8601(new Date())
// => '2012-10-17T17:57:03.892-04'

object

merge

merge(object<Object>, otherObject<Object>)

Merge merges otherObject into object and takes care of deep merging of objects

Examples
merge({user: 'geddy'}, {key: 'key'})
// => {user: 'geddy', key: 'key'}

merge({user: 'geddy', key: 'geddyKey'}, {key: 'key'})
// => {user: 'geddy', key: 'key'}

reverseMerge

reverseMerge(object<Object>, defaultObject<Object>)

ReverseMerge merges object into defaultObject

Examples
reverseMerge({user: 'geddy'}, {key: 'key'})
// => {user: 'geddy', key: 'key'}

reverseMerge({user: 'geddy', key: 'geddyKey'}, {key: 'key'})
// => {user: 'geddy', key: 'geddyKey'}

isEmpty

isEmpty(object<Object>)

isEmpty checks if an Object is empty

Examples
isEmpty({user: 'geddy'})
// => false

isEmpty({})
// => true

toArray

toArray(object<Object>)

Converts an object to an array of objects each including the original key/value

Examples
toArray({user: 'geddy'})
// => [{key: 'user', value: 'geddy'}]

network

isPortOpen

isPortOpen(port<Number>, host<String>, callback<Function>)

Checks if the given port in the given host is open

Examples
isPortOpen(3000, 'localhost', function (err, isOpen) {
  if (err) { throw err; }

  console.log(isOpen)
})

request

request

request(opts<Object>, callback<Function>)

Sends requests to the given url sending any data if the method is POST or PUT

Options
  • url [String] The URL to send the request to
  • method [String] The method to use for the request(Default: 'GET')
  • headers [Object] Headers to send on requests
  • data [String] Data to send on POST and PUT requests
  • dataType [String] The type of data to send
Examples
request({url: 'google.com', method: 'GET'}, function (err, data) {
  if (err) { throw err; }

  console.log(data)
})

inflection

inflections

inflections

A list of rules and replacements for different inflection types


parse

parse(type<String>, word<String>)

Parse a word from the given inflection type

Examples
parse('plurals', 'carrier')
// => 'carriers'

parse('singulars', 'pluralities')
// => 'plurality'

pluralize

pluralize(word<String>)

Create a plural inflection for a word

Examples
pluralize('carrier')
// => 'carriers'

singularize

singularize(word<String>)

Create a singular inflection for a word

Examples
singularize('pluralities')
// => 'plurality'

file

cpR

cpR(fromPath<String>, toPath<String>, opts<Object>)

Options
  • silent [Boolean] If false then will log the command

Copies a directory/file to a destination

Examples
cpR('path/to/directory', 'destination/path')
// => undefined

mkdirP

mkdirP(dir<String>, mode<Number>)

Create the given directory(ies) using the given mode permissions

Examples
mkdirP('dir', 0755)
// => undefined

mkdirP('recursive/dirs')
// => undefined

readdirR

readdirR(dir<String>, opts<Object>)

Options
  • format [String] Set the format to return(Default: Array)

Reads the given directory returning it's contents

Examples
readdirR('dir')
// => ['dir', 'item.txt']

readdirR('path/to/dir')
// => ['path/to/dir', 'path/to/dir/item.txt']

rmRf

rmRf(p<String>, opts<Object>)

Options
  • silent [String] If false then logs the command

Deletes the given directory/file

Examples
rmRf('file.txt')
// => undefined

isAbsolute

isAbsolute(p<String>)

Checks if a given path is absolute or relative

Examples
isAbsolute('/path/to/file.txt')
// => true

isAbsolute('C:\\path\\to\\file.txt')
// => true

absolutize

absolutize(p<String>)

Returns the absolute path for the given path

Examples
absolutize(path/to/dir)
// => /home/user/path/to/dir

searchParentPath

searchParentPath(p<String>, callback<Function>)

Search for a directory/file in the current directory and parent directories

Examples
searchParentPath('path/to/file.txt', function (err, path) {
  if (err) { throw err; }

  console.log(path)
})

watch

watch(path<String>, callback<Function>)

Watch a given path then calls the callback once a change occurs

Examples
watch('path/to/dir', function (currStat, oldStat) {
  console.log('the current mtime is: ' + currStat.mtime);
  console.log('the previous mtime was: ' + oldStat.mtime);
})

requireLocal

requireLocal(module<String>, message<String>)

Require a local module from the node_modules in the current directory

Examples
requireLocal('utilities', 'optional error message')
// => { ... }

string

escapeRegExpChars

escapeRegExpChars(string<String>)

Escapes regex control-characters in strings used to build regexes dynamically

Examples
escapeRegExpChars('/\s.*/')
// => '\\\\/s\\\\.\\\\*\\\\/'

toArray

toArray(string<String>)

Converts a string to an array

Examples
toArray('geddy')
// => ['g', 'e', 'd', 'd', 'y']

reverse

reverse(string<String>)

Reverses a string

Examples
reverse('geddy')
// => 'yddeg'

ltrim

ltrim(string<String>, char<String>)

Ltrim trims char from the left of a string and returns it if no char is given it will trim spaces

Examples
ltrim('&geddy', '&')
// => 'geddy'

ltrim('    geddy')
// => 'geddy'

rtrim

rtrim(string<String>, char<String>)

Rtrim trims char from the right of a string and returns it if no char is given it will trim spaces

Examples
rtrim('geddy&', '&')
// => 'geddy'

rtrim('geddy    ')
// => 'geddy'

trim

trim(string<String>, char<String>)

Trim trims char from the left and right of a string and returns it if no char is given it will trim spaces

Examples
trim('&&&&geddy&', '&')
// => 'geddy'

trim('    geddy    ')
// => 'geddy'

chop

chop(string<String>)

Returns a new String with the last character removed. If the string ends with \r\n, both characters are removed. Applying chop to an empty string returns an empty string.

Examples
chop('geddy&')
// => 'geddy'

lpad

lpad(string<String>, char<String>, width<Number>)

Lpad adds char to the left of string until the length of string is more than width

Examples
lpad('geddy', '&', 6)
// => '&geddy'

rpad

rpad(string<String>, char<String>, width<Number>)

Rpad adds char to the right of string until the length of string is more than width

Examples
rpad('geddy', '&', 7)
// => 'geddy&'

pad

pad(string<String>, char<String>, width<Number>)

Pad adds char to the left and right of string until the length of string is more than width

Examples
rpad('geddy', '&', 6)
// => '&geddy&'

truncate

truncate(string<String>, options<Integer/Object>, callback<Function>)

Options
  • length [Integer] Length the output string will be(Default: string.length)
  • len [Integer] Alias for length
  • omission [String] Replace last characters with an omission(Default: '...')
  • ellipsis [String] Alias for omission(Default: '...')
  • seperator [String/RegExp] Break the truncated test at the nearest seperator

Truncates a given string after a specified length if string is longer than length. The last characters will be replaced with an omission for a total length not exceeding length. If callback is given it will fire if string is truncated.

Examples
truncate('Once upon a time in a world', { length: 10 })
// => 'Once up...'

truncate('Once upon a time in a world', { length: 10, omission: '///' })
// => 'Once up///'

truncate('Once upon a time in a world', { length: 15, seperator: /\s/ })
// => 'Once upon a...'

truncate('Once upon a time in a world', { length: 15, seperator: ' ' })
// => 'Once upon a...'

truncate('<p>Once upon a time in a world</p>', { length: 20 })
// => '<p>Once upon a ti...'

truncateHTML

truncateHTML(string<String>, options<Integer/Object>, callback<Function>)

Options
  • once [Boolean] If true, it will only be truncated once, otherwise the(Default: false)

Truncates a given string inside HTML tags after a specified length if string is longer than length. The last characters will be replaced with an omission for a total length not exceeding length. If callback is given it will fire if string is truncated. If once` is true only the first string in the first HTML tags will be truncated leaving the others as they were

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>'

nl2br

nl2br(string<String>)

Nl2br returns a string where all newline chars are turned into line break HTML tags

Examples
nl2br("geddy\n")
// => 'geddy<br />'

snakeize

snakeize(string<String>, separ='_'<String>)

Snakeize converts camelCase and CamelCase strings to snake_case strings

Examples
snakeize("geddyJs")
// => 'geddy_js'

snakeize("GeddyJs")
// =>  'geddy_js'

camelize

camelize(string<String>, options<Object>)

Options
  • initialCap [Boolean] If initialCap is true the returned
  • leadingUnderscore [Boolean] If leadingUnderscore os true then if

Camelize takes a string and optional options and returns a camelCase version of the given string

Examples
camelize("geddy_js")
// => 'geddyJs'

camelize("geddy_js", {initialCap: true})
// => 'GeddyJs'

camelize("geddy_js", {leadingUnderscore: true})
// => 'geddyJs'

camelize("_geddy_js", {leadingUnderscore: true})
// => '_geddyJs'

decapitalize

decapitalize(string<String>)

Decapitalize returns the given string with the first letter uncapitalized.

Examples
decapitalize("Geddy")
// => 'geddy'

capitalize

capitalize(string<String>)

capitalize returns the given string with the first letter capitalized.

Examples
decapitalize("geddy")
// => 'Geddy'

dasherize

dasherize(string<String>, replace='-'<String>)

Dasherize returns the given string converting camelCase and snakeCase to dashes or replace them with the replace character.

Examples
dasherize("geddyJs")
// => 'geddy-js'

dasherize("geddyJs", "_")
// => 'geddy_js'

include

include(searchIn<String>, searchFor<String>)

Searches for a particular string in another string

Examples
include('geddy', 'js')
// => false

include('geddyjs', 'js')
// => true

getInflections

getInflections(string<String>, options<Object>)

Options
  • initialCap [Boolean]

Inflection returns an object that contains different inflections created from the given name

Examples
getInflections('user')
// => {filename: { ... }, constructor: { ... }, property: { ... }}

Authentication

Geddy provides built-in authentication which integrates with Passport to allow auth against either local accounts or third-party social services like Facebook and Twitter.

Using the generator

To set up a new Geddy app with built-in authentication, create your application like normal, then run the geddy auth command inside, like so:

$ geddy app by_tor
$ cd by_tor
$ geddy auth

This will pull down Geddy-Passport using NPM, and install all the needed code into your app. This includes the needed Passport libraries, and the Geddy models and controllers for the local User accounts and the login process.

Danger, Warning, etc.

The geddy auth generator should only be used in a new Geddy app. If you run it inside an existing app, it may overwrite existing files that you wanted to keep.

If you need to add auth to an existing app, you can take a look at the Geddy-Passport project, which is itself a Geddy app scaffold, and use the pieces you need.

Configuring Passport

You'll need to add the settings for Passport in your config/secrets.json file. That includes the redirect locations for after an auth failure/success, and the OAuth keys for your app. The setting will look similar to this:

{
  "passport": {
    "successRedirect": "/",
    "failureRedirect": "/login",
    "twitter": {
      "consumerKey": "XXXXXX",
      "consumerSecret": "XXXXXX"
    },
    "facebook": {
      "clientID": "XXXXXX",
      "clientSecret": "XXXXXX"
    },
    "yammer": {
      "clientID": "XXXXXX",
      "clientSecret": "XXXXXX"
    }
  }
}

Local users

Local User accounts just go through the usual RESTful actions you'd get in a normal Geddy resource. Start at "/users/add" to create a new User. You can modify "/app/models/user.js" to add any other properties you want.

Login with third-party services

A successful login with a third-party service like Facebook or Twitter will create a linked local User account if one does not exist.

Authenticated users

After a user successfully authenticates, she will end up redirected to the successRedirect you've specified, and there will be two new items in the user's session:

  • userId -- the id for the local User account
  • authType -- the method of authentication (e.g., 'local', 'twitter')

Requiring authentication in your app

Use a before-filter, and redirect to the login page if there is no userId in the user's session. If there is a userId, that means the user is authenticated. There is a built-in reequireAuth function in the Passport helper-library, which does just this.

The User controller for local accounts is protected like this:

var passport = require('../helpers/passport')
  , cryptPass = passport.cryptPass
  , requireAuth = passport.requireAuth;

var Users = function () {
  this.before(requireAuth, {
    except: ['add', 'create']
  });

// Rest of controller omitted

This allows new accounts to be created, because the 'add' and 'create' actions are exempted, but only authenticated users can view or update existing users.