提交 496dde95 编写于 作者: J José Valim

Added migrations and make base generators be lazy loaded.

上级 c03585aa
......@@ -12,9 +12,6 @@
require 'generators/base'
require 'generators/named_base'
require 'generators/active_record'
require 'generators/erb'
require 'generators/test_unit'
module Rails
module Generators
......
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
require 'generators/active_record'
module ActiveRecord
module Generators
class ModelGenerator < Base
......@@ -5,8 +7,7 @@ class ModelGenerator < Base
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 @@ def create_model_file
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
......
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
......
require 'generators/active_record'
module ActiveRecord
module Generators
class ObserverGenerator < Base
......
......@@ -145,13 +145,13 @@ def invoke_for_#{name}
# "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 @@ def self.invocations #:nodoc:
# 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
......
require 'generators/erb'
module Erb
module Generators
class ControllerGenerator < Base
......
require 'generators/erb'
module Erb
module Generators
class MailerGenerator < Base
......
require 'generators/test_unit'
module TestUnit
module Generators
class ControllerGenerator < Base
......
require 'generators/test_unit'
module TestUnit
module Generators
class HelperGenerator < Base
......
require 'generators/test_unit'
module TestUnit
module Generators
class MailerGenerator < Base
......
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")
......
require 'generators/test_unit'
module TestUnit
module Generators
class ObserverGenerator < Base
......
require 'generators/test_unit'
module TestUnit
module Generators
class PluginGenerator < Base
......
......@@ -36,20 +36,41 @@ def capture(stream)
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 @@ def test_invokes_default_orm
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 @@ def test_check_class_collision
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"])
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册