Skip to content

Commit

Permalink
clean
Browse files Browse the repository at this point in the history
  • Loading branch information
lancejpollard committed Jan 24, 2012
1 parent 13e4370 commit 2d11ab9
Show file tree
Hide file tree
Showing 24 changed files with 184 additions and 87 deletions.
2 changes: 1 addition & 1 deletion .npmignore
Expand Up @@ -10,4 +10,4 @@ spec/
dist/
examples/
favicon.ico
Watchfile
Watchfile
171 changes: 119 additions & 52 deletions README.md
@@ -1,18 +1,15 @@
# Tower.js

> Full Stack Web Framework for Node.js and the Browser. Minified & Gzipped: 15.7kb
> Full Stack Web Framework for Node.js and the Browser.
## Todo
Built on top of Node's Connect and Express, modeled after Ruby on Rails. Built for the client and server from the ground up.

- Controller testing framework
- mock http requests
- mock socket requests
- Database reset and testing
Includes a database-agnostic ORM with browser (memory) and MongoDB support, modeled after ActiveRecord and Mongoid for Ruby. Includes a controller architecture that works the same on both the client and server, modeled after Rails. The routing API is pretty much exactly like Rails 3's. Templates work on client and server as well (and you can swap in any template engine no problem). Includes asset pipeline that works just like Rails 3's - minifies and gzips assets with an md5-hashed name for optimal browser caching, only if you so desire. And it includes a watcher that automatically injects javascripts and stylesheets into the browser as you develop. It solves a lot of our problems, hope it solves yours too. If not, let me know!

## Install

``` bash
npm install tower
npm install tower -g
```

