mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
Added migrations and make base generators be lazy loaded.
This commit is contained in:
@@ -12,9 +12,6 @@ require 'rails/version' unless defined?(Rails::VERSION)
|
||||
|
||||
require 'generators/base'
|
||||
require 'generators/named_base'
|
||||
require 'generators/active_record'
|
||||
require 'generators/erb'
|
||||
require 'generators/test_unit'
|
||||
|
||||
module Rails
|
||||
module Generators
|
||||
|
||||
@@ -1,8 +1,58 @@
|
||||
require 'generators/named_base'
|
||||
require 'active_record'
|
||||
|
||||
module ActiveRecord
|
||||
module Generators
|
||||
module Migration
|
||||
|
||||
# Creates a migration template at the given destination. The difference
|
||||
# to the default template method is that the migration number is appended
|
||||
# to the destination file name.
|
||||
#
|
||||
# The migration number, migration file name, migration class name are
|
||||
# available as instance variables in the template to be rendered.
|
||||
#
|
||||
# ==== Examples
|
||||
#
|
||||
# migration_template "migrate.rb", "db/migrate/add_foo_to_bar"
|
||||
#
|
||||
def migration_template(source, destination=nil, log_status=true)
|
||||
destination = File.expand_path(destination || source, self.destination_root)
|
||||
|
||||
migration_dir = File.dirname(destination)
|
||||
@migration_number = next_migration_number(migration_dir)
|
||||
@migration_file_name = File.basename(destination).sub(/\.rb$/, '')
|
||||
@migration_class_name = @migration_file_name.camelize
|
||||
|
||||
if existing = migration_exists?(migration_dir, @migration_file_name)
|
||||
raise Rails::Generators::Error, "Another migration is already named #{@migration_file_name}: #{existing}"
|
||||
end
|
||||
|
||||
destination = File.join(migration_dir, "#{@migration_number}_#{@migration_file_name}.rb")
|
||||
template(source, destination, log_status)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def migration_exists?(dirname, file_name) #:nodoc:
|
||||
Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first
|
||||
end
|
||||
|
||||
def current_migration_number(dirname) #:nodoc:
|
||||
Dir.glob("#{dirname}/[0-9]*_*.rb").collect{ |f| f.split("_").first.to_i }.max
|
||||
end
|
||||
|
||||
def next_migration_number(dirname) #:nodoc:
|
||||
if ActiveRecord::Base.timestamped_migrations
|
||||
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
||||
else
|
||||
"%.3d" % (current_migration_number(dirname) + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Base < Rails::Generators::NamedBase
|
||||
include Migration
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'generators/active_record'
|
||||
|
||||
module ActiveRecord
|
||||
module Generators
|
||||
class ModelGenerator < Base
|
||||
@@ -5,8 +7,7 @@ module ActiveRecord
|
||||
|
||||
check_class_collision
|
||||
|
||||
conditional_class_option :timestamps
|
||||
conditional_class_option :migration
|
||||
conditional_class_options :migration, :timestamps
|
||||
|
||||
class_option :parent, :type => :string,
|
||||
:desc => "The parent class for the generated model"
|
||||
@@ -15,12 +16,10 @@ module ActiveRecord
|
||||
template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb")
|
||||
end
|
||||
|
||||
# TODO Add migration support
|
||||
def create_migration_file
|
||||
if options[:migration] && options[:parent].nil?
|
||||
# m.migration_template 'migration.rb', 'db/migrate', :assigns => {
|
||||
# :migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}"
|
||||
# }, :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}"
|
||||
file_name = "create_#{file_path.gsub(/\//, '_').pluralize}"
|
||||
migration_template "migration.rb", "db/migrate/#{file_name}.rb"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
class <%= migration_name %> < ActiveRecord::Migration
|
||||
class <%= @migration_class_name %> < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :<%= table_name %> do |t|
|
||||
<% for attribute in attributes -%>
|
||||
t.<%= attribute.type %> :<%= attribute.name %>
|
||||
<% end -%>
|
||||
<% unless options[:skip_timestamps] %>
|
||||
<% if options[:timestamps] %>
|
||||
t.timestamps
|
||||
<% end -%>
|
||||
end
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'generators/active_record'
|
||||
|
||||
module ActiveRecord
|
||||
module Generators
|
||||
class ObserverGenerator < Base
|
||||
|
||||
@@ -145,13 +145,13 @@ module Rails
|
||||
# "rails:generators:webrat", "webrat:generators:controller", "webrat"
|
||||
#
|
||||
def self.invoke_if(*names)
|
||||
default_options = names.extract_options!
|
||||
verbose = default_options.key?(:verbose) ? default_options[:verbose] : :blue
|
||||
conditional_class_options(*names)
|
||||
|
||||
options = names.extract_options!
|
||||
verbose = options.fetch(:verbose, :blue)
|
||||
invocations.concat(names)
|
||||
|
||||
names.each do |name|
|
||||
conditional_class_option name, default_options.dup
|
||||
|
||||
class_eval <<-METHOD, __FILE__, __LINE__
|
||||
def invoke_if_#{name}
|
||||
return unless options[#{name.inspect}]
|
||||
@@ -236,9 +236,14 @@ module Rails
|
||||
# Creates a conditional class option with type boolean, default value
|
||||
# lookup and default description.
|
||||
#
|
||||
def self.conditional_class_option(name, options={})
|
||||
options[:desc] ||= "Indicates when to generate #{name.to_s.humanize.downcase}"
|
||||
class_option name, options.merge!(:type => :boolean, :default => DEFAULTS[name] || false)
|
||||
def self.conditional_class_options(*names)
|
||||
default_options = names.extract_options!
|
||||
|
||||
names.each do |name|
|
||||
options = default_options.dup
|
||||
options[:desc] ||= "Indicates when to generate #{name.to_s.humanize.downcase}"
|
||||
class_option name, options.merge!(:type => :boolean, :default => DEFAULTS[name] || false)
|
||||
end
|
||||
end
|
||||
|
||||
# Overwrite class options help to allow invoked generators options to be
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'generators/erb'
|
||||
|
||||
module Erb
|
||||
module Generators
|
||||
class ControllerGenerator < Base
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'generators/erb'
|
||||
|
||||
module Erb
|
||||
module Generators
|
||||
class MailerGenerator < Base
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'generators/test_unit'
|
||||
|
||||
module TestUnit
|
||||
module Generators
|
||||
class ControllerGenerator < Base
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'generators/test_unit'
|
||||
|
||||
module TestUnit
|
||||
module Generators
|
||||
class HelperGenerator < Base
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'generators/test_unit'
|
||||
|
||||
module TestUnit
|
||||
module Generators
|
||||
class MailerGenerator < Base
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
require 'generators/test_unit'
|
||||
|
||||
module TestUnit
|
||||
module Generators
|
||||
class ModelGenerator < Base
|
||||
argument :attributes, :type => :hash, :default => {}, :banner => "field:type, field:type"
|
||||
|
||||
check_class_collision :suffix => "Test"
|
||||
conditional_class_option :fixture
|
||||
conditional_class_options :fixture
|
||||
|
||||
def create_test_file
|
||||
template 'unit_test.rb', File.join('test/unit', class_path, "#{file_name}_test.rb")
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'generators/test_unit'
|
||||
|
||||
module TestUnit
|
||||
module Generators
|
||||
class ObserverGenerator < Base
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
require 'generators/test_unit'
|
||||
|
||||
module TestUnit
|
||||
module Generators
|
||||
class PluginGenerator < Base
|
||||
|
||||
@@ -36,20 +36,41 @@ class GeneratorsTestCase < Test::Unit::TestCase
|
||||
|
||||
def assert_file(relative, *contents)
|
||||
absolute = File.join(destination_root, relative)
|
||||
assert File.exists?(absolute)
|
||||
assert File.exists?(absolute), "Expected file #{relative.inspect} to exist, but does not"
|
||||
|
||||
read = File.read(absolute) unless File.directory?(absolute)
|
||||
contents.each do |content|
|
||||
case content
|
||||
when String
|
||||
assert_equal content, File.read(absolute)
|
||||
assert_equal content, read
|
||||
when Regexp
|
||||
assert_match content, File.read(absolute)
|
||||
assert_match content, read
|
||||
end
|
||||
end
|
||||
read
|
||||
end
|
||||
|
||||
def assert_no_file(relative, content=nil)
|
||||
def assert_no_file(relative)
|
||||
absolute = File.join(destination_root, relative)
|
||||
assert !File.exists?(absolute)
|
||||
assert !File.exists?(absolute), "Expected file #{relative.inspect} to not exist, but does"
|
||||
end
|
||||
|
||||
def assert_migration(relative, *contents)
|
||||
file_name = migration_file_name(relative)
|
||||
assert file_name, "Expected migration #{relative} to exist, but was not found"
|
||||
assert_file File.join(File.dirname(relative), file_name), *contents
|
||||
end
|
||||
|
||||
def assert_no_migration(relative)
|
||||
file_name = migration_file_name(relative)
|
||||
assert_nil file_name, "Expected migration #{relative} to not exist, but found #{file_name}"
|
||||
end
|
||||
|
||||
def migration_file_name(relative)
|
||||
absolute = File.join(destination_root, relative)
|
||||
dirname, file_name = File.dirname(absolute), File.basename(absolute).sub(/\.rb$/, '')
|
||||
|
||||
migration = Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{file_name}.rb$/).first
|
||||
File.basename(migration) if migration
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,28 +17,64 @@ class ModelGeneratorTest < GeneratorsTestCase
|
||||
assert_file "app/models/account.rb", /class Account < ActiveRecord::Base/
|
||||
end
|
||||
|
||||
def test_orm_with_parent_option
|
||||
def test_model_with_parent_option
|
||||
run_generator ["account", "--parent", "Admin::Account"]
|
||||
assert_file "app/models/account.rb", /class Account < Admin::Account/
|
||||
end
|
||||
|
||||
def test_orm_with_underscored_parent_option
|
||||
def test_model_with_underscored_parent_option
|
||||
run_generator ["account", "--parent", "admin/account"]
|
||||
assert_file "app/models/account.rb", /class Account < Admin::Account/
|
||||
end
|
||||
|
||||
def test_migration
|
||||
run_generator
|
||||
assert_migration "db/migrate/create_accounts.rb", /class CreateAccounts < ActiveRecord::Migration/
|
||||
end
|
||||
|
||||
def test_migration_is_skipped
|
||||
run_generator ["account", "--no-migration"]
|
||||
assert_no_migration "db/migrate/create_accounts.rb"
|
||||
end
|
||||
|
||||
def test_migration_with_attributes
|
||||
run_generator ["product", "name:string", "supplier_id:integer"]
|
||||
assert_migration "db/migrate/create_products.rb", /t\.string :name/, /t\.integer :supplier_id/
|
||||
end
|
||||
|
||||
def test_model_with_references_attribute_generates_belongs_to_associations
|
||||
run_generator ["product", "name:string", "supplier_id:references"]
|
||||
assert_file "app/models/product.rb", /belongs_to :supplier/
|
||||
end
|
||||
|
||||
def test_model_with_belongs_to_attribute_generates_belongs_to_associations
|
||||
run_generator ["product", "name:string", "supplier_id:belongs_to"]
|
||||
assert_file "app/models/product.rb", /belongs_to :supplier/
|
||||
end
|
||||
|
||||
def test_migration_with_timestamps
|
||||
run_generator
|
||||
assert_migration "db/migrate/create_accounts.rb", /t.timestamps/
|
||||
end
|
||||
|
||||
def test_migration_timestamps_are_skipped
|
||||
run_generator ["account", "--no-timestamps"]
|
||||
content = assert_migration "db/migrate/create_accounts.rb"
|
||||
assert_no_match /t.timestamps/, content
|
||||
end
|
||||
|
||||
def test_invokes_default_test_framework
|
||||
run_generator
|
||||
assert_file "test/unit/account_test.rb", /class AccountTest < ActiveSupport::TestCase/
|
||||
assert_file "test/fixtures/accounts.yml", /name: MyString/, /age: 1/
|
||||
end
|
||||
|
||||
def test_fixtures_are_skipped
|
||||
def test_fixture_is_skipped
|
||||
run_generator ["account", "--skip-fixture"]
|
||||
assert_no_file "test/fixtures/accounts.yml"
|
||||
end
|
||||
|
||||
def test_fixtures_are_skipped_if_fixture_replacement_is_given
|
||||
def test_fixture_is_skipped_if_fixture_replacement_is_given
|
||||
content = run_generator ["account", "-r", "fixjour"]
|
||||
assert_match /Could not find and invoke 'fixjour'/, content
|
||||
assert_no_file "test/fixtures/accounts.yml"
|
||||
@@ -49,42 +85,6 @@ class ModelGeneratorTest < GeneratorsTestCase
|
||||
assert_match /The name 'Object' is either already used in your application or reserved/, content
|
||||
end
|
||||
|
||||
# def test_model_skip_migration_skips_migration
|
||||
# run_generator('model', %w(Product name:string --skip-migration))
|
||||
|
||||
# assert_generated_model_for :product
|
||||
# assert_generated_fixtures_for :products
|
||||
# assert_skipped_migration :create_products
|
||||
# end
|
||||
|
||||
# def test_model_with_attributes_generates_resources_with_attributes
|
||||
# run_generator('model', %w(Product name:string supplier_id:integer created_at:timestamp))
|
||||
|
||||
# assert_generated_model_for :product
|
||||
# assert_generated_fixtures_for :products
|
||||
# assert_generated_migration :create_products do |t|
|
||||
# assert_generated_column t, :name, :string
|
||||
# assert_generated_column t, :supplier_id, :integer
|
||||
# assert_generated_column t, :created_at, :timestamp
|
||||
# end
|
||||
# end
|
||||
|
||||
# def test_model_with_reference_attributes_generates_belongs_to_associations
|
||||
# run_generator('model', %w(Product name:string supplier:references))
|
||||
|
||||
# assert_generated_model_for :product do |body|
|
||||
# assert body =~ /^\s+belongs_to :supplier/, "#{body.inspect} should contain 'belongs_to :supplier'"
|
||||
# end
|
||||
# end
|
||||
|
||||
# def test_model_with_belongs_to_attributes_generates_belongs_to_associations
|
||||
# run_generator('model', %w(Product name:string supplier:belongs_to))
|
||||
|
||||
# assert_generated_model_for :product do |body|
|
||||
# assert body =~ /^\s+belongs_to :supplier/, "#{body.inspect} should contain 'belongs_to :supplier'"
|
||||
# end
|
||||
# end
|
||||
|
||||
protected
|
||||
|
||||
def run_generator(args=["Account", "name:string", "age:integer"])
|
||||
|
||||
Reference in New Issue
Block a user