CoffeeBoxは、Node.js、CoffeeScript、MondoDbで作成されたシンプルなブログアプリです。
そこそこ本格的で「学べる」コードだと思いますので、インストールから触りだけ読んでみたいと思います。
UIもキレイです。
インストールして起動まで一気に。
$ git clone https://github.com/qiao/coffee-box $ cd coffee-box/ $ npm install $ mongod --dbpath ~/MongoDb (MongoDBを起動しておきます) $ node index.js coffee-box server listening on port 3000 in development mode
http://localhost:3000 にアクセスします。
Login画面。OpenIDを使えます。
新規投稿です。
投稿完了。
ダッシュボード。
コードを少し見てみます。
ファイル構成です。
index.js
server.coffee
lib
├── markdown.coffee
├── marked.js
├── require_dir.coffee
└── taglist.coffee
public/
├── 404.html
├── favicon.ico
└── images
├── CREDIT
└── fabric_1.png
scripts/
└── populate.coffee
config/
├── config.coffee
├── routes.coffee
└── site.json
app
├── assets
│ ├── javascripts
│ │ ├── application.coffee
│ │ ├── bootstrap-tabs.js
│ │ ├── comments.coffee
│ │ ├── jquery.elastic.js
│ │ ├── jquery.js
│ │ ├── jquery.textarea.js
│ │ ├── preview.coffee
│ │ ├── session.coffee
│ │ └── site.coffee
│ └── stylesheets
│ ├── application.styl
│ ├── bootstrap.css
│ ├── comments.styl
│ ├── dashboard.styl
│ ├── posts.styl
│ ├── pygments.css
│ ├── session.styl
│ └── site.styl
├── controllers
│ ├── comments_controller.coffee
│ ├── dashboard_controller.coffee
│ ├── posts_controller.coffee
│ └── session_controller.coffee
├── helpers
│ ├── comments_helper.coffee
│ └── posts_helper.coffee
├── models
│ ├── comment.coffee
│ └── post.coffee
└── views
├── comments
│ ├── _comment.jade
│ ├── _comments.jade
│ ├── _form.jade
│ └── _spam.jade
├── dashboard
│ ├── _comments.jade
│ ├── _posts.jade
│ └── index.jade
├── layouts
│ ├── _footer.jade
│ ├── _header.jade
│ └── layout.jade
├── posts
│ ├── _form.jade
│ ├── edit.jade
│ ├── index.jade
│ ├── new.jade
│ └── show.jade
└── session
└── new.jade
MVCにわかれています。ViewテンプレートにはJadeを使っています。スタイルシートはStylus。
次に依存パッケージを見ていきます。
coffee-box@0.0.6 /Users/inouetomoyuki/Projects/node/coffee-box ├── async@0.1.18 ├── coffee-script@1.2.0 ├─┬ connect-assets@2.1.9 │ ├── connect-file-cache@0.2.4 │ ├── mime@1.2.2 │ ├─┬ snockets@1.3.4 │ │ ├── dep-graph@1.0.1 │ │ └── uglify-js@1.0.7 │ └── underscore@1.1.7 ├─┬ express@2.5.8 │ ├─┬ connect@1.8.6 │ │ └── formidable@1.0.9 │ ├── mime@1.2.4 │ ├── mkdirp@0.3.0 │ └── qs@0.4.2 ├── express-messages@0.0.2 ├── gravatar@1.0.6 ├─┬ jade@0.22.1 │ ├── commander@0.5.2 │ └── mkdirp@0.3.0 ├── moment@1.5.1 ├─┬ mongoose@2.5.13 │ ├── hooks@0.2.0 │ └─┬ mongodb@0.9.9-7 │ └── bson@0.0.4 ├── openid@0.4.1 ├─┬ pygments@0.1.2 │ └── underscore@1.3.1 ├─┬ rss@0.0.3 │ ├── logging@2.0.16 │ └── xml@0.0.7 ├─┬ stylus@0.25.0 │ ├── cssom@0.2.3 │ ├── debug@0.6.0 │ └── mkdirp@0.3.1 ├── uglify-js@1.2.6 └── validator@0.4.5
Expressが使われています。MongoDBのODMにはMongooseです。エラー表示やステータス表示にexpress-message。connect-assetsで、Rails Asset PipelineっぽくCSSやらJSやらまとめているようです。
server.coffeeを見てみます。
express = require 'express'
app = module.exports = express.createServer()
require('./config/config') app
require('./config/routes') app
app.listen 3000
console.log "coffee-box server listening on port #{app.address().port} " +
"in #{app.settings.env} mode"
Expressを使っています。ConfigとRouterがあるみたい。
ルータを見ていきます。
config/routes.coffee(一部)
module.exports = (app) -> # get controllers from app settings controllersGetter = app.settings.controllersGetter PostsController = controllersGetter.getPostsController app CommentsController = controllersGetter.getCommentsController app SessionController = controllersGetter.getSessionController app DashboardController = controllersGetter.getDashboardController app # middleware for finding all posts published as individual pages findPages = PostsController.findPages # middleware for requiring login requireLogin = SessionController.requireLogin app.get '/' , findPages , PostsController.index app.get '/posts.:format?' , findPages , PostsController.index app.get POST_SHOW_PATTERN , findPages , PostsController.show app.get '/posts/new.:format?' , requireLogin , findPages , PostsController.new app.get POST_EDIT_PATTERN , requireLogin , findPages , PostsController.edit app.post '/posts.:format?' , requireLogin , PostsController.create app.put POST_SHOW_PATTERN , requireLogin , PostsController.update app.del POST_SHOW_PATTERN , requireLogin , PostsController.destroy app.post '/posts/preview' , PostsController.preview
Controllerを登録して、ルーティングを決めています。例えば app.get '/'だったら、PostControllerのindex関数にルーティングされていることがわかります。
Postコントローラを見ていきます。
post_controller.coffee(一部)
index: (req, res, next) ->
# check pagination param: /posts/?page=2
pageNo = parseInt(req.query['page'], 10) or 1
POSTS_PER_PAGE = 5
Post.countPostPages POSTS_PER_PAGE, (err, totalPages) ->
Post.getPostsOfPage pageNo, POSTS_PER_PAGE, (err, posts) ->
return res.redirect '500' if err?
res.render 'posts/index'
posts: posts
pageNo: pageNo
totalPages: totalPages
Post.getPostsOfPage がモデルを呼び出しているところ。res.renderでViewのposts/index.jadeにデータを投げ込んでレンダリングしています。
Postモデルを見ていきます。
app/models/post.coffee
async = require 'async'
mongoose = require 'mongoose'
Schema = mongoose.Schema
{markdown} = require('../../lib/markdown')
{makeTagList} = require('../../lib/taglist')
{CommentSchema} = require('./comment')
PostSchema = new Schema
title:
type: String
required: true
content:
type: String
rawContent:
type: String
slug:
type: String
required: true
unique: true
comments:
type: [CommentSchema]
(中略)
PostSchema.statics.getPostsOfPage = (pageNo, postsPerPage, callback) ->
@countPostPages postsPerPage, (err, count) =>
return callback err, null if err?
query =
public: true
asPage: false
options =
skip: (pageNo - 1) * postsPerPage
limit: postsPerPage
sort: [['createdAt', 'desc']]
@find query, {}, options, callback
mongooseを使ってスキーマを作っています。getPostsOfPage メソッドで、MongoDbにクエリを投げています。
Postのindexビューを見ていきます。
app/views/posts/index.jade(一部)
// entry list
ul.unstyled#entry-list
each post in posts
li!= partial('show', { locals: { post: post } })
(略)
Postコントローラの、res.renderでPostモデルから取得したデータを postsに入れています。jadeでループさせて表示させています。個々のPostデータの表示には、パーシャルを使って show.jade で表示させています。
app/views/posts/show.jade
article.entry.post
!= messages()
header.entry-header
h2.entry-title
a(href=postPath(post))= post.title
.entry-meta
.entry-day= postDay(post)
.entry-month= postMonth(post)
.entry-content
!= post.content
!= partial('comments/comments', { post: post, comments: post.comments })
全体的な流れはこんな感じです。
CoffeeBoxのコードはMVCでの組み方がよくわかります。ブログではログインの方法やセッションの持たせ方、設定などの方法、Stylusでの組み方、Assetの使い方についても理解しやすいです。
まだ改善できるところもありますし、CoffeeBoxは、コールドリーディングにはちょうどいい素材かもしれません。これがすべてではありませんが、脱初心者を目指す方はぜひ。





0 件のコメント:
コメントを投稿