• Stars
    star
    185
  • Rank 208,271 (Top 5 %)
  • Language
    Ruby
  • Created over 16 years ago
  • Updated over 13 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Desert is a component framework for Rails that allows your plugins have a Rails app like directory structure, routes, migrations, and dependencies.

Desert - It doesn’t get any DRYer than this

Desert is a Rails plugin framework that makes it easy to share models, views, controllers, helpers, routes, and migrations across your applications.

With Desert, reusability doesn’t come at the cost of extensibility: it’s trivial to extend the functionality of a plugin - both in your application and in other plugins.

Classes are automatically mixed in with your own or other plugins’ classes. This allows you to make full featured composable components.

Desert is a replacement for Appable Plugins (wiki.pluginaweek.org/Appable_plugins).

Bug/Feature Tracker

Pivotal Tracker: www.pivotaltracker.com/projects/358

Anatomy of a desert plugin

|-- app
|   |-- controllers
|   |   |-- application.rb
|   |   `-- blogs_controller.rb
|   |-- helpers
|   |   |-- application_helper.rb
|   |   `-- blogs_helper.rb
|   |-- models
|   |   `-- user.rb
|   `-- views
|       |-- blogs
|       |-- layouts
|       |   `-- users.html.erb
|       `-- users
|           |-- index.html.erb
|           `-- show.html.erb
|-- db
|   `-- migrate
|       `-- 001_migrate_users_to_001.rb
|-- lib
|   `-- current_user.rb
|-- spec
|   |-- controllers
|   |   `-- blogs_controller_spec.rb
|   |-- fixtures
|   |-- models
|   |-- spec_helper.rb
|   `-- views
|       `-- blogs
`-- vendor
    `-- plugins
        `-- user
            |-- app
            |   |-- controllers
            |   |   `-- users_controller.rb
            |   |-- helpers
            |   |   `-- users_helper.rb
            |   |-- models
            |   |   `-- user.rb
            |   `-- views
            |       `-- users
            |           |-- edit.html.erb
            |           |-- index.html.erb
            |           |-- new.html.erb
            |           `-- show.html.erb
            |-- config
            |   `-- desert_routes.rb
            |-- db
            |   `-- migrate
            |       `-- 001_create_users.rb
            |-- init.rb
            |-- lib
            |   `-- current_user.rb
            |-- spec
            |   |-- controllers
            |   |   `-- user_controller_spec.rb
            |   |-- fixtures
            |   |   `-- users.yml
            |   |-- models
            |   |   `-- user.rb
            |   |-- spec_helper.rb
            |   `-- views
            |       `-- users
            `-- tasks

Installation and Usage

  • Install the gem

    sudo gem install desert
    
  • Require ‘desert’ between ‘boot’ and Rails::Initializer.run in environment.rb

    # File: config/environment.rb
    
    require File.join(File.dirname(__FILE__), 'boot')
    
    require 'desert'
    
    Rails::Initializer.run do |config|
    end
    

NOTE: you may have to require rubygems before requiring desert.

  • Generate your desert plugin

    script/generate desert_plugin my_plugin_app

Manage Plugin Dependencies

By default, Rails loads plugins in alphabetical order, making it tedious to manage dependencies. Desert will automatically load plugins in the proper order when you declare their dependencies like this:

# File: vendor/plugins/blogs/init.rb

require_plugin 'user'
require_plugin 'will_paginate'

Here user and will_paginate will always be loaded before <tt>blogs<tt>. Note that any plugin can be declared as a dependency.

Share Routes

When you share controllers, you’ll want to share their routes too. If you look in your RAILS_ROOT/config/routes.rb file you will notice that the generator added a new line to the top:

map.routes_from_plugin(:my_plugin_app)

In the user plugin:

# File: vendor/plugins/user/config/desert_routes.rb

resource :users

In the blogs plugin:

# File: vendor/plugins/blogs/config/desert_routes.rb

resource :blogs

In the application:

# File: config/desert_routes.rb

ActionController::Routing::Routes.draw do |map|
  map.routes_from_plugin :blogs
  map.routes_from_plugin :user