## Generator
Expand Down Expand Up @@ -79,11 +76,22 @@ Here's how you might organize a blog:
``` coffeescript
# config/application.coffee
class App extends Tower.Application
@config.encoding = "utf-8"
@config.filterParameters += ["password", "password_confirmation"]
@config.loadPaths += ["./themes"]
global.App = module.exports = App
@configure ->
@use "favicon", Tower.publicPath + "/favicon.ico"
@use "static", Tower.publicPath, maxAge: Tower.publicCacheDuration
@use "profiler" if Tower.env != "production"
@use "logger"
@use "query"
@use "cookieParser", Tower.session.secret
@use "session", Tower.session.key
@use "bodyParser"
@use "csrf"
@use "methodOverride", "_method"
@use Tower.Middleware.Agent
@use Tower.Middleware.Location
@use Tower.Middleware.Router
module.exports = global.App = App
```
## Models
Expand Down Expand Up @@ -221,29 +229,39 @@ Tower.Route.where(pattern: "=~": "/posts").first()
``` coffeescript
# app/views/posts/new.coffee
formFor @post, ->
fieldset ->
legend "Basic Info"
field "title"
field "body", as: "text"
submit "Save"
formFor "post", (f) ->
f.fieldset (fields) ->
fields.field "title", as: "string"
fields.field "body", as: "text"
fields.field "position", as: "textField"
f.fieldset (fields) ->
fields.submit "Submit"
```
### Tables
``` coffeescript
# app/views/posts/index.coffee
tableFor @posts, ->
thead ->
tcell "Title"
tcell "Author"
tbody ->
tableFor "posts", (t) ->
t.head ->
t.row ->
t.cell "title", sort: true
t.cell "body", sort: true
t.cell "position", sort: true
t.cell()
t.cell()
t.cell()
t.body ->
for post in @posts
trow
tcell post.title
tcell post.author.name
tfoot ->
pagination @posts
t.row ->
t.cell post.get("title")
t.cell post.get("body")
t.cell post.get("position")
t.cell linkTo 'Show', post
t.cell linkTo 'Edit', editPostPath(post)
t.cell linkTo 'Destroy', post, method: "delete"
linkTo 'New Post', newPostPath()
```
### Layouts
Expand All @@ -253,29 +271,53 @@ tableFor @posts, ->
doctype 5
html ->
head ->
meta charset: 'utf-8'
title "#{@title or 'Untitled'} | My awesome website"
meta name: 'description', content: @desc if @desc?
stylesheets "vendor", "application"
meta charset: "utf-8"
title t("title")
meta name: "description", content: t("description")
meta name: "keywords", content: t("keywords")
meta name: "robots", content: t("robots")
meta name: "author", content: t("author")
csrfMetaTag()
appleViewportMetaTag width: "device-width", max: 1, scalable: false
stylesheets "lib", "vendor", "application"
javascriptTag "https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"
javascripts "vendor", "lib", "application"
body ->
header ->
h1 @title or 'Untitled'
nav ->
ul ->
(li -> a href: '/', -> 'Home') unless @path is '/'
li -> a href: '/chunky', -> 'Bacon!'
switch @user.role
when 'owner', 'admin'
li -> a href: '/admin', -> 'Secret Stuff'
when 'vip'
li -> a href: '/vip', -> 'Exclusive Stuff'
else
li -> a href: '/commoners', -> 'Just Stuff'
section ->
yield()
footer ->
p shoutify('bye')
body role: "application", ->
if hasContentFor "templates"
yield "templates"
nav id: "navigation", role: "navigation", ->
div class: "frame", ->
partial "shared/navigation"
header id: "header", role: "banner", ->
div class: "frame", ->
partial "shared/header"
section id: "body", role: "main", ->
div class: "frame", ->
yields "body"
aside id: "sidebar", role: "complementary", ->
if hasContentFor "sidebar"
yields "sidebar"
footer id: "footer", role: "contentinfo", ->
div class: "frame", ->
partial "shared/footer"
if hasContentFor "popups"
aside id: "popups", ->
yields "popups"
if hasContentFor "bottom"
yields "bottom"
```
The default templating engine is [CoffeeKup](http://coffeekup.org/), which is pure coffeescript. It's much more powerful than Jade, and it's just as performant if not more so. You can set Jade or any other templating engine as the default by setting `Tower.View.engine = "jade"` in `config/application`. Tower uses [Shift.js](http://github.com/viatropos/shift.js), which is a normalized interface to most of the Node.js templating languages.
Expand Down Expand Up @@ -314,6 +356,30 @@ class PostsController extends Tower.Controller
Actually, all that's built in! So for the simple case you don't even need to write anything in your controllers (skinny controllers, fat models).
## Databases
``` coffeescript
# config/databases.coffee
module.exports =
mongodb:
development:
name: "app-development"
port: 27017
host: "127.0.0.1"
test:
name: "app-test"
port: 27017
host: "127.0.0.1"
staging:
name: "app-staging"
port: 27017
host: "127.0.0.1"
production:
name: "app-production"
port: 27017
host: "127.0.0.1"
```
## Mailers
``` coffeescript
Expand All @@ -326,7 +392,8 @@ class App.Notification extends Tower.Mailer
## Internationalization
``` coffeescript
en:
# config/locales/en.coffee
module.exports =
hello: "world"
forms:
titles:
Expand Down Expand Up @@ -376,7 +443,7 @@ It's built on [connect](http://github.com/sencha/connect), so you can use any of
``` coffeescript
# config/assets.coffee
Tower.assets =
module.exports =
javascripts:
vendor: [
"/vendor/javascripts/jquery.js"
Expand Down
3 changes: 2 additions & 1 deletion lib/tower/client/controller/events.js
Expand Up @@ -2,7 +2,6 @@
Tower.Controller.Events = {
ClassMethods: {
DOM_EVENTS: ["click", "dblclick", "blur", "error", "focus", "focusIn", "focusOut", "hover", "keydown", "keypress", "keyup", "load", "mousedown", "mouseenter", "mouseleave", "mousemove", "mouseout", "mouseover", "mouseup", "mousewheel", "ready", "resize", "scroll", "select", "submit", "tap", "taphold", "swipe", "swipeleft", "swiperight"],
DOM_EVENT_PATTERN: new RegExp("^(" + (this.DOM_EVENTS.join("|")) + ")"),
dispatcher: global,
addEventHandler: function(name, handler, options) {
if (options.type === "socket" || !eventType.match(this.DOM_EVENT_PATTERN)) {
Expand Down Expand Up @@ -57,4 +56,6 @@ Tower.Controller.Events = {
}
};

Tower.Controller.Events.ClassMethods.DOM_EVENT_PATTERN = new RegExp("^(" + (Tower.Controller.Events.ClassMethods.DOM_EVENTS.join("|")) + ")");

module.exports = Tower.Controller.Events;
17 changes: 12 additions & 5 deletions lib/tower/generator/generators/tower/app/appGenerator.js
Expand Up @@ -32,9 +32,12 @@ Tower.Generator.AppGenerator = (function() {
return this.template("application.coffee");
});
this.directory("helpers");
return this.inside("stylesheets", function() {
this.inside("stylesheets", function() {
return this.template("application.styl");
});
return this.inside("controllers", function() {
return this.template("applicationController.coffee");
});
});
this.inside("controllers", function() {
return this.template("applicationController.coffee");
Expand Down Expand Up @@ -88,7 +91,7 @@ Tower.Generator.AppGenerator = (function() {
});
});
this.directory("log");
this.template("package.json");
this.template("pack", "package.json");
if (!this.program.skipProcfile) this.template("Procfile");
this.inside("public", function() {
this.template("404.html");
Expand All @@ -98,7 +101,11 @@ Tower.Generator.AppGenerator = (function() {
this.template("humans.txt");
this.template("robots.txt");
return this.inside("javascripts", function() {
return this.createFile("templates.js", "");
return this.inside("app", function() {
return this.inside("views", function() {
return this.createFile("templates.js", "");
});
});
});
});
this.template("README.md");
Expand All @@ -122,8 +129,8 @@ Tower.Generator.AppGenerator = (function() {
this.get("https://raw.github.com/balupton/history.js/master/scripts/uncompressed/history.js", "history.js");
this.get("https://raw.github.com/timrwood/moment/master/moment.js", "moment.js");
this.get("https://raw.github.com/medialize/URI.js/gh-pages/src/URI.js", "uri.js");
this.get("http://coffeekup.org/coffeekup.js", "coffeekup.js");
return this.get("https://raw.github.com/visionmedia/mocha/master/mocha.js", "mocha.js");
this.get("https://raw.github.com/visionmedia/mocha/master/mocha.js", "mocha.js");
return this.get("http://coffeekup.org/coffeekup.js", "coffeekup.js");
});
this.directory("stylesheets");
return this.inside("swfs", function() {
Expand Down
@@ -0,0 +1,3 @@
class <%= project.className %>.ApplicationController extends Tower.Controller
ready: ->

@@ -1 +1,5 @@
// https://github.com/blup/bootstrap-stylus/blob/master/lib/bootstrap/forms.styl
// @import '/lib/stylesheets/variables'
// @import '/lib/stylesheets/mixins'
// @import '/lib/stylesheets/tables'
// @import '/lib/stylesheets/forms'
// @import '/lib/stylesheets/typography'
Expand Up @@ -7,7 +7,7 @@ html ->
#if browserIs "ie"
# javascriptTag "http://html5shiv.googlecode.com/svn/trunk/html5.js"

if contentFor "templates"
if hasContentFor "templates"
yields "templates"

nav id: "navigation", role: "navigation", ->
Expand All @@ -24,16 +24,16 @@ html ->
div class: "frame", ->
yields "body"
aside id: "sidebar", role: "complementary", ->
if contentFor "sidebar"
if hasContentFor "sidebar"
yields "sidebar"

footer id: "footer", role: "contentinfo", ->
div class: "frame", ->
partial "shared/footer"

if contentFor "popups"
if hasContentFor "popups"
aside id: "popups", ->
yields "popups"

if contentFor "bottom"
if hasContentFor "bottom"
yields "bottom"
@@ -0,0 +1 @@
ul
Expand Up @@ -3,6 +3,7 @@ module.exports =
application: [
"/app/client/config/application"
"/config/routes"
"/app/views/templates.js"
]

lib: [
Expand Down
Expand Up @@ -13,9 +13,7 @@ Tower.Generator.AssetsGenerator = (function() {
AssetsGenerator.prototype.run = function() {
return this.inside("app", '.', function() {
return this.inside("client", '.', function() {
return this.inside("stylesheets", '.', function() {
return this.template("stylesheet.css", "" + this.model.pluralName + ".styl");
});
return this.inside("stylesheets", '.', function() {});
});
});
};
Expand Down
Expand Up @@ -12,9 +12,14 @@ Tower.Generator.ControllerGenerator = (function() {

ControllerGenerator.prototype.run = function() {
this.inside("app", '.', function() {
return this.inside("controllers", '.', function() {
this.inside("controllers", '.', function() {
return this.template("controller.coffee", "" + this.model.pluralName + "Controller.coffee");
});
return this.inside("client", function() {
return this.inside("controllers", '.', function() {
return this.template("controller.coffee", "" + this.model.pluralName + "Controller.coffee");
});
});
});
return this.route('@resources "' + this.model.pluralName + '"');
};
Expand Down
@@ -0,0 +1,2 @@
class <%= project.className %>.<%= model.pluralClassName %>Controller extends Tower.Controller

@@ -1,9 +1,6 @@
class <%= model.namespacedClassName %> extends Tower.Model
@field "id", type: "Id"<% for (var i = 0; i < model.attributes.length; i++) { %>
@field "<%= model.attributes[i].name %>", type: "<%= model.attributes[i].type %>"<% if (model.attributes[i].default != null) { %>, default: <%= model.attributes[i].default %><% } %><% } %>

<% for (var i = 0; i < model.relations.length; i++) { %>
@<%= model.relations[i].type %> "<%= model.relations[i].name %>"
<% } %>

@<%= model.relations[i].type %> "<%= model.relations[i].name %>"<% } %>
@timestamps()

0 comments on commit 2d11ab9

Please sign in to comment.