drumkit v0.1.1
DrumKit
WARNING! This framework is currently in very early development, it may be broken or may break at any time.
DrumKit is a plugin-powered, full-stack Web development framework for Node.js.
Installation
DrumKit is dependent on Node.js and NPM. If you have both, you can install DrumKit globally:
npm install -g drumkitIt is important to install this globally so that you have access to the drumkit command across your system.
All DrumKit modules on the other hand will be installed locally in each of your DrumKit projects.
Getting Started
DrumKit will bootstrap a project directory for you with the create command:
cd ~/myapps
drumkit create new-appThis will generate a DrumKit application in ~/myapps/new-app and will use npm to install
your dependencies. Once your app is installed, you can start the server:
cd new-app
drumkit startBy default, your app will be running at http://localhost:8765.
Running the Console
You also can interact with your code in a REPL by firing up the console:
cd path/to/your/app
drumkit consoleNow Build Your App!
Build models with dk-model (see also dk-model-couchdb and dk-couchdb).
Build view templates and helpers with dk-template.
Build routes with dk-routes.
Check out these other DrumKit plugins:
- Build your own plugins with
drumkit plugin [pluginName]
dk-core
WARNING! This framework is currently in very early development, it may be broken or may break at any time.
The dk-core plugin provides core functionality for the DrumKit.js framework. Currently it has no configuration
options.
Installation
Install the package with npm:
npm install dk-coreAvailable Commands
drumkit start env
cd into a project directory and run drumkit start to start up your DrumKit.js application.
The env defaults to development.
drumkit console env
cd into a project directory and run drumkit console to start up your application in a
coffeescript REPL console. The env defaults to development.
drumkit consolejs env
Works the same as drumkit console except it uses straight JavaScript rather than CoffeeScript.
drumkit plugin pluginName
Bootstraps a new Drumkit plugin at ./plugins/pluginName.
dk-assets
An Asset Manager Plugin for DrumKit.js
WARNING! This framework is currently in very early development, it may be broken or may break at any time.
Installation
You can install dk-assets using npm:
npm install dk-assetsGetting Started
Out of the box, dk-assets assumes that you have a public folder with js and css subdirectories:
- public
- css
- jsAny files inside the public dir are automatically served, so public/images/logo.png will be available
at http://localhost:8080/images/logo.png. You can change the location or name of your public directory
by specifying it with dk.assets.config.
All JS and CSS files can be automatically packaged (concatenated) into single files for faster loading.
You can turn packaging on by running dk.assets.config with the package option set to true.
Plugin Developers Guide
If you have JS and/or CSS assets that you want included in the asset packages, use the package method.
It takes a the URL that you want to serve the asset at, followed by either the path to your static asset
file or a function that returns JS/CSS. If you package a coffeescript or stylus file, they will be automatically
compiled to JS and CSS on the fly:
# Package a coffeescript file, serve at /js/my-file.js
dk.assets.package "/js/my-file.js", "#{__dirname}/some-dir/my-file.coffee"
# Package a stylus file, serve at /css/my-file.css
dk.assets.package "/css/my-file.css", "#{__dirname}/some-dir/my-file.stylus"
# Package the result of a function as a file
dk.assets.package "/js/dynamic.js", ->
"console.log('This could be something dynamically generated.');"For assets in your plugin that you want to serve but not package (ie images), you can use
the serve method, which behaves similarly to package:
# Serve a coffeescript file at /js/my-file.js
dk.assets.package "/js/my-file.js", "#{__dirname}/some-dir/my-file.coffee"
# Serve a stylus file at /css/my-file.css
dk.assets.package "/css/my-file.css", "#{__dirname}/some-dir/my-file.stylus"
# Serve the result of a function at /js/dynamic.js
dk.assets.package "/js/dynamic.js", ->
"console.log('This could be something dynamically generated.');"Full API
dk.assets.config(options)
Available options:
dir: (String) Sets the path to your public directory. All files in this directory will be automatically served. Defaults to "public"package: (Boolean) Sets whetherdk-assetsshould package all JS and CSS files into a single JS and CSS file (ie/js/all.jsand/css/all.css). This is preferable a production environment. Defaults to false
# Use a nonstandard public directory, package CSS and JS files
dk.assets.config dir: "nonstandard/public-dir", package: truedk.assets.package(url, fileOrFunction, serve=true)
Use the package method in order to make a JS or CSS file available at a given URL,
and add it to the package. Any coffeescript or stylus file will automatically
be compiled on the fly.
# Package a coffeescript file, serve at /js/my-file.js
dk.assets.package "/js/my-file.js", "#{__dirname}/some-dir/my-file.coffee"
# Package a stylus file, serve at /css/my-file.css
dk.assets.package "/css/my-file.css", "#{__dirname}/some-dir/my-file.stylus"
# Package the result of a function as a file
dk.assets.package "/js/dynamic.js", ->
"console.log('This could be something dynamically generated.');"dk.assets.serve(url, fileOrFunction)
Serves the given file (or string generated by the passed function) at the URL. This file is not added to the JS or CSS packages, and will not be automatically loaded on the page. Coffeescript and stylus code will be compiled on the fly.
# Serve a coffeescript file at /js/my-file.js
dk.assets.package "/js/my-file.js", "#{__dirname}/some-dir/my-file.coffee"
# Serve a stylus file at /css/my-file.css
dk.assets.package "/css/my-file.css", "#{__dirname}/some-dir/my-file.stylus"
# Serve the result of a function at /js/dynamic.js
dk.assets.package "/js/dynamic.js", ->
"console.log('This could be something dynamically generated.');"dk.assets.jsFiles()
Returns an array of relative URLs for all packaged JS files. If the package option
is true, it will return ["/js/all.js"].
# Get all the packaged JS URLs
dk.assets.jsFiles() # returns ["/js/thisFile.js", "/js/thatFile.js", etc...]dk.assets.cssFiles()
Returns an array of relative URLs for all packaged CSS files. If the package option
is true, it will return ["/css/all.css"].
# Get all the packaged CSS URLs
dk.assets.cssFiles() # returns ["/css/thisFile.css", "/css/thatFile.css", etc...]dk-couchdb
WARNING! This framework is currently in very early development, it may be broken or may break at any time.
The dk-couchdb plugin gives you access to CouchDB databases in a DrumKit.js app.
Installation
Install the package locally with npm:
npm install dk-couchdbOn the Server
new dk.couchdb()
Create a database connection to a CouchDB instance running at http://localhost:5984 by instantiating
a dk.couchdb object with your database name:
db = new dk.couchdb "my-database-name"If your CouchDB is running on another host or port, you can pass these in as options:
db = new dk.couchdb "my-database-name", host: "myhost.com", port: 1234db.get(id, function(err, data){})
Single documents can be fetched by id using the get instance method. This is an asynchronous
operation, so the second argument is a required callback.
db.get "some-id", (err, doc) ->
if err
console.log "Error: #{err}"
else
console.log "Got doc", docdb.view(viewName, function(err, docs){})
Multiple documents can be fetched using a CouchDB view with the view instance method.
This is an asynchronous operation, so the second argument is a required callback.
db.view "my-design-doc/all", (err, docs) ->
if err
console.log "Error: #{err}"
else
console.log "Got docs", docsdb.save(data, function(err, doc){})
You can create or update a document using the save instance method. This is an asynchronous
operation, so the second argument is a required callback. If the data has an id key, it will
be an update, otherwise save will create a new document.
data = {firstName: "Chris", lastName: "Powers"}
db.save data, (err, doc) ->
if err
console.log "Error: #{err}"
else
console.log "Saved doc", docdb.destroy(id, function(err){})
You can remove a document from the database using the destroy instance method with the document id.
This is an asynchronous operation, so the second argument is a required callback.
db.destroy "some-id", (err) ->
if err
console.log "Error: #{err}"
else
console.log "Removed the document"In the Browser
Currently dk-couchdb is not available directly in the browser, use dk-model instead.
dk-model-couchdb
A CouchDB Model adapter for DrumKit.
WARNING! This framework is currently in very early development, it may be broken or may break at any time.
Installation
Install this plugin with npm:
npm install dk-model-couchdbGetting Started
All you need to do is include this plugin in your package.json file and you should
be good to go. dk-model-couchdb will automatically hook into dk-model and
dk-couchdb for you, so no configuration should be necessary on your end.
dk-model
WARNING! This framework is currently in very early development, it may be broken or may break at any time.
The dk-model plugin provides a database-agnositic persistence layer API to
DrumKit.js that can be used both on the server and the browser.
Installation
Install dk-model using npm:
npm install dk-modelGetting Started
By default, dk-model expects your project to have a models directory that
will automatically load your model files from there. If you want to use a
different directory, you can configure the dir option:
dk.model.config dir: "#{__dirname}/nonstandardModelDir"Model classes are created using the dk.model method, which takes the model name
and a callback as parameters. The callback function will be called with your new
model class as the an argument. Inside the callback function is where you should
add instance methods, class methods and properties to your class. For example:
dk.model "User", (User) ->
# These are the attributes that will be persisted
User.property "firstName", String
User.property "lastName", String
# Class methods, this will print:
# Property: firstName, Type: String
# Property: lastName, Type: String
User.printProperties = ->
for name, type of this.properties
console.log "Property: #{name}, Type: #{type}"
# Instance methods (ie methods on prototype object)
User::fullName = ->
"#{@firstName} #{@lastName}"Model classes are generated by the CoffeeScript class construct, so you are
able to use prototypal inheritance.
To access your new model class in other files you can use the dk.model method
without the callback:
User = dk.model "User"
john = new User firstName: "John", lastName: "Smith"
john.fullName() # returns "John Smith"CRUD Operations
The goal of dk-model is to provide the developer with a database agnostic
persistence API that will proxy CRUD operations to the appropriate persistence
plugin. For example, the dk-model-couchdb plugin acts as an adapter between
dk-model and dk-couchdb.
All the methods listed below will be available both on the server and browser, as will your custom model methods.
All CRUD operations are asyncronous and require callback functions as their last parameter. The callback functions generally are passed any resulting errors as their first parameter and an object (or array of objects) as the second.
Class Methods
new MyModel(attributes={})
Instances of a model class are initialized using the new constructor and take
an object of attributes as the first parameter.
User = dk.model "User"
user = new User firstName: "John", lastName: "Smith".all(options, function(err, objects))
Fetches all records based on the options that are passed (options may be
different across adapters).
User = dk.model "User"
User.all {}, (err, users) ->
if err
console.log "Error fetching users:", err
else
for user in users
console.log "Fetched", user.fullName().get(id, function(err, object))
Fetches a single record by its identifier.
User = dk.model "User"
User.get 123, (err, user) ->
if err
console.log "Error fetching user:", err
else
console.log "Fetched", user.fullName().save(attributes, function(err, object))
Attempts to create a new record with the given attributes, or update
a record if attributes has an id.
User = dk.model "User"
User.save firstName: "John", lastName: "Smith", (err, user) ->
if err
console.log "Error creating user:", err
else
console.log "Created", user.fullName()
User.save id: 123, firstName: "Jane", lastName: "Doe", (err, user) ->
if err
console.log "Error updating user:", err
else
console.log "Updated", user.fullName().create(attributes, function(err, object))
Right now this simply aliases save.
.destroy(id, function(err))
Deletes the record with the given id.
User = dk.model "User"
User.destroy 123, (err) ->
if err
console.log "Error destroying user:", err
else
doSomethingElse()Instance Methods
save(function(err, object))
Saves the given model object. If it is a new record, then the object passed into the callback will have its new id.
User = dk.model "User"
user = new User firstName: "John"
user.lastName = "Smith"
user.save (err, obj) ->
if err
console.log "Error saving user:", err
else
console.log "New user's id is", obj.iddestroy(function(err))
Deletes the given model object from persistence (currently the JS object will remain in memory).
User = dk.model "User"
User.get 123, (err, user) ->
user.destroy (err) ->
if err
console.log "Error destroying user:", err
else
console.log "Just destroyed", user.fullName()TODO
This still needs a lot of work and love, including but not limited to:
- Validation
- Better error handling
- Using promises rather than callbacks
- More adapters
dk-routes
WARNING! This framework is currently in very early development, it may be broken or may break at any time.
This is a DrumKit plugin that adds URL routing on both the server and browser.
Installation
Install dk-routes with npm:
npm install dk-routesGetting Started
The dk-routes plugin assumes that you have a routes.coffee file that defines
all your routes. To use a different file, pass the path option to config:
dk.routes.config path: "#{__dirname}/nonstandard-path.coffee"Inside this file you can define your routes, which will be available both on the
server and on the browser. The routes DSL provides you with the top level methods
get, post, put and del (delete). Each of these methods takes three parameters --
a route URL, an optional helper method name and a function. For example:
get "/users", "users", ->
dk.model("User").all {}, (err, users) =>
this.render "users", users: usersIn the above example, when either the server or the browser receives a request
for the url /users, it will fetch all the User objects and use them to
render the users view. Also, because "users" was passed as the second parameter
to get, the helper method usersPath will be added to all templates.
Note that in the example, the callback passed to the User.all method uses the
double arrow => rather than the single ->. This is done to maintain the value of
this inside the callback because inside routes, this points to a special
RouteContext object.
RouteContext
Inside of any route function, this refers to a RouteContext object. These
objects have two purposes:
- Make request details available (ex. params)
- Provide route actions (ex. rendering, redirects)
Here is the current (limited) API:
params(paramName)
Returns the value of the request param with the given name. This param could be in the URL, the querystring or a POST message body.
get "/users/:id", "user", ->
dk.model("User").get this.params("id"), (err, user) =>
this.render "user", user: userrender(templateName, locals)
Renders the template with the given templateName using the given locals.
get "/users/:id", "user", ->
dk.model("User").get this.params("id"), (err, user) =>
this.render "user", user: userredirect(path)
Redirect the user to the given path.
post "/users", ->
dk.model("User").create this.params("user"), (err, user) =>
this.redirect "/users/#{user.id}"title(str)
Sets the value of the page title tag.
get "/users/:id", "user", ->
dk.model("User").get this.params("id"), (err, user) =>
this.title "User: #{user.fullName()}"
this.description "This is a page about #{user.fullName()}"
this.render "user", user: userdescription(str)
Sets the value of the page description meta tag.
get "/users/:id", "user", ->
dk.model("User").get this.params("id"), (err, user) =>
this.title "User: #{user.fullName()}"
this.description "This is a page about #{user.fullName()}"
this.render "user", user: userTODO
Tons of work still needed on this, especially:
- Figure out how to keep browser from overwriting what server generates
- Build out
RouteContextto have more request data and actions - Allow routes file to be straight JS
- More routing features
dk-server
HTTP Server Plugin for DrumKit.js
WARNING! This framework is currently in very early development, it may be broken or may break at any time.
Installation
You can install dk-server using npm:
npm install dk-serverGetting Started
This module is meant to be pretty low-level, so application developers should not need to ever
use it directly. If you need to setup URLs and respond to HTTP requests, you should probably be
using the dk-routes plugin.
Plugin Developers Guide
The dk-server plugin acts as a Connect compliant server to allow you to respond to requests
and wire up middleware. You are given get, post, put, del and use. This module cannot
be used on the browser.
dk.server.get "/hello", (req, res) ->
res.send "Hello there!"
connect = require "connect"
dk.server.use connect.logger(format: ":method :url")NOTE: If you need to serve asset files (JS, CSS, images), use dk-assets.
dk-template
Server and Browser Templating for DrumKit.js
WARNING! This framework is currently in very early development, it may be broken or may break at any time.
Installation
You can install dk-template using npm:
npm install dk-assetsGetting Started
Out of the box, dk-template assumes that you have a views directory that holds all of your templates.
If you need to customize this, you can do so in your app configuration:
dk.template.config dir: "/path/to/my/views"Currently dk-template supports .eco and .ejs templates. Other rendering engines can easily be
added (see Plugin Developers Guide). The render method takes a template name and a context object,
returning the rendered template as a string:
<!-- in views/js-user.ejs -->
<p>My name is <%= user.name %> and I like straight JS.</p>
```html
<!-- in views/coffee-user.eco -->
<p>My name is <%= @user.name %> and I prefer CoffeeScript.</p>
```coffeescript
# In my CoffeeScript source
dk.template.render "js-user", user: {name: "John"}
# => returns "<p>My name is John and I like straight JS.</p>"
dk.template.render "coffee-user", user: {name: "Jane"}
# => returns "<p>My name is Jane and I prefer CoffeeScript.</p>"
The `render` method is available both on the server and the browser. Please refer
to the EJS and ECO projects' documentation for a full explanation of their features.
## View Helper Methods
To add helper methods that will be available to all templates, use the
`dk.template.helpers.add` method in your `helpers.coffee` file:
```html
<!-- in views/quote.eco -->
<p>Favorite Quote: "<%= @truncate @quote, 10 %>"</p># In helpers.coffee
dk.template.helpers.add
truncate: (str, len) ->
if str.length > len
str.slice(0, len) + '...'
else
str# Elsewhere in the app
dk.template.render "quote", quote: "Four score and seven years ago"
# returns '<p>Favorite Quote: "Four score..."</p>Helper methods defined in your helpers.coffee file will be made available on
both the server and browser. If you want to define your helper methods in a file
other than helpers.coffee, you can do so by using the helpersPath config option:
dk.template.config helpersPath: "#{__dirname}/nonstandardHelpersPath.coffeeAlso, you can use a helpers.js file instead if you prefer straight JS.
Plugin Developers Guide
Support for .ejs, .eco and .mustache files was added simply using Drumkit plugin extensions, so it is
easy to create your own extensions to support other rendering engines. View the following files
to see how it is done:
lib/dk-template-eco.coffeelib/dk-template-ejs.coffeelib/dk-template-mustache.coffeepublic/js/dk-template-eco.coffeepublic/js/dk-template-ejs.coffeepublic/js/dk-template-mustache.coffee
dk.template.layout
This module is responsible for rendering full page layouts on the server. By default,
dk.template.layout uses its own minimal layout, which is at ./views/layout.eco. To use
your own custom layout file, use the path option of the config method.
dk.template.layout.config(options)
Available options:
path: (String) An absolute path to your custom layout file. Defaults to using a built-in layout.title: (String) A default page title, defaults to "".description: (String) A default page description, defaults to "".
dk.template.layout.config
path: "#{__dirname}/views/layout.eco"
title: "My DrumKit App"
description: "This app was built using DrumKit.js"dk.template.layout.render(templateName, context)
Renders the template called templateName inside of your layout.
NOTE: The layout has these additional values available in its context:
content: The rendered content of the inner view templatetemplateName.title: The page title.description: The page description.
# renders the 'users' template inside of the page layout
dk.template.layout.render "users", users: ["Bill", "Susan"]dk-websockets
WARNING! This framework is currently in very early development, it may be broken or may break at any time.
The dk-websockets plugin adds Websocket functionality to your DrumKit.js application.
Installation
Install the package with npm:
npm install dk-websocketsGetting Started
For general use you should not use dk-websockets directly -- use the higher-level dk-transport instead.
Plugin Developers Guide
The dk.websockets object is an EventEmitter, so you can listen for the following events:
dk.websockets.on "connection", (client) ->
# do something
dk.websockets.on "message", (msg) ->
# do something
dk.websockets.on "disconnect", (client) ->
# do something