aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Gunderloy <MikeG1@larkfarm.com>2008-10-12 20:59:16 -0500
committerKarel Minarik <karmi@karmi.cz>2008-10-14 10:20:13 +0200
commit0aeb2dcf13ee72a14ee5671e97252d78fd35e76b (patch)
tree343169a30581c8d483de7232bc6e9f2f62c29c56
parent5ba2fdf0472b91d944deb373c727b748a44bb2e5 (diff)
downloadrails-0aeb2dcf13ee72a14ee5671e97252d78fd35e76b.tar.gz
rails-0aeb2dcf13ee72a14ee5671e97252d78fd35e76b.tar.bz2
rails-0aeb2dcf13ee72a14ee5671e97252d78fd35e76b.zip
Edits and rewrites (work in progress)
-rw-r--r--railties/doc/guides/getting_started_with_rails/getting_started_with_rails.txt373
1 files changed, 198 insertions, 175 deletions
diff --git a/railties/doc/guides/getting_started_with_rails/getting_started_with_rails.txt b/railties/doc/guides/getting_started_with_rails/getting_started_with_rails.txt
index 3259ef8a45..fa6f398dfd 100644
--- a/railties/doc/guides/getting_started_with_rails/getting_started_with_rails.txt
+++ b/railties/doc/guides/getting_started_with_rails/getting_started_with_rails.txt
@@ -4,114 +4,161 @@ Getting Started With Rails
This guide covers getting up and running with Ruby on Rails. After reading it, you should be familiar with:
* Installing Rails, creating a new Rails application, and connecting your application to a database
-* Understanding the purpose of each folder in the Rails structure
-* Creating a scaffold, and explain what it is creating and why you need each element
-* The basics of model, view, and controller interaction
-* The basics of HTTP and RESTful design
+* The general layout of a Rails application
+* The basic principles of MVC (Model, View Controller) and RESTful design
+* How to quickly generate the starting pieces of a Rails application.
-== How to use this guide
-This guide is designed for beginners who want to get started with a Rails application from scratch. It assumes that you have no prior experience using the framework. However, it is highly recommended that you *familiarize yourself with Ruby before diving into Rails*. Rails isn't going to magically revolutionize the way you write web applications if you have no experience with the language it uses.
+== This Guide Assumes
+
+This guide is designed for beginners who want to get started with a Rails application from scratch. It does not assume that you have any prior experience with Rails. However, to get the most out of it, you need to have some prerequisites installed:
+
+* The link:http://www.ruby-lang.org/en/downloads/[Ruby] language
+* The link:http://rubyforge.org/frs/?group_id=126[RubyGems] packaging system
+* A working installation of link:http://www.sqlite.org/[SQLite] (preferred), link:http://www.mysql.com/[MySQL], or link:http://www.postgresql.org/[PostgreSQL]
+
+It is highly recommended that you *familiarize yourself with Ruby before diving into Rails*. You will find it much easier to follow what's going on with a Rails application if you understand basic Ruby syntax. Rails isn't going to magically revolutionize the way you write web applications if you have no experience with the language it uses.
== What is Rails?
-Rails is a web development framework written in the Ruby language. It is designed to make programming web applications easier by making several assumptions about what every developer needs to get started. It allows you to write less code while accomplishing more than other languages and frameworks.
-== Installing Rails
+Rails is a web development framework written in the Ruby language. It is designed to make programming web applications easier by making several assumptions about what every developer needs to get started. It allows you to write less code while accomplishing more than many other languages and frameworks. Longtime Rails developers also report that it makes web application development more fun.
+
+Rails is _opinionated software_. That is, it assumes that there is a best way to do things, and it's designed to encourage that best way - and in some cases discourage alternatives. If you learn "The Rails Way" you'll probably discover a tremendous increase in productivity. If you persist in bringing old habits from other languages to your Rails development, and trying to use patterns you learned elsewhere, you may have a less happy experience.
+
+The Rails philosophy includes several guiding principles:
+
+* DRY - "Don't Repeat Yourself" - suggests that writing the same code over and over again is a bad thing.
+* Convention Over Configuration - means that Rails makes assumptions about what you want to do and how you're going to do it, rather than letting you tweak every little thing through endless configuration files.
+* REST is the best pattern for web applications - organizing your application around resources and standard HTTP verbs is the fastest way to go.
+
+=== Models, Views, and Controllers
+Rails is organized around the Model, View, Controller architecture, usually just called MVC. MVC benefits include:
+
+* Isolation of business logic from the user interface
+* Ease of keeping code DRY
+* Making it clear where different types of code belong for easier maintenance
+
+==== Models
+
+A model represents the information (data) of the application and the rules to manipulate that data. In the case of Rails, models are primarily used for managing the rules of interaction with a corresponding database table. In most cases, one table in your database will correspond to one model in your application. The bulk of your application's business logic will be concentrated in the models.
+
+==== Views
+
+Views represent the user interface of your application. In Rails, views are often HTML files with embedded Ruby code that performs tasks related solely to the presentation of the data. Views handle the job of providing data to the web browser or other tool that is used to make requests from your application.
+
+==== Controllers
+
+Controllers provide the "glue" between models and views. In Rails, controllers are responsible for processing the incoming requests from the web browser, interrogating the models for data, and passing that data on to the views for presentation.
+
+=== REST
+
+The foundation of RESTful routing is generally considered to be Roy Fielding's doctoral thesis, link:http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm[Architectural Styles and the Design of Network-based Software Architectures]. Fortunately, you need not read this entire document to understand how REST works in Rails. REST, an acronym for Representational State Transfer, boils down to two main principles for our purposes:
+
+* Using resource identifiers (which, for the purposes of discussion, you can think of as URLs) to represent resources
+* Transferring representations of the state of that resource between system components.
+
+For example, to a Rails application a request such as this:
-`gem install rails`
++DELETE /photos/17+
-== Create a new Rails project
+would be understood to refer to a photo resource with the ID of 17, and to indicate a desired action - deleting that resource. REST is a natural style for the architecture of web applications, and Rails makes it even more natural by using conventions to shield you from some of the RESTful complexities.
-We're going to create a Rails project called "blog", which is the project that we will build off of for this guide.
+== Creating a New Rails Project
-From your terminal, type:
+If you follow this guide, you'll create a Rails project called +blog+, a (very) simple weblog. Before you can start building the application, you need to make sure that you have Rails itself installed.
-`rails blog`
+=== Installing Rails
-This will create a folder in your working directory called "blog". Open up that folder and have a look at it. For the majority of this tutorial, we will live in the app/ folder, but here's a basic rundown on the function of each folder in a Rails app:
+In most cases, the easiest way to install Rails is to take advantage of RubyGems:
+
+[source, shell]
+-------------------------------------------------------
+gem install rails
+-------------------------------------------------------
+
+NOTE: There are some special circumstances in which you might want to use an alternate installation strategy:
+
+* If you're working on Windows, you may find it easier to install link:http://instantrails.rubyforge.org/wiki/wiki.pl[Instant Rails]. Be aware, though, that Instant Rails releases tend to lag seriously behind the actual Rails version. Also, you will find that Rails development on Windows is overall less pleasant than on other operating systems. If at all possible, we suggest that you install a Linux virtual machine and use that for Rails development, instead of using Windows.
+* If you want to keep up with cutting-edge changes to Rails, you'll want to clone the link:http://github.com/rails/rails/tree/master[Rails source code] from github. This is not recommended as an option for beginners, though.
+
+=== Creating the Blog Application
+
+Open a terminal, navigate to a folder where you have rights to create files, and type:
+
+[source, shell]
+-------------------------------------------------------
+rails blog
+-------------------------------------------------------
+
+This will create a Rails application that uses a SQLite database for data storage. If you prefer to use MySQL, run this command instead:
+
+[source, shell]
+-------------------------------------------------------
+rails blog -d mysql
+-------------------------------------------------------
+
+And if you're using PostgreSQL for data storage, run this command:
+
+[source, shell]
+-------------------------------------------------------
+rails blog -d postgresql
+-------------------------------------------------------
+
+In any case, Rails will create a folder in your working directory called +blog+. Open up that folder and explore its contents. Most of the work in this tutorial will happen in the +app/+ folder, but here's a basic rundown on the function of each folder that Rails creates in a new application by default:
[grid="all"]
`-----------`-----------------------------------------------------------------------------------------------------------------------------
File/Folder Purpose
------------------------------------------------------------------------------------------------------------------------------------------
-README This is a brief instruction manual for your application. Use it to tell others what it does, how to set it up, etc.
-Rakefile
-app/ Contains the controllers, models, and views for your application. We'll focus on the app folder in this guide
-config/ Configure your application's runtime rules, routes, database, etc.
-db/ Shows your current database schema, as well as the database migrations (we'll get into migrations shortly)
-doc/ In-depth documentation for your application
-lib/ Extended modules for your application (not covered in this guide)
-log/ Application log files
-public/ The only folder seen to the world as-is. This is where your images, javascript, stylesheets (CSS), and other static files go
-script/ Scripts provided by Rails to do recurring tasks, benchmarking, plugin installation, starting the console or the web server
-test/ Unit tests, fixtures, etc. (not covered in this guide)
+README This is a brief instruction manual for your application. Use it to tell others what your application does, how to set it up, and so on.
+Rakefile This file contains batch jobs that can be run from the terminal.
+app/ Contains the controllers, models, and views for your application. You'll focus on this folder for the remainder of this guide.
+config/ Configure your application's runtime rules, routes, database, and more.
+db/ Shows your current database schema, as well as the database migrations. You'll learn about migrations shortly.
+doc/ In-depth documentation for your application.
+lib/ Extended modules for your application (not covered in this guide).
+log/ Application log files.
+public/ The only folder seen to the world as-is. This is where your images, javascript, stylesheets (CSS), and other static files go.
+script/ Scripts provided by Rails to do recurring tasks, such as benchmarking, plugin installation, and starting the console or the web server.
+test/ Unit tests, fixtures, and other test apparatus. These are covered in link:../testing_rails_applications/testing_rails_applications.html[Testing Rails Applications]
tmp/ Temporary files
-vendor/ Plugins folder
+vendor/ The Rails source code (if you install it into your project) and plugins containing additional prepackaged functionality.
-------------------------------------------------------------------------------------------------------------------------------------------
-=== Configure SQLite Database
+=== Configuring a SQLite Database
+
+Rails comes with built-in support for SQLite, which is a lightweight flat-file based database application. While a busy production environment may overload SQLite, it works well for development and testing. Rails defaults to using a SQLite database when creating a new project, but you can always change it later.
+
+If you open the file +config/database.yml+ you'll see a default database configuration using SQLite. The file contains sections for three different environments in which Rails can run by default:
-Rails comes with built-in support for SQLite, which is a lightweight flat-file based database application. While it is not designed for a production environment, it works well for development and testing. Rails defaults to SQLite as the database adapter when creating a new project, but you can always change it later.
+* The +development+ environment is used on your development computer as you interact manually with the application
+* The +test+ environment is used to run automated tests
+* The +production+ environment is used when you deploy your application for the world to use.
-Open up +config/database.yml+ and you'll see the following:
+Here's the section of the configuration file with connection information for the development environment:
---------------------------------------------------------------------
-# SQLite version 3.x
-# gem install sqlite3-ruby (not necessary on OS X Leopard)
+[source, ruby]
+-------------------------------------------------------
development:
adapter: sqlite3
database: db/development.sqlite3
timeout: 5000
+-------------------------------------------------------
-# Warning: The database defined as "test" will be erased and
-# re-generated from your development database when you run "rake".
-# Do not set this db to the same as development or production.
-test:
- adapter: sqlite3
- database: db/test.sqlite3
- timeout: 5000
-
-production:
- adapter: sqlite3
- database: db/production.sqlite3
- timeout: 5000
---------------------------------------------------------------------
+If you don't have any database set up, SQLite is the easiest to get installed. If you're on OS X 10.5 or greater on a Mac, you already have it. Otherwise, you can install it using RubyGems:
If you're not running OS X 10.5 or greater, you'll need to install the SQLite gem. Similar to installing Rails you just need to run:
-`gem install sqlite3-ruby`
-
-Because we're using SQLite, there's really nothing else you need to do to setup your database!
-
-=== Configure MySQL Database
-
-.MySQL Tip
-*******************************
-If you want to skip directly to using MySQL on your development machine, typing the following will get you setup with a MySQL configuration file that assumes MySQL is running locally and that the root password is blank:
-
-`rails blog -d mysql`
+[source, shell]
+-------------------------------------------------------
+gem install sqlite3-ruby
+-------------------------------------------------------
-You'll need to make sure you have MySQL up and running on your system with the correct permissions. MySQL installation and configuration is outside the scope of this document.
-*******************************
+=== Configuring a MySQL Database
-If you choose to use MySQL, your +config/database.yml+ will look a little different:
+If you choose to use MySQL, your +config/database.yml+ will look a little different. Here's the development section:
---------------------------------------------------------------------
-# MySQL. Versions 4.1 and 5.0 are recommended.
-#
-# Install the MySQL driver:
-# gem install mysql
-# On Mac OS X:
-# sudo gem install mysql -- --with-mysql-dir=/usr/local/mysql
-# On Mac OS X Leopard:
-# sudo env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
-# This sets the ARCHFLAGS environment variable to your native architecture
-# On Windows:
-# gem install mysql
-# Choose the win32 build.
-# Install MySQL and put its /bin directory on your path.
-#
-# And be sure to use new-style password hashing:
-# http://dev.mysql.com/doc/refman/5.0/en/old-client.html
+[source, ruby]
+-------------------------------------------------------
development:
adapter: mysql
encoding: utf8
@@ -119,62 +166,34 @@ development:
username: root
password:
socket: /tmp/mysql.sock
+-------------------------------------------------------
+If your development computer's MySQL installation includes a root user with an empty password, this configuration should work for you. Otherwise, change the username and password in the +development+ section as appropriate.
-# Warning: The database defined as "test" will be erased and
-# re-generated from your development database when you run "rake".
-# Do not set this db to the same as development or production.
-test:
- adapter: mysql
- encoding: utf8
- database: blog_test
- username: root
- password:
- socket: /tmp/mysql.sock
-
-production:
- adapter: mysql
- encoding: utf8
- database: blog_production
- username: root
- password:
- socket: /tmp/mysql.sock
-----------------------------------------------------------------------
-
-== Starting the web server
-Rails comes bundled with the lightweight Webrick web server, which (like SQLite) works great in development mode, but is not designed for a production environment. If you install Mongrel with `gem install mongrel`, Rails will use the Mongrel web server as the default instead (recommended).
-*******************
-If you're interested in alternative web servers for development and/or production, check out mod_rails (a.k.a Passenger)
-*******************
-Rails lets you run in development, test, and production environments (you can also add an unlimited number of additional environments if necessary). In this guide, we're going to work with the development environment only, which is the default when starting the server. From the root of your application folder, simply type the following to startup the web server:
-
-`./script/server`
+=== Configuring a PostgreSQL Database
-This will start a process that allows you to connect to your application via a web browser on port 3000. Open up a browser to +http://localhost:3000/+
+If you choose to use PostgreSQL, your +config/database.yml+ will be customized to use PostgreSQL databases:
-You can hit Ctrl+C anytime from the terminal to stop the web server.
-
-You should see the "Welcome Aboard" default Rails screen, and can click on the "About your application's environment" link to see a brief summary of your current configuration. If you've gotten this far, you're riding rails! Let's dive into the code!
-
-== Models, Views, and Controllers
-Rails uses Model, View, Controller (MVC) architecture because it isolates business logic from the user interface, ensuring that changes to a template will not affect the underlying code that makes it function. It also helps keep your code clean and DRY (Don't Repeat Yourself!) by making it perfectly clear where different types of code belong.
-
-=== The Model
-The model represents the information (data) of the application and the rules to manipulate that data. In the case of Rails, models are primarily used for managing the rules of interaction with a corresponding database table. Assume that for every table in your database, you will have a corresponding model (not necessarily the other way around, but that's beyond the scope of this guide).
+[source, ruby]
+-------------------------------------------------------
+development:
+ adapter: postgresql
+ encoding: unicode
+ database: blog_development
+ username: blog
+ password:
+-------------------------------------------------------
-Models in Rails use a singular name, and their corresponding database tables use a plural name. In the case of our "Blog" application, we're going to need a table for our blog posts. Because we're generating a model, we want to use the singular name:
+Change the username and password in the +development+ section as appropriate.
-`./script/generate model Post`
+== Getting Up and Running Quickly With Scaffolding
-You'll see that this generates several files, we're going to focus on two. First, let's take a look at +app/models/post.rb+
+Whenever you are dealing with a resource and you know you'll need a way to manage that resource in your application, you can start by generating a scaffold. The reason that this guide did not start with generating the scaffold is because it is not all that useful once you are using Rails on a regular basis. For our blog, we want a "Post" resource, so let's generate that now:
--------------------------------
-class Post < ActiveRecord::Base
-end
--------------------------------
+`./script/generate scaffold Post name:string title:string content:text`
-This is what each model you create will look like by default. Here Rails is making the assumption that your Post model will be tied to a database, because it is telling the Post class to descend from the ActiveRecord::Base class, which is where all the database magic happens. Let's leave the model alone for now and move onto migrations.
+This generates the model, controller, migration, views, tests, and routes for this resource. It also populates these files with default data to get started.
-==== Migrations
+=== Migrations
Database migrations make it simple to add/remove/modify tables, columns, and indexes while allowing you to roll back or forward between states with ease.
Have a look at +db/migrate/2008XXXXXXXXXX_create_posts.rb+ (Yours will have numbers specific to the time that the file was generated), which was generated when creating our Post model:
@@ -226,51 +245,6 @@ This command will always run any migrations that have not yet been run.
Rails is very smart, it knows that if you have a model "Person," the database table should be called "people". If you have a model "Company", the database table will be called "companies". There are a few circumstances where it will not know the correct singular and plural of a model name, but you should have no problem with this as long as you are using common English words. Fixing these rare circumstances is beyond the scope of this guide.
**************************************************************************************************************
-=== The Controller
-The controller communicates input from the user (the view) to the model.
-
-==== RESTful Design
-The REST idea will likely take some time to wrap your brain around if you're new to the concept. But know the following:
-
-* It is best to keep your controllers RESTful at all times if possible
-* Resources must be defined in +config/routes.rb+ in order for the RESTful architecture to work properly, so let's add that now:
-
---------------------
-map.resources :posts
---------------------
-
-* The seven actions that are automatically part of the RESTful design in Rails are +index+, +show+, +new+, +create+, +edit+, +update+, and +destroy+.
-
-Let's generate a controller:
-
-`./script/generate controller Posts`
-
-Open up the controller that it generates in +app/controllers/posts_controller.rb+. It should look like:
-
----------------------------------------------
-class PostsController < ApplicationController
-end
----------------------------------------------
-
-Because of the +map.resources :posts+ line in your +config/routes.rb+ file, this controller is ready to take on all seven actions listed above. But we're going to need some logic in this controller in order to interact with the model, and we're going to need to generate our view files so the user can interact with your application from their browser.
-
-We're going to use the scaffold generator to create all the files and basic logic to make this work, now that you know how to generate models and controllers manually.
-
-To do that, let's completely start over. Back out of your Rails project folder, and *remove it completely* (`rm -rf blog`).
-Create the project again and enter the directory by running the commands:
-
-`rails blog`
-
-`cd blog`
-
-
-=== Rails Scaffold
-Whenever you are dealing with a resource and you know you'll need a way to manage that resource in your application, you can start by generating a scaffold. The reason that this guide did not start with generating the scaffold is because it is not all that useful once you are using Rails on a regular basis. For our blog, we want a "Post" resource, so let's generate that now:
-
-`./script/generate scaffold Post name:string title:string content:text`
-
-This generates the model, controller, migration, views, tests, and routes for this resource. It also populates these files with default data to get started.
-
First, let's make sure our database is up to date by running `rake db:migrate`. That may generate an error if your database still has the tables from our earlier migration. In this case, let's completely reset the database and run all migrations by running `rake db:reset`.
Start up the web server with `./script/server` and point your browser to `http://localhost:3000/posts`.
@@ -279,7 +253,7 @@ Here you'll see an example of the instant gratification of Rails where you can c
Now let's see how all this works. Open up `app/controllers/posts_controller.rb`, and you'll see this time it is filled with code.
-==== Index
+=== Index
Let's take a look at the `index` action:
@@ -298,7 +272,7 @@ In this action, we're setting the `@posts` instance variable to a hash of all po
The `respond_to` block handles both HTML and XML calls to this action. If we call `http://localhost:3000/posts.xml`, we'll see all our posts in XML format. The HTML format looks for our corresponding view in `app/views/posts/index.html.erb`. You can add any number of formats to this block to allow actions to be processed with different file types.
-==== Show
+=== Show
Back in your browser, click on the "New post" link and create your first post if you haven't done so already. Return back to the index, and you'll see the details of your post listed, along with three actions to the right of the post: `show`, `edit`, and `destroy`. Click the `show` link, which will bring you to the URL `http://localhost:3000/posts/1`. Now let's look at the `show` action in `app/controllers/posts_controller.rb`:
@@ -315,7 +289,7 @@ end
This time, we're setting `@post` to a single record in the database that is searched for by its `id`, which is provided to the controller by the "1" in `http://localhost:3000/posts/1`. The `show` action is ready to handle HTML or XML with the `respond_to` block: XML can be accessed at: `http://localhost:3000/posts/1.xml`.
-==== New & Create
+=== New & Create
In your controller, you'll see the `new` and `create` actions, which are used together to create a new record. Our `new` action simply instantiates a new Post object without any parameters:
@@ -354,18 +328,67 @@ def create
end
---------------------------------------
-==== Edit & Update
+=== Edit & Update
For the `edit`, `update`, and `destroy` actions, we will use the same `@post = Post.find(params[:id])` to find the appropriate record.
-==== Destroy
+=== Destroy
Description of the destroy action
-=== The View
-The view is where you put all the code that gets seen by the user: divs, tables, text, checkboxes, etc. Think of the view as the home of your HTML. If done correctly, there should be no business logic in the view.
+== Starting the web server
+Rails comes bundled with the lightweight Webrick web server, which (like SQLite) works great in development mode, but is not designed for a production environment. If you install Mongrel with `gem install mongrel`, Rails will use the Mongrel web server as the default instead (recommended).
+*******************
+If you're interested in alternative web servers for development and/or production, check out mod_rails (a.k.a Passenger)
+*******************
+Rails lets you run in development, test, and production environments (you can also add an unlimited number of additional environments if necessary). In this guide, we're going to work with the development environment only, which is the default when starting the server. From the root of your application folder, simply type the following to startup the web server:
+
+`./script/server`
+
+This will start a process that allows you to connect to your application via a web browser on port 3000. Open up a browser to +http://localhost:3000/+
+
+You can hit Ctrl+C anytime from the terminal to stop the web server.
+
+You should see the "Welcome Aboard" default Rails screen, and can click on the "About your application's environment" link to see a brief summary of your current configuration. If you've gotten this far, you're riding rails! Let's dive into the code!
+
+== Adding a Second Model
+
+== Generating a Model
+
+Models in Rails use a singular name, and their corresponding database tables use a plural name. In the case of our "Blog" application, we're going to need a table for our blog posts. Because we're generating a model, we want to use the singular name:
+
+`./script/generate model Post`
+
+You'll see that this generates several files, we're going to focus on two. First, let's take a look at +app/models/post.rb+
+
+-------------------------------
+class Post < ActiveRecord::Base
+end
+-------------------------------
+
+This is what each model you create will look like by default. Here Rails is making the assumption that your Post model will be tied to a database, because it is telling the Post class to descend from the ActiveRecord::Base class, which is where all the database magic happens. Let's leave the model alone for now and move onto migrations.
+
+=== Associating Models
+
+=== Generating a Controller
+
+=== Building Views
+
+== What's Next?
+
+Now that you've seen your first Rails application, you should feel free to update it and experiment on your own. But you don't have to do everything without help. As you need assistance getting up and running with Rails, feel free to consult these support resources:
+
+* The [http://manuals.rubyonrails.org/]Ruby On Rails guides
+* The link:http://groups.google.com/group/rubyonrails-talk[Ruby on Rails mailing list]
+* The #rubyonrails channel on irc.freenode.net
+* The link:http://wiki.rubyonrails.org/rails[Rails wiki]
+
+== Changelog ==
+http://rails.lighthouseapp.com/projects/16213-rails-guides/tickets/2[Lighthouse ticket]
+* October 12, 2008: More detail, rearrangement, editing by link:../authors.html#mgunderloy[Mike Gunderloy] (not yet approved for publication)
+* September 8, 2008: initial version by James Miller (not yet approved for publication)