aboutsummaryrefslogtreecommitdiffstats
path: root/railties/doc/guides/source/creating_plugins
diff options
context:
space:
mode:
authorJeff Dean <jeff@zilkey.com>2008-11-16 20:30:42 -0500
committerJeff Dean <jeff@zilkey.com>2008-11-16 20:30:42 -0500
commit097b4678f6d52e86a9d46ba6c862e6eb6ef7bbdd (patch)
treea7cdd348247eaf32016d37b4d4596054e17353ee /railties/doc/guides/source/creating_plugins
parentb58d0a944726f26d48d44e7b002e0b0bad32fe85 (diff)
downloadrails-097b4678f6d52e86a9d46ba6c862e6eb6ef7bbdd.tar.gz
rails-097b4678f6d52e86a9d46ba6c862e6eb6ef7bbdd.tar.bz2
rails-097b4678f6d52e86a9d46ba6c862e6eb6ef7bbdd.zip
Plugin Guide: added section on migrations, updated generator section, tightened up spacing of P's inside LI's
Diffstat (limited to 'railties/doc/guides/source/creating_plugins')
-rw-r--r--railties/doc/guides/source/creating_plugins/acts_as_yaffle.txt2
-rw-r--r--railties/doc/guides/source/creating_plugins/appendix.txt73
-rw-r--r--railties/doc/guides/source/creating_plugins/controllers.txt2
-rw-r--r--railties/doc/guides/source/creating_plugins/gem.txt2
-rw-r--r--railties/doc/guides/source/creating_plugins/generator_commands.txt140
-rw-r--r--railties/doc/guides/source/creating_plugins/generator_method.txt89
-rw-r--r--railties/doc/guides/source/creating_plugins/generators.txt103
-rw-r--r--railties/doc/guides/source/creating_plugins/helpers.txt2
-rw-r--r--railties/doc/guides/source/creating_plugins/index.txt16
-rw-r--r--railties/doc/guides/source/creating_plugins/migration_generator.txt156
-rw-r--r--railties/doc/guides/source/creating_plugins/migrations.txt209
-rw-r--r--railties/doc/guides/source/creating_plugins/models.txt2
-rw-r--r--railties/doc/guides/source/creating_plugins/routes.txt (renamed from railties/doc/guides/source/creating_plugins/custom_route.txt)2
-rw-r--r--railties/doc/guides/source/creating_plugins/setup.txt64
-rw-r--r--railties/doc/guides/source/creating_plugins/tests.txt (renamed from railties/doc/guides/source/creating_plugins/test_setup.txt)67
15 files changed, 577 insertions, 352 deletions
diff --git a/railties/doc/guides/source/creating_plugins/acts_as_yaffle.txt b/railties/doc/guides/source/creating_plugins/acts_as_yaffle.txt
index de116af7db..674f086e17 100644
--- a/railties/doc/guides/source/creating_plugins/acts_as_yaffle.txt
+++ b/railties/doc/guides/source/creating_plugins/acts_as_yaffle.txt
@@ -1,4 +1,4 @@
-== Add an `acts_as_yaffle` method to Active Record ==
+== Add an 'acts_as' method to Active Record ==
A common pattern in plugins is to add a method called 'acts_as_something' to models. In this case, you want to write a method called 'acts_as_yaffle' that adds a 'squawk' method to your models.
diff --git a/railties/doc/guides/source/creating_plugins/appendix.txt b/railties/doc/guides/source/creating_plugins/appendix.txt
index a78890ccd5..d890f861b5 100644
--- a/railties/doc/guides/source/creating_plugins/appendix.txt
+++ b/railties/doc/guides/source/creating_plugins/appendix.txt
@@ -6,41 +6,54 @@
* http://nubyonrails.com/articles/2006/05/09/the-complete-guide-to-rails-plugins-part-ii
* http://github.com/technoweenie/attachment_fu/tree/master
* http://daddy.platte.name/2007/05/rails-plugins-keep-initrb-thin.html
+ * http://www.mbleigh.com/2008/6/11/gemplugins-a-brief-introduction-to-the-future-of-rails-plugins
=== Final plugin directory structure ===
The final plugin should have a directory structure that looks something like this:
------------------------------------------------
- |-- MIT-LICENSE
- |-- README
- |-- Rakefile
- |-- generators
- | `-- yaffle
- | |-- USAGE
- | |-- templates
- | | `-- definition.txt
- | `-- yaffle_generator.rb
- |-- init.rb
- |-- install.rb
- |-- lib
- | |-- acts_as_yaffle.rb
- | |-- commands.rb
- | |-- core_ext.rb
- | |-- routing.rb
- | `-- view_helpers.rb
- |-- tasks
- | `-- yaffle_tasks.rake
- |-- test
- | |-- acts_as_yaffle_test.rb
- | |-- core_ext_test.rb
- | |-- database.yml
- | |-- debug.log
- | |-- routing_test.rb
- | |-- schema.rb
- | |-- test_helper.rb
- | `-- view_helpers_test.rb
- |-- uninstall.rb
- `-- yaffle_plugin.sqlite3.db
+vendor/plugins/yaffle/
+|-- MIT-LICENSE
+|-- README
+|-- Rakefile
+|-- generators
+| `-- yaffle
+| |-- USAGE
+| |-- templates
+| | `-- definition.txt
+| `-- yaffle_generator.rb
+|-- install.rb
+|-- lib
+| |-- app
+| | |-- controllers
+| | | `-- woodpeckers_controller.rb
+| | |-- helpers
+| | | `-- woodpeckers_helper.rb
+| | `-- models
+| | `-- woodpecker.rb
+| |-- yaffle
+| | |-- acts_as_yaffle.rb
+| | |-- commands.rb
+| | `-- core_ext.rb
+| `-- yaffle.rb
+|-- rails
+| `-- init.rb
+|-- tasks
+| `-- yaffle_tasks.rake
+|-- test
+| |-- acts_as_yaffle_test.rb
+| |-- core_ext_test.rb
+| |-- database.yml
+| |-- debug.log
+| |-- generator_test.rb
+| |-- schema.rb
+| |-- test_helper.rb
+| |-- woodpecker_test.rb
+| |-- woodpeckers_controller_test.rb
+| |-- wookpeckers_helper_test.rb
+| |-- yaffle_plugin.sqlite3.db
+| `-- yaffle_test.rb
+`-- uninstall.rb
------------------------------------------------
diff --git a/railties/doc/guides/source/creating_plugins/controllers.txt b/railties/doc/guides/source/creating_plugins/controllers.txt
index ee408adb1d..4f4417b416 100644
--- a/railties/doc/guides/source/creating_plugins/controllers.txt
+++ b/railties/doc/guides/source/creating_plugins/controllers.txt
@@ -1,4 +1,4 @@
-== Add a controller ==
+== Controllers ==
This section describes how to add a controller named 'woodpeckers' to your plugin that will behave the same as a controller in your main app. This is very similar to adding a model.
diff --git a/railties/doc/guides/source/creating_plugins/gem.txt b/railties/doc/guides/source/creating_plugins/gem.txt
index 93f5e0ee89..8a0bbb3bc0 100644
--- a/railties/doc/guides/source/creating_plugins/gem.txt
+++ b/railties/doc/guides/source/creating_plugins/gem.txt
@@ -1 +1,3 @@
+== Gems ==
+
http://www.mbleigh.com/2008/6/11/gemplugins-a-brief-introduction-to-the-future-of-rails-plugins \ No newline at end of file
diff --git a/railties/doc/guides/source/creating_plugins/generator_commands.txt b/railties/doc/guides/source/creating_plugins/generator_commands.txt
new file mode 100644
index 0000000000..5cce81c8bd
--- /dev/null
+++ b/railties/doc/guides/source/creating_plugins/generator_commands.txt
@@ -0,0 +1,140 @@
+== Generator Commands ==
+
+You may have noticed above that you can used one of the built-in rails migration commands `migration_template`. If your plugin needs to add and remove lines of text from existing files you will need to write your own generator methods.
+
+This section describes how you you can create your own commands to add and remove a line of text from 'config/routes.rb'.
+
+To start, add the following test method:
+
+*vendor/plugins/yaffle/test/route_generator_test.rb*
+
+[source, ruby]
+-----------------------------------------------------------
+require File.dirname(__FILE__) + '/test_helper.rb'
+require 'rails_generator'
+require 'rails_generator/scripts/generate'
+require 'rails_generator/scripts/destroy'
+
+class RouteGeneratorTest < Test::Unit::TestCase
+
+ def fake_rails_root
+ File.join(File.dirname(__FILE__), "rails_root")
+ end
+
+ def routes_path
+ File.join(fake_rails_root, "config", "routes.rb")
+ end
+
+ def setup
+ FileUtils.mkdir_p(File.join(fake_rails_root, "config"))
+ end
+
+ def teardown
+ FileUtils.rm_r(fake_rails_root)
+ end
+
+ def test_generates_route
+ content = <<-END
+ ActionController::Routing::Routes.draw do |map|
+ map.connect ':controller/:action/:id'
+ map.connect ':controller/:action/:id.:format'
+ end
+ END
+ File.open(routes_path, 'wb') {|f| f.write(content) }
+
+ Rails::Generator::Scripts::Generate.new.run(["yaffle_route"], :destination => fake_rails_root)
+ assert_match /map\.yaffle/, File.read(routes_path)
+ end
+
+ def test_destroys_route
+ content = <<-END
+ ActionController::Routing::Routes.draw do |map|
+ map.yaffle
+ map.connect ':controller/:action/:id'
+ map.connect ':controller/:action/:id.:format'
+ end
+ END
+ File.open(routes_path, 'wb') {|f| f.write(content) }
+
+ Rails::Generator::Scripts::Destroy.new.run(["yaffle_route"], :destination => fake_rails_root)
+ assert_no_match /map\.yaffle/, File.read(routes_path)
+ end
+end
+-----------------------------------------------------------
+
+Run `rake` to watch the test fail, then make the test pass add the following:
+
+*vendor/plugins/yaffle/lib/yaffle.rb*
+
+[source, ruby]
+-----------------------------------------------------------
+require "yaffle/commands"
+-----------------------------------------------------------
+
+*vendor/plugins/yaffle/lib/yaffle/commands.rb*
+
+[source, ruby]
+-----------------------------------------------------------
+require 'rails_generator'
+require 'rails_generator/commands'
+
+module Yaffle #:nodoc:
+ module Generator #:nodoc:
+ module Commands #:nodoc:
+ module Create
+ def yaffle_route
+ logger.route "map.yaffle"
+ look_for = 'ActionController::Routing::Routes.draw do |map|'
+ unless options[:pretend]
+ gsub_file('config/routes.rb', /(#{Regexp.escape(look_for)})/mi){|match| "#{match}\n map.yaffle\n"}
+ end
+ end
+ end
+
+ module Destroy
+ def yaffle_route
+ logger.route "map.yaffle"
+ gsub_file 'config/routes.rb', /\n.+?map\.yaffle/mi, ''
+ end
+ end
+
+ module List
+ def yaffle_route
+ end
+ end
+
+ module Update
+ def yaffle_route
+ end
+ end
+ end
+ end
+end
+
+Rails::Generator::Commands::Create.send :include, Yaffle::Generator::Commands::Create
+Rails::Generator::Commands::Destroy.send :include, Yaffle::Generator::Commands::Destroy
+Rails::Generator::Commands::List.send :include, Yaffle::Generator::Commands::List
+Rails::Generator::Commands::Update.send :include, Yaffle::Generator::Commands::Update
+-----------------------------------------------------------
+
+*vendor/plugins/yaffle/generators/yaffle/yaffle_route_generator.rb*
+
+[source, ruby]
+-----------------------------------------------------------
+class YaffleRouteGenerator < Rails::Generator::Base
+ def manifest
+ record do |m|
+ m.yaffle_route
+ end
+ end
+end
+-----------------------------------------------------------
+
+To see this work, type:
+
+-----------------------------------------------------------
+./script/generate yaffle_route
+./script/destroy yaffle_route
+-----------------------------------------------------------
+
+NOTE: If you haven't set up the custom route from above, 'script/destroy' will fail and you'll have to remove it manually. \ No newline at end of file
diff --git a/railties/doc/guides/source/creating_plugins/generator_method.txt b/railties/doc/guides/source/creating_plugins/generator_method.txt
deleted file mode 100644
index 126692f2c4..0000000000
--- a/railties/doc/guides/source/creating_plugins/generator_method.txt
+++ /dev/null
@@ -1,89 +0,0 @@
-== Add a custom generator command ==
-
-You may have noticed above that you can used one of the built-in rails migration commands `migration_template`. If your plugin needs to add and remove lines of text from existing files you will need to write your own generator methods.
-
-This section describes how you you can create your own commands to add and remove a line of text from 'routes.rb'. This example creates a very simple method that adds or removes a text file.
-
-To start, add the following test method:
-
-*vendor/plugins/yaffle/test/generator_test.rb*
-
-[source, ruby]
------------------------------------------------------------
-def test_generates_definition
- Rails::Generator::Scripts::Generate.new.run(["yaffle", "bird"], :destination => fake_rails_root)
- definition = File.read(File.join(fake_rails_root, "definition.txt"))
- assert_match /Yaffle\:/, definition
-end
------------------------------------------------------------
-
-Run `rake` to watch the test fail, then make the test pass add the following:
-
-*vendor/plugins/yaffle/generators/yaffle/templates/definition.txt*
-
------------------------------------------------------------
-Yaffle: A bird
------------------------------------------------------------
-
-*vendor/plugins/yaffle/lib/yaffle.rb*
-
-[source, ruby]
------------------------------------------------------------
-require "yaffle/commands"
------------------------------------------------------------
-
-*vendor/plugins/yaffle/lib/commands.rb*
-
-[source, ruby]
------------------------------------------------------------
-require 'rails_generator'
-require 'rails_generator/commands'
-
-module Yaffle #:nodoc:
- module Generator #:nodoc:
- module Commands #:nodoc:
- module Create
- def yaffle_definition
- file("definition.txt", "definition.txt")
- end
- end
-
- module Destroy
- def yaffle_definition
- file("definition.txt", "definition.txt")
- end
- end
-
- module List
- def yaffle_definition
- file("definition.txt", "definition.txt")
- end
- end
-
- module Update
- def yaffle_definition
- file("definition.txt", "definition.txt")
- end
- end
- end
- end
-end
-
-Rails::Generator::Commands::Create.send :include, Yaffle::Generator::Commands::Create
-Rails::Generator::Commands::Destroy.send :include, Yaffle::Generator::Commands::Destroy
-Rails::Generator::Commands::List.send :include, Yaffle::Generator::Commands::List
-Rails::Generator::Commands::Update.send :include, Yaffle::Generator::Commands::Update
------------------------------------------------------------
-
-Finally, call your new method in the manifest:
-
-*vendor/plugins/yaffle/generators/yaffle/yaffle_generator.rb*
-
-[source, ruby]
------------------------------------------------------------
-class YaffleGenerator < Rails::Generator::NamedBase
- def manifest
- m.yaffle_definition
- end
-end
------------------------------------------------------------
diff --git a/railties/doc/guides/source/creating_plugins/generators.txt b/railties/doc/guides/source/creating_plugins/generators.txt
new file mode 100644
index 0000000000..eb0fbb5ee9
--- /dev/null
+++ b/railties/doc/guides/source/creating_plugins/generators.txt
@@ -0,0 +1,103 @@
+== Generators ==
+
+Many plugins ship with generators. When you created the plugin above, you specified the --with-generator option, so you already have the generator stubs in 'vendor/plugins/yaffle/generators/yaffle'.
+
+Building generators is a complex topic unto itself and this section will cover one small aspect of generators: creating a generator that adds a time-stamped migration.
+
+To add a generator to a plugin:
+
+ * Write a test
+ * Add your instructions to the 'manifest' method of the generator
+ * Add any necessary template files to the templates directory
+ * Update the USAGE file to add helpful documentation for your generator
+
+=== Testing generators ===
+
+Many rails plugin authors do not test their generators, however testing generators is quite simple. A typical generator test does the following:
+
+ * Creates a new fake rails root directory that will serve as destination
+ * Runs the generator
+ * Asserts that the correct files were generated
+ * Removes the fake rails root
+
+This section will describe how to create a simple generator that adds a file. For the generator in this section, the test could look something like this:
+
+*vendor/plugins/yaffle/test/definition_generator_test.rb*
+
+[source, ruby]
+------------------------------------------------------------------
+require File.dirname(__FILE__) + '/test_helper.rb'
+require 'rails_generator'
+require 'rails_generator/scripts/generate'
+
+class DefinitionGeneratorTest < Test::Unit::TestCase
+
+ def fake_rails_root
+ File.join(File.dirname(__FILE__), 'rails_root')
+ end
+
+ def file_list
+ Dir.glob(File.join(fake_rails_root, "*"))
+ end
+
+ def setup
+ FileUtils.mkdir_p(fake_rails_root)
+ @original_files = file_list
+ end
+
+ def teardown
+ FileUtils.rm_r(fake_rails_root)
+ end
+
+ def test_generates_correct_file_name
+ Rails::Generator::Scripts::Generate.new.run(["yaffle_definition"], :destination => fake_rails_root)
+ new_file = (file_list - @original_files).first
+ assert_equal "definition.txt", File.basename(new_file)
+ end
+
+end
+------------------------------------------------------------------
+
+You can run 'rake' from the plugin directory to see this fail. Unless you are doing more advanced generator commands it typically suffices to just test the Generate script, and trust that rails will handle the Destroy and Update commands for you.
+
+To make it pass, create the generator:
+
+*vendor/plugins/yaffle/generators/yaffle_definition/yaffle_definition_generator.rb*
+
+[source, ruby]
+------------------------------------------------------------------
+class YaffleDefinitionGenerator < Rails::Generator::Base
+ def manifest
+ record do |m|
+ m.file "definition.txt", "definition.txt"
+ end
+ end
+end
+------------------------------------------------------------------
+
+=== The USAGE file ===
+
+If you plan to distribute your plugin, developers will expect at least a minimum of documentation. You can add simple documentation to the generator by updating the USAGE file.
+
+Rails ships with several built-in generators. You can see all of the generators available to you by typing the following at the command line:
+
+------------------------------------------------------------------
+./script/generate
+------------------------------------------------------------------
+
+You should see something like this:
+
+------------------------------------------------------------------
+Installed Generators
+ Plugins (vendor/plugins): yaffle_definition
+ Builtin: controller, integration_test, mailer, migration, model, observer, plugin, resource, scaffold, session_migration
+------------------------------------------------------------------
+
+When you run `script/generate yaffle_definition -h` you should see the contents of your 'vendor/plugins/yaffle/generators/yaffle_definition/USAGE'.
+
+For this plugin, update the USAGE file could look like this:
+
+------------------------------------------------------------------
+Description:
+ Adds a file with the definition of a Yaffle to the app's main directory
+------------------------------------------------------------------
diff --git a/railties/doc/guides/source/creating_plugins/helpers.txt b/railties/doc/guides/source/creating_plugins/helpers.txt
index 51b4cebb01..c2273813dd 100644
--- a/railties/doc/guides/source/creating_plugins/helpers.txt
+++ b/railties/doc/guides/source/creating_plugins/helpers.txt
@@ -1,4 +1,4 @@
-== Add a helper ==
+== Helpers ==
This section describes how to add a helper named 'WoodpeckersHelper' to your plugin that will behave the same as a helper in your main app. This is very similar to adding a model and a controller.
diff --git a/railties/doc/guides/source/creating_plugins/index.txt b/railties/doc/guides/source/creating_plugins/index.txt
index 19484e2830..5d10fa4f31 100644
--- a/railties/doc/guides/source/creating_plugins/index.txt
+++ b/railties/doc/guides/source/creating_plugins/index.txt
@@ -29,23 +29,27 @@ This guide describes how to build a test-driven plugin that will:
For the purpose of this guide pretend for a moment that you are an avid bird watcher. Your favorite bird is the Yaffle, and you want to create a plugin that allows other developers to share in the Yaffle goodness. First, you need to get setup for development.
-include::test_setup.txt[]
+include::setup.txt[]
+
+include::tests.txt[]
include::core_ext.txt[]
include::acts_as_yaffle.txt[]
-include::migration_generator.txt[]
-
-include::generator_method.txt[]
-
include::models.txt[]
include::controllers.txt[]
include::helpers.txt[]
-include::custom_route.txt[]
+include::routes.txt[]
+
+include::generators.txt[]
+
+include::generator_commands.txt[]
+
+include::migrations.txt[]
include::odds_and_ends.txt[]
diff --git a/railties/doc/guides/source/creating_plugins/migration_generator.txt b/railties/doc/guides/source/creating_plugins/migration_generator.txt
deleted file mode 100644
index f4fc32481c..0000000000
--- a/railties/doc/guides/source/creating_plugins/migration_generator.txt
+++ /dev/null
@@ -1,156 +0,0 @@
-== Create a generator ==
-
-Many plugins ship with generators. When you created the plugin above, you specified the --with-generator option, so you already have the generator stubs in 'vendor/plugins/yaffle/generators/yaffle'.
-
-Building generators is a complex topic unto itself and this section will cover one small aspect of generators: creating a generator that adds a time-stamped migration.
-
-To create a generator you must:
-
- * Add your instructions to the 'manifest' method of the generator
- * Add any necessary template files to the templates directory
- * Test the generator manually by running various combinations of `script/generate` and `script/destroy`
- * Update the USAGE file to add helpful documentation for your generator
-
-=== Testing generators ===
-
-Many rails plugin authors do not test their generators, however testing generators is quite simple. A typical generator test does the following:
-
- * Creates a new fake rails root directory that will serve as destination
- * Runs the generator forward and backward, making whatever assertions are necessary
- * Removes the fake rails root
-
-For the generator in this section, the test could look something like this:
-
-*vendor/plugins/yaffle/test/yaffle_generator_test.rb*
-
-[source, ruby]
-------------------------------------------------------------------
-require File.dirname(__FILE__) + '/test_helper.rb'
-require 'rails_generator'
-require 'rails_generator/scripts/generate'
-require 'rails_generator/scripts/destroy'
-
-class GeneratorTest < Test::Unit::TestCase
-
- def fake_rails_root
- File.join(File.dirname(__FILE__), 'rails_root')
- end
-
- def file_list
- Dir.glob(File.join(fake_rails_root, "db", "migrate", "*"))
- end
-
- def setup
- FileUtils.mkdir_p(fake_rails_root)
- @original_files = file_list
- end
-
- def teardown
- FileUtils.rm_r(fake_rails_root)
- end
-
- def test_generates_correct_file_name
- Rails::Generator::Scripts::Generate.new.run(["yaffle", "bird"], :destination => fake_rails_root)
- new_file = (file_list - @original_files).first
- assert_match /add_yaffle_fields_to_bird/, new_file
- end
-
-end
-------------------------------------------------------------------
-
-You can run 'rake' from the plugin directory to see this fail. Unless you are doing more advanced generator commands it typically suffices to just test the Generate script, and trust that rails will handle the Destroy and Update commands for you.
-
-=== Adding to the manifest ===
-
-This example will demonstrate how to use one of the built-in generator methods named 'migration_template' to create a migration file. To start, update your generator file to look like this:
-
-*vendor/plugins/yaffle/generators/yaffle/yaffle_generator.rb*
-
-[source, ruby]
-------------------------------------------------------------------
-class YaffleGenerator < Rails::Generator::NamedBase
- def manifest
- record do |m|
- m.migration_template 'migration:migration.rb', "db/migrate", {:assigns => yaffle_local_assigns,
- :migration_file_name => "add_yaffle_fields_to_#{custom_file_name}"
- }
- end
- end
-
- private
- def custom_file_name
- custom_name = class_name.underscore.downcase
- custom_name = custom_name.pluralize if ActiveRecord::Base.pluralize_table_names
- end
-
- def yaffle_local_assigns
- returning(assigns = {}) do
- assigns[:migration_action] = "add"
- assigns[:class_name] = "add_yaffle_fields_to_#{custom_file_name}"
- assigns[:table_name] = custom_file_name
- assigns[:attributes] = [Rails::Generator::GeneratedAttribute.new("last_squawk", "string")]
- end
- end
-end
-------------------------------------------------------------------
-
-The generator creates a new file in 'db/migrate' with a timestamp and an 'add_column' statement. It reuses the built in rails `migration_template` method, and reuses the built-in rails migration template.
-
-It's courteous to check to see if table names are being pluralized whenever you create a generator that needs to be aware of table names. This way people using your generator won't have to manually change the generated files if they've turned pluralization off.
-
-=== Manually test the generator ===
-
-To run the generator, type the following at the command line:
-
-------------------------------------------------------------------
-./script/generate yaffle bird
-------------------------------------------------------------------
-
-and you will see a new file:
-
-*db/migrate/20080529225649_add_yaffle_fields_to_birds.rb*
-
-[source, ruby]
-------------------------------------------------------------------
-class AddYaffleFieldsToBirds < ActiveRecord::Migration
- def self.up
- add_column :birds, :last_squawk, :string
- end
-
- def self.down
- remove_column :birds, :last_squawk
- end
-end
-------------------------------------------------------------------
-
-
-=== The USAGE file ===
-
-Rails ships with several built-in generators. You can see all of the generators available to you by typing the following at the command line:
-
-------------------------------------------------------------------
-script/generate
-------------------------------------------------------------------
-
-You should see something like this:
-
-------------------------------------------------------------------
-Installed Generators
- Plugins (vendor/plugins): yaffle
- Builtin: controller, integration_test, mailer, migration, model, observer, plugin, resource, scaffold, session_migration
-------------------------------------------------------------------
-
-When you run `script/generate yaffle` you should see the contents of your 'vendor/plugins/yaffle/generators/yaffle/USAGE' file.
-
-For this plugin, update the USAGE file looks like this:
-
-------------------------------------------------------------------
-Description:
- Creates a migration that adds yaffle squawk fields to the given model
-
-Example:
- ./script/generate yaffle hickwall
-
- This will create:
- db/migrate/TIMESTAMP_add_yaffle_fields_to_hickwall
-------------------------------------------------------------------
diff --git a/railties/doc/guides/source/creating_plugins/migrations.txt b/railties/doc/guides/source/creating_plugins/migrations.txt
new file mode 100644
index 0000000000..7154f0bc06
--- /dev/null
+++ b/railties/doc/guides/source/creating_plugins/migrations.txt
@@ -0,0 +1,209 @@
+== Migrations ==
+
+If your plugin requires changes to the app's database you will likely want to somehow add migrations. Rails does not include any built-in support for calling migrations from plugins, but you can still make it easy for developers to call migrations from plugins.
+
+If you have a very simple needs, like creating a table that will always have the same name and columns, then you can use a more simple solution, like creating a custom rake task or method. If your migration needs user input to supply table names or other options, you probably want to opt for generating a migration.
+
+Let's say you have the following migration in your plugin:
+
+*vendor/plugins/yaffle/lib/db/migrate/20081116181115_create_birdhouses.rb:*
+
+[source, ruby]
+----------------------------------------------
+class CreateBirdhouses < ActiveRecord::Migration
+ def self.up
+ create_table :birdhouses, :force => true do |t|
+ t.string :name
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :birdhouses
+ end
+end
+----------------------------------------------
+
+Here are a few possibilities for how to allow developers to use your plugin migrations:
+
+=== Create a custom rake task ===
+
+*vendor/plugins/yaffle/lib/db/migrate/20081116181115_create_birdhouses.rb:*
+
+[source, ruby]
+----------------------------------------------
+class CreateBirdhouses < ActiveRecord::Migration
+ def self.up
+ create_table :birdhouses, :force => true do |t|
+ t.string :name
+ t.timestamps
+ end
+ end
+
+ def self.down
+ drop_table :birdhouses
+ end
+end
+----------------------------------------------
+
+
+*vendor/plugins/yaffle/tasks/yaffle.rake:*
+
+[source, ruby]
+----------------------------------------------
+namespace :db do
+ namespace :migrate do
+ desc "Migrate the database through scripts in vendor/plugins/yaffle/lib/db/migrate and update db/schema.rb by invoking db:schema:dump. Target specific version with VERSION=x. Turn off output with VERBOSE=false."
+ task :yaffle => :environment do
+ ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
+ ActiveRecord::Migrator.migrate("vendor/plugins/yaffle/lib/db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
+ end
+ end
+end
+----------------------------------------------
+
+=== Call plugin migrations from regular migrations ===
+
+*vendor/plugins/yaffle/lib/yaffle.rb:*
+
+[source, ruby]
+----------------------------------------------
+Dir.glob(File.join(File.dirname(__FILE__), "db", "migrate", "*")).each do |file|
+ require file
+end
+----------------------------------------------
+
+*db/migrate/20081116181115_create_birdhouses.rb:*
+
+[source, ruby]
+----------------------------------------------
+class CreateBirdhouses < ActiveRecord::Migration
+ def self.up
+ Yaffle::CreateBirdhouses.up
+ end
+
+ def self.down
+ Yaffle::CreateBirdhouses.down
+ end
+end
+----------------------------------------------
+
+NOTE: several plugin frameworks such as Desert and Engines provide more advanced plugin functionality.
+
+== Generating migrations ==
+
+Generating migrations has several advantages over other methods. Namely, you can allow other developers to more easily customize the migration. The flow looks like this:
+
+ * call your script/generate script and pass in whatever options they need
+ * examine the generated migration, adding/removing columns or other options as necessary
+
+This example will demonstrate how to use one of the built-in generator methods named 'migration_template' to create a migration file. Extending the rails migration generator requires a somewhat intimate knowledge of the migration generator internals, so it's best to write a test first:
+
+*vendor/plugins/yaffle/test/yaffle_migration_generator_test.rb*
+
+[source, ruby]
+------------------------------------------------------------------
+require File.dirname(__FILE__) + '/test_helper.rb'
+require 'rails_generator'
+require 'rails_generator/scripts/generate'
+require 'rails_generator/scripts/destroy'
+
+class MigrationGeneratorTest < Test::Unit::TestCase
+
+ def fake_rails_root
+ File.join(File.dirname(__FILE__), 'rails_root')
+ end
+
+ def file_list
+ Dir.glob(File.join(fake_rails_root, "db", "migrate", "*"))
+ end
+
+ def setup
+ FileUtils.mkdir_p(fake_rails_root)
+ @original_files = file_list
+ end
+
+ def teardown
+ FileUtils.rm_r(fake_rails_root)
+ end
+
+ def test_generates_correct_file_name
+ Rails::Generator::Scripts::Generate.new.run(["yaffle", "some_name_nobody_is_likely_to_ever_use_in_a_real_migration"], :destination => fake_rails_root)
+ new_file = (file_list - @original_files).first
+ assert_match /add_yaffle_fields_to_some_name_nobody_is_likely_to_ever_use_in_a_real_migrations/, new_file
+ assert_match /add_column :some_name_nobody_is_likely_to_ever_use_in_a_real_migrations do |t|/, File.read(new_file)
+ end
+
+ def test_pluralizes_properly
+ ActiveRecord::Base.pluralize_table_names = false
+ Rails::Generator::Scripts::Generate.new.run(["yaffle", "some_name_nobody_is_likely_to_ever_use_in_a_real_migration"], :destination => fake_rails_root)
+ new_file = (file_list - @original_files).first
+ assert_match /add_yaffle_fields_to_some_name_nobody_is_likely_to_ever_use_in_a_real_migration/, new_file
+ assert_match /add_column :some_name_nobody_is_likely_to_ever_use_in_a_real_migration do |t|/, File.read(new_file)
+ end
+
+end
+------------------------------------------------------------------
+
+NOTE: the migration generator checks to see if a migation already exists, and it's hard-coded to check the 'db/migrate' directory. As a result, if your test tries to generate a migration that already exists in the app, it will fail. The easy workaround is to make sure that the name you generate in your test is very unlikely to actually appear in the app.
+
+After running the test with 'rake' you can make it pass with:
+
+*vendor/plugins/yaffle/generators/yaffle/yaffle_generator.rb*
+
+[source, ruby]
+------------------------------------------------------------------
+class YaffleGenerator < Rails::Generator::NamedBase
+ def manifest
+ record do |m|
+ m.migration_template 'migration:migration.rb', "db/migrate", {:assigns => yaffle_local_assigns,
+ :migration_file_name => "add_yaffle_fields_to_#{custom_file_name}"
+ }
+ end
+ end
+
+ private
+ def custom_file_name
+ custom_name = class_name.underscore.downcase
+ custom_name = custom_name.pluralize if ActiveRecord::Base.pluralize_table_names
+ end
+
+ def yaffle_local_assigns
+ returning(assigns = {}) do
+ assigns[:migration_action] = "add"
+ assigns[:class_name] = "add_yaffle_fields_to_#{custom_file_name}"
+ assigns[:table_name] = custom_file_name
+ assigns[:attributes] = [Rails::Generator::GeneratedAttribute.new("last_squawk", "string")]
+ end
+ end
+end
+------------------------------------------------------------------
+
+The generator creates a new file in 'db/migrate' with a timestamp and an 'add_column' statement. It reuses the built in rails `migration_template` method, and reuses the built-in rails migration template.
+
+It's courteous to check to see if table names are being pluralized whenever you create a generator that needs to be aware of table names. This way people using your generator won't have to manually change the generated files if they've turned pluralization off.
+
+To run the generator, type the following at the command line:
+
+------------------------------------------------------------------
+./script/generate yaffle_migration bird
+------------------------------------------------------------------
+
+and you will see a new file:
+
+*db/migrate/20080529225649_add_yaffle_fields_to_birds.rb*
+
+[source, ruby]
+------------------------------------------------------------------
+class AddYaffleFieldsToBirds < ActiveRecord::Migration
+ def self.up
+ add_column :birds, :last_squawk, :string
+ end
+
+ def self.down
+ remove_column :birds, :last_squawk
+ end
+end
+------------------------------------------------------------------
+
diff --git a/railties/doc/guides/source/creating_plugins/models.txt b/railties/doc/guides/source/creating_plugins/models.txt
index 458edec80a..dfe11f9c4e 100644
--- a/railties/doc/guides/source/creating_plugins/models.txt
+++ b/railties/doc/guides/source/creating_plugins/models.txt
@@ -1,4 +1,4 @@
-== Add a model ==
+== Models ==
This section describes how to add a model named 'Woodpecker' to your plugin that will behave the same as a model in your main app. When storing models, controllers, views and helpers in your plugin, it's customary to keep them in directories that match the rails directories. For this example, create a file structure like this:
diff --git a/railties/doc/guides/source/creating_plugins/custom_route.txt b/railties/doc/guides/source/creating_plugins/routes.txt
index 1fce902a4e..cdc20e998e 100644
--- a/railties/doc/guides/source/creating_plugins/custom_route.txt
+++ b/railties/doc/guides/source/creating_plugins/routes.txt
@@ -1,4 +1,4 @@
-== Add a Custom Route ==
+== Routes ==
Testing routes in plugins can be complex, especially if the controllers are also in the plugin itself. Jamis Buck showed a great example of this in http://weblog.jamisbuck.org/2006/10/26/monkey-patching-rails-extending-routes-2.
diff --git a/railties/doc/guides/source/creating_plugins/setup.txt b/railties/doc/guides/source/creating_plugins/setup.txt
new file mode 100644
index 0000000000..fcf5b459e6
--- /dev/null
+++ b/railties/doc/guides/source/creating_plugins/setup.txt
@@ -0,0 +1,64 @@
+== Setup ==
+
+=== Create the basic app ===
+
+The examples in this guide require that you have a working rails application. To create a simple rails app execute:
+
+------------------------------------------------
+gem install rails
+rails yaffle_guide
+cd yaffle_guide
+script/generate scaffold bird name:string
+rake db:migrate
+script/server
+------------------------------------------------
+
+Then navigate to http://localhost:3000/birds. Make sure you have a functioning rails app before continuing.
+
+.Editor's note:
+NOTE: The aforementioned instructions will work for sqlite3. For more detailed instructions on how to create a rails app for other databases see the API docs.
+
+
+=== Generate the plugin skeleton ===
+
+Rails ships with a plugin generator which creates a basic plugin skeleton. Pass the plugin name, either 'CamelCased' or 'under_scored', as an argument. Pass `\--with-generator` to add an example generator also.
+
+This creates a plugin in 'vendor/plugins' including an 'init.rb' and 'README' as well as standard 'lib', 'task', and 'test' directories.
+
+Examples:
+----------------------------------------------
+./script/generate plugin yaffle
+./script/generate plugin yaffle --with-generator
+----------------------------------------------
+
+To get more detailed help on the plugin generator, type `./script/generate plugin`.
+
+Later on this guide will describe how to work with generators, so go ahead and generate your plugin with the `\--with-generator` option now:
+
+----------------------------------------------
+./script/generate plugin yaffle --with-generator
+----------------------------------------------
+
+You should see the following output:
+
+----------------------------------------------
+create vendor/plugins/yaffle/lib
+create vendor/plugins/yaffle/tasks
+create vendor/plugins/yaffle/test
+create vendor/plugins/yaffle/README
+create vendor/plugins/yaffle/MIT-LICENSE
+create vendor/plugins/yaffle/Rakefile
+create vendor/plugins/yaffle/init.rb
+create vendor/plugins/yaffle/install.rb
+create vendor/plugins/yaffle/uninstall.rb
+create vendor/plugins/yaffle/lib/yaffle.rb
+create vendor/plugins/yaffle/tasks/yaffle_tasks.rake
+create vendor/plugins/yaffle/test/core_ext_test.rb
+create vendor/plugins/yaffle/generators
+create vendor/plugins/yaffle/generators/yaffle
+create vendor/plugins/yaffle/generators/yaffle/templates
+create vendor/plugins/yaffle/generators/yaffle/yaffle_generator.rb
+create vendor/plugins/yaffle/generators/yaffle/USAGE
+----------------------------------------------
+
+To begin just change one thing - move 'init.rb' to 'rails/init.rb'.
diff --git a/railties/doc/guides/source/creating_plugins/test_setup.txt b/railties/doc/guides/source/creating_plugins/tests.txt
index 64236ff110..ef6dab2f9f 100644
--- a/railties/doc/guides/source/creating_plugins/test_setup.txt
+++ b/railties/doc/guides/source/creating_plugins/tests.txt
@@ -1,69 +1,4 @@
-== Preparation ==
-
-=== Create the basic app ===
-
-The examples in this guide require that you have a working rails application. To create a simple rails app execute:
-
-------------------------------------------------
-gem install rails
-rails yaffle_guide
-cd yaffle_guide
-script/generate scaffold bird name:string
-rake db:migrate
-script/server
-------------------------------------------------
-
-Then navigate to http://localhost:3000/birds. Make sure you have a functioning rails app before continuing.
-
-.Editor's note:
-NOTE: The aforementioned instructions will work for sqlite3. For more detailed instructions on how to create a rails app for other databases see the API docs.
-
-
-=== Generate the plugin skeleton ===
-
-Rails ships with a plugin generator which creates a basic plugin skeleton. Pass the plugin name, either 'CamelCased' or 'under_scored', as an argument. Pass `\--with-generator` to add an example generator also.
-
-This creates a plugin in 'vendor/plugins' including an 'init.rb' and 'README' as well as standard 'lib', 'task', and 'test' directories.
-
-Examples:
-----------------------------------------------
-./script/generate plugin yaffle
-./script/generate plugin yaffle --with-generator
-----------------------------------------------
-
-To get more detailed help on the plugin generator, type `./script/generate plugin`.
-
-Later on this guide will describe how to work with generators, so go ahead and generate your plugin with the `\--with-generator` option now:
-
-----------------------------------------------
-./script/generate plugin yaffle --with-generator
-----------------------------------------------
-
-You should see the following output:
-
-----------------------------------------------
-create vendor/plugins/yaffle/lib
-create vendor/plugins/yaffle/tasks
-create vendor/plugins/yaffle/test
-create vendor/plugins/yaffle/README
-create vendor/plugins/yaffle/MIT-LICENSE
-create vendor/plugins/yaffle/Rakefile
-create vendor/plugins/yaffle/init.rb
-create vendor/plugins/yaffle/install.rb
-create vendor/plugins/yaffle/uninstall.rb
-create vendor/plugins/yaffle/lib/yaffle.rb
-create vendor/plugins/yaffle/tasks/yaffle_tasks.rake
-create vendor/plugins/yaffle/test/core_ext_test.rb
-create vendor/plugins/yaffle/generators
-create vendor/plugins/yaffle/generators/yaffle
-create vendor/plugins/yaffle/generators/yaffle/templates
-create vendor/plugins/yaffle/generators/yaffle/yaffle_generator.rb
-create vendor/plugins/yaffle/generators/yaffle/USAGE
-----------------------------------------------
-
-To begin just change one thing - move 'init.rb' to 'rails/init.rb'.
-
-=== Setup the plugin for testing ===
+== Tests ==
If your plugin interacts with a database, you'll need to setup a database connection. In this guide you will learn how to test your plugin against multiple different database adapters using Active Record. This guide will not cover how to use fixtures in plugin tests.