From 4146efc380255319768031f26e63210fd4158e99 Mon Sep 17 00:00:00 2001 From: Jeff Dean Date: Thu, 13 Nov 2008 23:29:46 -0500 Subject: Plugin guide: update generator guide to include tests --- railties/doc/guides/html/creating_plugins.html | 231 +++++++++++++++++-------- 1 file changed, 162 insertions(+), 69 deletions(-) (limited to 'railties/doc/guides/html/creating_plugins.html') diff --git a/railties/doc/guides/html/creating_plugins.html b/railties/doc/guides/html/creating_plugins.html index 793cd2b7a7..5589971ec5 100644 --- a/railties/doc/guides/html/creating_plugins.html +++ b/railties/doc/guides/html/creating_plugins.html @@ -239,6 +239,17 @@ ul#navMain {
  • Create a migration generator +
  • Add a custom generator command @@ -433,22 +444,22 @@ create vendor/plugins/yaffle/generators/yaffle/yaffle_generator.rb create vendor/plugins/yaffle/generators/yaffle/USAGE

    1.3. Setup the plugin for testing

    -

    In this guide you will learn how to test your plugin against multiple different adapters using Active Record. This guide will not cover how to use fixtures in plugin 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.

    To setup your plugin to allow for easy testing you'll need to add 3 files:

    • -A database.yml file with all of your connection strings. +A database.yml file with all of your connection strings

    • -A schema.rb file with your table definitions. +A schema.rb file with your table definitions

    • -A test helper that sets up the database before your tests. +A test helper method that sets up the database

    @@ -457,11 +468,11 @@ A test helper that sets up the database before your tests.
    sqlite:
       :adapter: sqlite
    -  :dbfile: yaffle_plugin.sqlite.db
    +  :dbfile: vendor/plugins/yaffle/test/yaffle_plugin.sqlite.db
     
     sqlite3:
       :adapter: sqlite3
    -  :dbfile: yaffle_plugin.sqlite3.db
    +  :dbfile: vendor/plugins/yaffle/test/yaffle_plugin.sqlite3.db
     
     postgresql:
       :adapter: postgresql
    @@ -473,8 +484,8 @@ postgresql:
     mysql:
       :adapter: mysql
       :host: localhost
    -  :username: rails
    -  :password:
    +  :username: root
    +  :password: password
       :database: yaffle_plugin_test

    For this guide you'll need 2 tables/models, Hickwalls and Wickwalls, so add the following:

    @@ -509,34 +520,38 @@ ENV['RAILS_ROOT require 'test/unit' require File.expand_path(File.join(ENV['RAILS_ROOT'], 'config/environment.rb')) -config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml')) -ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log") +def load_schema + config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml')) + ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log") -db_adapter = ENV['DB'] + db_adapter = ENV['DB'] -db_adapter ||= - begin - require 'rubygems' - require 'sqlite' - 'sqlite' - rescue MissingSourceFile + # no db passed, try one of these fine config-free DBs before bombing. + db_adapter ||= begin - require 'sqlite3' - 'sqlite3' + require 'rubygems' + require 'sqlite' + 'sqlite' rescue MissingSourceFile + begin + require 'sqlite3' + 'sqlite3' + rescue MissingSourceFile + end end - end -if db_adapter.nil? - raise "No DB Adapter selected. Pass the DB= option to pick one, or install Sqlite or Sqlite3." -end + if db_adapter.nil? + raise "No DB Adapter selected. Pass the DB= option to pick one, or install Sqlite or Sqlite3." + end -ActiveRecord::Base.establish_connection(config[db_adapter]) + ActiveRecord::Base.establish_connection(config[db_adapter]) -load(File.dirname(__FILE__) + "/schema.rb") + load(File.dirname(__FILE__) + "/schema.rb") -require File.dirname(__FILE__) + '/../init.rb' + require File.dirname(__FILE__) + '/../init.rb' +end +

    Now whenever you write a test that requires the database, you can call load_schema.

    1.4. Run the plugin tests

    Once you have these files in place, you can write your first test to ensure that your plugin-testing setup is correct. By default rails generates a file in vendor/plugins/yaffle/test/yaffle_test.rb with a sample test. Replace the contents of that file with:

    vendor/plugins/yaffle/test/yaffle_test.rb:

    @@ -548,6 +563,7 @@ http://www.gnu.org/software/src-highlite -->
    require File.dirname(__FILE__) + '/test_helper.rb'
     
     class YaffleTest < Test::Unit::TestCase
    +  load_schema
     
       class Hickwall < ActiveRecord::Base
       end
    @@ -800,6 +816,8 @@ http://www.gnu.org/software/src-highlite -->
     end
     
     class ActsAsYaffleTest < Test::Unit::TestCase
    +  load_schema
    +
       def test_a_hickwalls_yaffle_text_field_should_be_last_squawk
         assert_equal "last_squawk", Hickwall.yaffle_text_field
       end
    @@ -851,6 +869,8 @@ http://www.gnu.org/software/src-highlite -->
     end
     
     class ActsAsYaffleTest < Test::Unit::TestCase
    +  load_schema
    +
       def test_a_hickwalls_yaffle_text_field_should_be_last_squawk
         assert_equal "last_squawk", Hickwall.yaffle_text_field
       end
    @@ -987,31 +1007,92 @@ http://www.gnu.org/software/src-highlite -->
     
     

    5. Create a migration generator

    -

    When you created the plugin above, you specified the —with-generator option, so you already have the generator stubs in your plugin.

    -

    We'll be relying on the built-in rails generate template for this tutorial. Going into the details of generators is beyond the scope of this tutorial.

    -

    Type:

    -
    -
    -
    script/generate
    -
    -

    You should see the line:

    -
    -
    -
    Plugins (vendor/plugins): yaffle
    -
    -

    When you run script/generate yaffle you should see the contents of your USAGE file. For this plugin, the USAGE file looks like this:

    +

    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 +

      +
    • +
    +

    5.1. 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

    -
    -
    Description:
    -    Creates a migration that adds yaffle squawk fields to the given model
    +
    +
    require File.dirname(__FILE__) + '/test_helper.rb'
    +require 'rails_generator'
    +require 'rails_generator/scripts/generate'
    +require 'rails_generator/scripts/destroy'
     
    -Example:
    -    ./script/generate yaffle hickwall
    +class YaffleTest < Test::Unit::TestCase
     
    -    This will create:
    -        db/migrate/TIMESTAMP_add_yaffle_fields_to_hickwall
    -
    -

    Now you can add code to your generator:

    + 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.

    +

    5.2. 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

    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 @@ -1039,31 +1120,19 @@ http://www.gnu.org/software/src-highlite --> 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")] - assigns[:attributes] << Rails::Generator::GeneratedAttribute.new("last_squawked_at", "datetime") end end end
    -

    Note that you need to be aware of whether or not table names are pluralized.

    -

    This does a few things:

    -
      -
    • -

      -Reuses the built in rails migration_template method. -

      -
    • -
    • -

      -Reuses the built-in rails migration template. -

      -
    • -
    -

    When you run the generator like

    +

    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.

    +

    5.3. Manually test the generator

    +

    To run the generator, type the following at the command line:

    -
    script/generate yaffle bird
    +
    ./script/generate yaffle bird
    -

    You will see a new file:

    +

    and you will see a new file:

    db/migrate/20080529225649_add_yaffle_fields_to_birds.rb

    class AddYaffleFieldsToBirds < ActiveRecord::Migration
       def self.up
         add_column :birds, :last_squawk, :string
    -    add_column :birds, :last_squawked_at, :datetime
       end
     
       def self.down
    -    remove_column :birds, :last_squawked_at
         remove_column :birds, :last_squawk
       end
     end
     
    +

    5.4. 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
    +

    6. Add a custom generator command

    -- cgit v1.2.3