end

Here the application adds the users resource from the user plugin and the blogs resource from the blogs plugin. Notice that there is no need to call methods on map in the plugin route files, because they are instance eval’d in the map object.

All standard routing methods are available in your plugin’s routes file, such as:

namespace :admin do |admin|
  admin.resources :posts
end

Desert uses a separate table to manage migration version to maintain backwards compatibility with Rails 1.x. Your plugin app’s migration live in your_plugin/db/migrate. To run migrations, follow these steps:

  • Create a new migration in your main app

    script/generate migration migrate_my_plugin_to_045
  • Add the custom ‘migrate_plugin` method

    class MigrateMyPluginTo045 < ActiveRecord::Migration
      def self.up
        migrate_plugin(:my_plugin, 20080530223548)
      end
    
      def self.down
        migrate_plugin(:my_plugin, 0)
      end
    end
    
  • Run your migrations normally

    rake db:migrate
    
    connect "/signup", :controller => "users", :action => "signup"
    

Share Migrations

Sharing models means sharing schema fragments, and that means sharing migrations:

In the user plugin:

vendor/plugins/user/db/migrate/
  001_create_user_table.rb

In the blogs plugin:

vendor/plugins/blogs/db/migrate/
  001_create_user_table.rb
  002_add_became_a_blogger_at_to_user.rb

Here the blogs plugin needs to add a column to the users table. No problem! It just includes a migration in its db/migrate directory, just like a regular Rails application. When the application developer installs the plugin, he migrates the plugin in his own migration:

application_root/db/migrate/009_install_user_and_blogs_plugins.rb

class InstallUserAndBlogsPlugins < ActiveRecord::Migration
  def self.up
    migrate_plugin 'user', 1
    migrate_plugin :blogs, 2
  end

  def self.down
    migrate_plugin 'user', 0
    migrate_plugin :blogs, 0
  end
end

Here the application migrates the user plugin to version 1 and the blogs plugin to version 2. If a subsequent version of the plugin introduces new migrations, the application developer has full control over when to apply them to his schema.

Share Views

To share views, just create templates and partials in the plugin’s app/views directory, just as you would with a Rails application.

application_root/app/views/blogs/index.html.erb

<%= @blog.posts.each do |post| %>
  ...
<% end %>

Customize / extend behavior in each installation

Say you want to create a plugin named acts_as_spiffy. Desert allows Spiffy to have a set of features that can be reused and extended in several projects.

The Spiffy project has a:

  • SpiffyController

  • Spiffy model

  • SpiffyHelper

  • spiffy.html.erb

  • SpiffyLib library class

The Spiffy plugin acts as its own mini Rails application. Here is the directory structure:

RAILS_ROOT/vendor/plugins/spiffy/app/controllers/spiffy_controller.rb
RAILS_ROOT/vendor/plugins/spiffy/app/models/spiffy.rb
RAILS_ROOT/vendor/plugins/spiffy/app/helpers/spiffy_helper.rb
RAILS_ROOT/vendor/plugins/spiffy/app/views/spiffy/spiffy.rhtml
RAILS_ROOT/vendor/plugins/spiffy/lib/spiffy_lib.rb

Now, say there is a Spiffy Store rails application that uses acts_as_spiffy. The Rails app can open up any of the Spiffy classes and override any of the methods.

Say spiffy.rb in the Spiffy plugin is defined as:

class Spiffy < ActiveRecord::Base
  def why?
    "I just am Spiffy"
  end
end

The Spiffy#why method can be overridden in RAILS_ROOT/app/models/spiffy.rb

class Spiffy < ActiveRecord::Base
  def why?
    "I sell Spiffy stuff"
  end
end

Running plugin tests

You can run your plugin tests/specs like so:

rake desert:testspec:plugins PLUGIN=spiffy

Leaving off the PLUGIN environment variable will cause it to run all the test/specs for all installed plugins, which may not be what you want.

Running Desert Specs

To run specs, you need to:

  • Make sure you have the necessary gems installed:

    sudo geminstaller

  • On OSX, you may have to manually install sqlite3-ruby gem

    sudo env ARCHFLAGS=“-arch i386” gem install sqlite3-ruby

  • If sqlite3-ruby fails to compile, install it.

    OSX: sudo port install sqlite3 Debian: sudo aptitude install sqlite sqlite3 libsqlite-dev libsqlite3-dev

  • Install git git.or.cz/

  • Install the dependencies

    rake install_dependencies

  • Run the specs

    rake

Notes on Rails version dependencies

Desert is a library that heavily monkey patches Rails. To ensure that Desert works with multiple versions of Rails, its tests are run against the supported versions of Rails.

To set up the different supported versions of Rails, run

rake install_dependencies

This will clone the Rails git repo and export the supported versions of rails into the respective directories.

rake update_dependencies

will update the clones repo on your machine.

Copyright © 2007-2011 Pivotal Labs. This software is licensed under the MIT License.

More Repositories

1

jelly

a sweet unobtrusive javascript framework for jQuery and Rails
JavaScript
96
star
2

style-guide

A mountable Rails engine for curating and viewing your site's visual elements.
CSS
49
star
3

jasmine-tmbundle

TextMate Bundle for Jasmine JavaScript Specs
Ruby
43
star
4

polonium

Selenium RC with Rails integration and enhanced assertions.
JavaScript
39
star
5

jazz_money

Run your Jasmine specs without launching a browser
Ruby
35
star
6

guiderails

Ruby
25
star
7

wschef

A project to set up Pivotal's OS X workstations using Chef
Vim Script
23
star
8

performatron

A rails performance benchmarking system
Ruby
22
star
9

paddock

Paddock is an environment-based feature switch system.
Ruby
20
star
10

screw-unit-server

Server and helpers for your Screw Unit tests.
JavaScript
20
star
11

webrat-rspec-rails

Webrat for rspec-rails
Ruby
12
star
12

apdex

Calculate apdex scores from an Apache or Nginx log
Ruby
12
star
13

lsof

Lsof Ruby Gem
Ruby
11
star
14

jasmine-webos

JavaScript BDD for Palm webOS
JavaScript
10
star
15

js-spec-server

The JSSpec client library (http://code.google.com/p/jsspec/) plus a convenient ruby server.
JavaScript
9
star
16

bookmark_fu

Create bookmarks in popular social bookmarking sites.
Ruby
7
star
17

fitnesse-ruby

The fitnesse server packaged as a convenient gem.
Ruby
7
star
18

ci_cookbook

This is an experimental cookbook for configuring a CI machine
Ruby
6
star
19

minimalenium

Exploring TSTTCPW to run Selenium tests under Rails
Ruby
6
star
20

js-test-core

The JsTestCore library is the core javascript test server library used by several JS Test server libraries.
Ruby
6
star
21

thin-rest

A lightweight & fast restful resource layer built on top of Thin.
Ruby
6
star
22

desert_assets

Desert Assets is a meta-plugin for Desert and enables your plugin to provide javascript, css and images.
Ruby
6
star
23

js-test-server

A convenient server for javascript test/spec frameworks.
Ruby
5
star
24

Pivotal-Android-Tabs

A simple Android app with example implementations of Android tabs
Java
5
star
25

execwar

Executable war file created with jruby, runnable with 'java -jar execwar.war'
Ruby
3
star
26

funkytown

This plugin is designed to let you use Selenium RC to write Selenium tests in Ruby, using a simple series of Rake tasks
Ruby
3
star
27

cheques

Ruby
2
star
28

theboard

See your CI Status from your WebOS device
JavaScript
2
star
29

opscode-ey-cloud-recipes

Ruby
2
star
30

clock

A simple wrapper for Ruby's Time object to provide some more control in testing
Ruby
1
star
31

addLoginItem

Adds Login Item to user's startup
Roff
1
star
32

default-url-options-for-mailers

Default or infer the :protocol, :host, and :port values for ActionMailer
Ruby
1
star
33

CocosConCarne

Testing stubs for writing cocos2d specs
1
star
34

django-style-guide

Python
1
star