gist

2012年3月14日水曜日

Twitter生まれの軽量なMVCフレームワーク「Matador」を試してみた

Matadorは、TwitterのOBが開発したNode.jsのMVCフレームワークです。ExpressにMVCの手法を取り入れたような、シンプルで軽量なフレームワークになっています。

インストールからアプリの雛形作成、起動まで。

$ npm install -g matador
$ npm init sample
$ cd sample
$ npm install
$ node server.js
matador running on port 3000

と、まあ、ここまでは簡単です。

少し構造を見てみます。

依存パッケージ

$ npm ls
/Users/inouetomoyuki/Dropbox/Projects/node/sample
└─┬ matador@1.0.11-beta 
  ├── colors@0.6.0-1 
  ├─┬ express@2.5.8 
  │ ├─┬ connect@1.8.5 
  │ │ └── formidable@1.0.9 
  │ ├── mime@1.2.4 
  │ ├── mkdirp@0.3.0 
  │ └── qs@0.4.2 
  ├── hogan.js@2.0.0 
  ├── klass@1.2.2 
  ├─┬ optimist@0.3.1 
  │ └── wordwrap@0.0.2 
  ├── uglify-js@1.2.5 
  └── valentine@1.5.1 

Express, Hogan, Klassを使っています。

アプリ作成直後のディレクトリ構造

$ tree app
server.js
node_modules/
app
├── config
│   ├── development.js
│   ├── production.js
│   └── routes.js
├── controllers
│   ├── ApplicationController.js
│   └── HomeController.js
├── models
│   ├── ApplicationModel.js
│   └── BaseModel.js
├── public
│   └── css
│       ├── directory.css
│       └── main.css
└── views
    ├── 404.html
    ├── admin
    │   ├── index.html
    │   └── partials
    │       └── helloworld.html
    ├── directory.html
    ├── index.html
    ├── layout.html
    └── partials
        └── helloworld.html

model, view, controller できちんと分かれていますね。シンプルです。

MongoDBを使って、タイトルと本文を登録するアプリを作ってみます。

まずはHelloWorldっぽいのを削除します。

$ app/controllers/HomeController.js
$ app/views/index.html
$ app/views/partials/helloworld.html

MongoDBはググってインストールして起動させておきましょう。

mongoose, mongodbをインストールします。

$ npm install mongoose
$ npm install mongodb

mongoを設定します。

app/models/ApplicationModel.js

module.exports = function (app, config) {
  return app.getModel('Base', true).extend(function() {
    this.mongo = require('mongodb')
    this.mongoose = require('mongoose')
    this.Schema = this.mongoose.Schema
    this.mongoose.connect('mongodb://localhost/madador')
  })  
}

scaffold機能でmodelとcontrollerの雛形を作成します。

$ madator controller Post
$ madator model Post

雛形にアクションを追加していきます。

app/models/PostModel.js

module.exports = function (app, config) {
  
  return app.getModel("Application", true).extend(function() {
      this.DBModel = this.mongoose.model('Post', new this.Schema({
          title: {type: String, require:true, trim:true }
        , body: {type: String, require:true, trim:true }
      }))
  })
  .methods({
    save: function(title, body, callback) {
      var post = new this.DBModel({
          title: title
        , body: body
      })
      post.save(callback)
    }
  , index: function(callback) {
      this.DBModel.find(callback)
    }
  })
}

app/controllers/PostController.js

module.exports = function (app, config) {
  
  return app.getController("Application", true).extend(function() {
    this.viewFolder = 'posts' // まだ動作しない模様
  })      
  .methods({
    index: function (req, res) {
      var PostModel = app.getModel('Post', true)
      var model = new PostModel()
      var _self = this
      model.index(function(err, posts) {
        if(err) throw err;
        _self.render(res, 'index', {
          posts: posts
        })
      })
    }
  , form: function(req, res) {
      this.render(res, 'new', {})
    }
  , create: function(req, res) {
      var PostModel = app.getModel('Post', true)
      var model = new PostModel()
      var _self = this;
      model.save(req.body.title, req.body.body, function(err) {
        if(err) throw err;
        res.redirect('/')
      })
    }
  })
}

ビューを作ります。登録フォームと一覧だけ。

app/views/index.html

<table border="1">
<tr>
<td>タイトル</td>
<td>一言</td>
</tr>     
  
{{#posts}} 
<tr>  
  <td><b>{{title}}</b></td>
<td>{{body}}</td> 
</tr> 
{{/posts}}
</table>
<a href="/posts/new">新規投稿</a>

app/views/new.html

<form action="/posts/create" method="post">
<label>タイトル</label><br />
<input type="input" name="title"><br />
<label>本文</label><br />
<textarea name="body"></textarea><br />
<input type="submit" value="登録">

</form>

ルーティングを定義します。

app/config/routes.js

module.exports = function (app) {
  return { 
    root: [
       ['get', '/', 'Post', 'index']
     ,  ['get', '/posts', 'Post', 'index']
     ,  ['get', '/posts/new', 'Post', 'form']
     ,  ['post', '/posts/create', 'Post', 'create']
    ]
  }
}

起動してみます。

http://localhost:3000/posts/new

http://localhost:3000/

viewsディレクトリ内をposts/new.htmlのように配置するには、PostController のコンストラクタに this.viewFolder = "posts" みたいにするそうですが、まだ動作しないようです。GitHub Issue

Matadorは Tower.jsに比べるてシンプルなので理解しやすいですね。CoffeeScriptに対応しないかな。

追記

MatadorはCoffeeScriptに対応しました。対応方法は、[Node.js] Matador+CoffeeScriptの環境を構築する をご覧下さいませ。

0 件のコメント: