npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

torero

v0.0.8-alpha

Published

an MVC framework for Node that I'm going to maintain.

Downloads

5

Readme

Matador

Sane defaults and a simple structure, scaling as your application grows.

Matador is a clean, organized framework for Node.js architected to suit MVC enthusiasts. It gives you a well-defined development environment with flexible routing, easy controller mappings, and basic request filtering. It’s built on open source libraries such as Hogan.js for view rendering, Klass for its inheritance model, Valentine for functional development, and Express to give a bundle of other Node server related helpers.

Installation

Get the CLI

$ npm install matador -g

Create an app

$ matador init my-app
$ cd !$ && npm install matador

Start your app

$ node server.js

Dancing with the Bulls

Build on your app

// app/config/routes.js
'/hello/:name': { 'get': 'Home.hello' }

// app/controllers/HomeController.js
hello: function (request, response, name) {
  response.send('hello ' + name)
}

View Rendering

Uses Twitter's Hogan.js with layouts, partials, and i18n support.

// app/controllers/HomeController.js
this.render(response, 'index', {
  title: 'Hello Bull Fighters'
})
<!-- app/views/layout.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-type" content="text/html; charset=utf-8">
    <title>{{title}}</title>
  </head>
  <body>
    {{{body}}}
  </body>
</html>
<!-- app/views/index.html -->
<h1>{{title}}</h1>

View Partials

To Be Updated

Matador looks for view partials in a folder named partials in the views directory: app/views/partials/

// app/controllers/HomeController.js
module.exports = function (app, config) {
  return app.controllers.Base.extend()
  .methods({
    index: function (req, res) {
      this.render(res, 'index', {
          user: {
              first: "John"
            , last: "Smith"
          }
        , todo: [{ name: 'dishes', id: 0 }, { name: 'mow lawn', id: 1 }]
      })
    }
  })
}
<!-- app/views/partials/fullname.html -->
{{first}} {{last}}
<!-- app/views/partials/tasks.html -->
<ul>
  {{#todo}}
  <li>{{name}}</li>
  {{/todo}}
</ul>
<!-- app/views/index.html -->
<h1>Hello {{#user}}{{> fullname}}{{/user}} welcome to Matador!</h1>
{{> tasks}}

Produces the following HTML:

<h1>Hello John Smith welcome to Matador!</h1>
<ul>
  <li>dishes</li>
  <li>mow lawn</li>
</ul>

Overriding View Partials

Matador allows you to easily override view partials on a per-directory basis. To override a partial create a new folder named 'partials' in the folder your controller is using as its viewFolder. Matador will look first in this folder for partials, if no matching partial exists it will traverse up the directory tree until it finds a matching partial.

// app/controllers/admin/AdminController.js
module.exports = function (app, config) {
  return app.getController('Application', true).extend(function () {
    this.viewFolder = "admin" // we've set the view folder to "admin"
  })
  .methods({
    index: function (req, res) {
      this.render(res, 'index', {
          user: {
              first: "John"
            , last: "Smith"
          }
        , todo: [{ name: 'dishes', id: 0 }, { name: 'mow lawn', id: 1 }]
      })
    }
  })
}
<!-- app/views/admin/partials/tasks.html -->
<!-- This file will override the tasks.html partial found in app/views/partials -->
<ul>
{{#todo}}
<li><a href="/edit/{{id}}">Edit the "{{name}}" task </a> or <a href="/delete/{{id}}">delete it</a></li>
{{/todo}}
</ul>
<!-- app/views/admin/index.html -->
<!-- 'app/views/admin/partials/fullname.html' Does not exist, so 'app/views/partials/fullname.html' will be used -->
<h1>Welcome {{#user}}{{> fullname}}{{/user}} to the Admin Area</h1>
{{> tasks}}

Produces the following HTML:

<h1>Welcome John Smith to the Admin Area</h1>
<ul>
  <li><a href="/edit/0">Edit the "dishes" task</a> or <a href="/delete/0">delete it</a></li>
  <li><a href="/edit/1">Edit the "mow lawn" task</a> or <a href="/delete/1">delete it</a></li>
</ul>

Note: For performance reasons, partials are fetched when the application starts. You must restart your application for changes in partials to be reflected.

Request Filtering

// app/controllers/ApplicationController.js
module.exports = function (app, config) {
  return app.controllers.Base.extend(function () {
    this.addBeforeFilter(this.requireAuth)
    this.addExcludeFilter(['welcome'], this.requireAuth)
  })
  .methods({
    requireAuth: function (callback) {
      if (this.request.cookies.authed) return callback(null)
      this.response.redirect('/welcome')
    }
  , welcome: function () {
      this.render('welcome')
    }
  })
}

Routing

The app/config/routes.js file is where you specify an array of tuples indicating where incoming requests will map to a controller and the appropriate method. If no action is specified, it defaults to 'index' as illustrated below:

module.exports = function (app) {
  return {
    '/': 'Home' // maps to ./HomeController.js => index
  , '/admin': 'Admin.show' // maps to ./admin/AdminController.js => show
  }
}

How can I organize my Models?

By default, Models are thin with just a Base and Application Model in place. You can give them some meat, for example, and embed Mongo Schemas. See the following as a brief illustration:

// 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/myapp')
  })
}

Then create, for example, a UserModel.js that extended it...

module.exports = function (app, config) {
  return app.getModel('Application', true).extend(function () {
    this.DBModel = this.mongoose.model('User', new this.Schema({
        name: { type: String, required: true, trim: true }
      , email: { type: String, required: true, lowercase: true, trim: true }
    }))
  })
  .methods({
    create: function (name, email, callback) {
      var user = new this.DBModel({
          name: name
        , email: email
      })
      user.save(callback)
    }
  , find: function (id, callback) {
      this.DBModel.findById(id, callback)
    }
  })
}

This provides a proper abstraction between controller logic and how your models interact with a database then return data back to controllers.

Take special note that models do not have access to requests or responses, as they rightfully shouldn't.

Model & Controller Inheritance

The inheritance model Matador uses is built with Klass, and is exposed via a global Class variable (not all globals are bad). Class comes in two flavors where by constructors can be set via an initialize method, or a function reference, and by default (in the scaffold), Matador uses the function reference style so that you may benefit from the auto-initialization of super classes, and there is no need to call this.supr() in your constructors.

Valentine

The Valentine module is included as a simple tool giving you type checking, functional iterators, and some other nice utilities that often get used in applications of any size. It is exposed globally as v. It is used liberally in the Matador router, thus feel free to take advantage of its existence as well.

Scaffolding

$ matador controller [name]
$ matador model [name]

Contributing & Development

Questions, pull requests, bug reports are all welcome. Submit them here on Github. When submitting pull requests, please run through the linter to conform to the framework style

$ npm install -d
$ npm run-script lint

Authors

Obviously, Dustin Senos & Dustin Diaz

License

Copyright 2012 Obvious Corporation

Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0