From 0761d1b0f7e89d49fe8cd6ab7eed3f084bd56fbd Mon Sep 17 00:00:00 2001 From: Carlhuda Date: Thu, 29 Apr 2010 18:30:19 -0700 Subject: Set up app generator class to make it easier to for alt-stacks to override targeted areas --- .../rails/generators/rails/app/app_generator.rb | 321 ++++++++++++++------- railties/test/generators/app_generator_test.rb | 4 + 2 files changed, 221 insertions(+), 104 deletions(-) diff --git a/railties/lib/rails/generators/rails/app/app_generator.rb b/railties/lib/rails/generators/rails/app/app_generator.rb index 667a123025..29e78a898c 100644 --- a/railties/lib/rails/generators/rails/app/app_generator.rb +++ b/railties/lib/rails/generators/rails/app/app_generator.rb @@ -3,87 +3,30 @@ require 'active_support/secure_random' require 'rails/version' unless defined?(Rails::VERSION) require 'rbconfig' -module Rails::Generators - # We need to store the RAILS_DEV_PATH in a constant, otherwise the path - # can change in Ruby 1.8.7 when we FileUtils.cd. - RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__)) - - RESERVED_NAMES = %w[generate console server dbconsole - application destroy benchmarker profiler - plugin runner test] - - class AppGenerator < Base - DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db ) - - attr_accessor :rails_template - add_shebang_option! - - argument :app_path, :type => :string - - class_option :database, :type => :string, :aliases => "-d", :default => "sqlite3", - :desc => "Preconfigure for selected database (options: #{DATABASES.join('/')})" - - class_option :template, :type => :string, :aliases => "-m", - :desc => "Path to an application template (can be a filesystem path or URL)." - - class_option :dev, :type => :boolean, :default => false, - :desc => "Setup the application with Gemfile pointing to your Rails checkout" - - class_option :edge, :type => :boolean, :default => false, - :desc => "Setup the application with Gemfile pointing to Rails repository" - - class_option :skip_gemfile, :type => :boolean, :default => false, - :desc => "Don't create a Gemfile" - - class_option :skip_activerecord, :type => :boolean, :aliases => "-O", :default => false, - :desc => "Skip ActiveRecord files" - - class_option :skip_testunit, :type => :boolean, :aliases => "-T", :default => false, - :desc => "Skip TestUnit files" - - class_option :skip_prototype, :type => :boolean, :aliases => "-J", :default => false, - :desc => "Skip Prototype files" - - class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false, - :desc => "Skip Git ignores and keeps" - - # Add bin/rails options - class_option :version, :type => :boolean, :aliases => "-v", :group => :rails, - :desc => "Show Rails version number and quit" - - class_option :help, :type => :boolean, :aliases => "-h", :group => :rails, - :desc => "Show this help message and quit" - - def initialize(*args) - raise Error, "Options should be given after the application name. For details run: rails --help" if args[0].blank? - super - if !options[:skip_activerecord] && !DATABASES.include?(options[:database]) - raise Error, "Invalid value for --database option. Supported for preconfiguration are: #{DATABASES.join(", ")}." - end +module Rails + class AppBuilder + def initialize(generator) + @generator = generator + @options = generator.options end - def create_root - self.destination_root = File.expand_path(app_path, destination_root) - valid_app_const? - - empty_directory '.' - set_default_accessors! - FileUtils.cd(destination_root) + def gemfile + template "Gemfile" end - def create_root_files - copy_file "README" - copy_file "gitignore", ".gitignore" unless options[:skip_git] - template "Rakefile" + def configru template "config.ru" - template "Gemfile" unless options[:skip_gemfile] end - def create_app_files + def gitignore + copy_file "gitignore", ".gitignore" + end + + def app directory 'app' end - def create_config_files + def config empty_directory "config" inside "config" do @@ -97,29 +40,24 @@ module Rails::Generators end end - def create_boot_file - template "config/boot.rb" - end - - def create_activerecord_files - return if options[:skip_activerecord] - template "config/databases/#{options[:database]}.yml", "config/database.yml" + def database_yml + template "config/databases/#{@options[:database]}.yml", "config/database.yml" end - def create_db_files + def db directory "db" end - def create_doc_files + def doc directory "doc" end - def create_lib_files + def lib empty_directory "lib" empty_directory_with_gitkeep "lib/tasks" end - def create_log_files + def log empty_directory "log" inside "log" do @@ -130,39 +68,34 @@ module Rails::Generators end end - def create_public_files - directory "public", "public", :recursive => false # Do small steps, so anyone can overwrite it. + def public_directory + directory "public", "public", :recursive => false end - def create_public_image_files + def images directory "public/images" end - def create_public_stylesheets_files + def stylesheets empty_directory_with_gitkeep "public/stylesheets" end - def create_prototype_files - unless options[:skip_prototype] - directory "public/javascripts" - else - empty_directory_with_gitkeep "public/javascripts" - end + def javascripts + directory "public/javascripts" end - def create_script_files + def script directory "script" do |content| "#{shebang}\n" + content end chmod "script", 0755, :verbose => false end - def create_test_files - return if options[:skip_testunit] + def test directory "test" end - def create_tmp_files + def tmp empty_directory "tmp" inside "tmp" do @@ -172,20 +105,195 @@ module Rails::Generators end end - def create_vendor_files + def vendor_plugins empty_directory_with_gitkeep "vendor/plugins" end - def apply_rails_template - apply rails_template if rails_template - rescue Thor::Error, LoadError, Errno::ENOENT => e - raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}" + + private + %w(template copy_file directory empty_directory inside + empty_directory_with_gitkeep create_file chmod shebang).each do |method| + class_eval <<-RUBY + def #{method}(*args, &block) + @generator.send(:#{method}, *args, &block) + end + RUBY end - def bundle_if_dev_or_edge - bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') - run "#{bundle_command} install" if dev_or_edge? + # TODO: Remove once this is fully in place + def method_missing(meth, *args, &block) + STDERR.puts "Calling #{meth} with #{args.inspect} with #{block}" + @generator.send(meth, *args, &block) end + end + + module Generators + # We need to store the RAILS_DEV_PATH in a constant, otherwise the path + # can change in Ruby 1.8.7 when we FileUtils.cd. + RAILS_DEV_PATH = File.expand_path("../../../../../..", File.dirname(__FILE__)) + + RESERVED_NAMES = %w[generate console server dbconsole + application destroy benchmarker profiler + plugin runner test] + + class AppGenerator < Base + DATABASES = %w( mysql oracle postgresql sqlite3 frontbase ibm_db ) + + attr_accessor :rails_template + add_shebang_option! + + argument :app_path, :type => :string + + class_option :database, :type => :string, :aliases => "-d", :default => "sqlite3", + :desc => "Preconfigure for selected database (options: #{DATABASES.join('/')})" + + class_option :template, :type => :string, :aliases => "-m", + :desc => "Path to an application template (can be a filesystem path or URL)." + + class_option :dev, :type => :boolean, :default => false, + :desc => "Setup the application with Gemfile pointing to your Rails checkout" + + class_option :edge, :type => :boolean, :default => false, + :desc => "Setup the application with Gemfile pointing to Rails repository" + + class_option :skip_gemfile, :type => :boolean, :default => false, + :desc => "Don't create a Gemfile" + + class_option :skip_activerecord, :type => :boolean, :aliases => "-O", :default => false, + :desc => "Skip ActiveRecord files" + + class_option :skip_testunit, :type => :boolean, :aliases => "-T", :default => false, + :desc => "Skip TestUnit files" + + class_option :skip_prototype, :type => :boolean, :aliases => "-J", :default => false, + :desc => "Skip Prototype files" + + class_option :skip_git, :type => :boolean, :aliases => "-G", :default => false, + :desc => "Skip Git ignores and keeps" + + # Add bin/rails options + class_option :version, :type => :boolean, :aliases => "-v", :group => :rails, + :desc => "Show Rails version number and quit" + + class_option :help, :type => :boolean, :aliases => "-h", :group => :rails, + :desc => "Show this help message and quit" + + def initialize(*args) + raise Error, "Options should be given after the application name. For details run: rails --help" if args[0].blank? + super + + if builder = options[:builder] + apply builder + end + + @builder = AppBuilder.new(self) + + if !options[:skip_activerecord] && !DATABASES.include?(options[:database]) + raise Error, "Invalid value for --database option. Supported for preconfiguration are: #{DATABASES.join(", ")}." + end + end + + def create_root + self.destination_root = File.expand_path(app_path, destination_root) + valid_app_const? + + empty_directory '.' + set_default_accessors! + FileUtils.cd(destination_root) + end + + def create_root_files + copy_file "README" + template "Rakefile" + build(:configru) + build(:gitignore) unless options[:skip_git] + build(:gemfile) unless options[:skip_gemfile] + end + + def create_app_files + build(:app) + end + + def create_config_files + build(:config) + end + + def create_boot_file + template "config/boot.rb" + end + + def create_activerecord_files + return if options[:skip_activerecord] + build(:database_yml) + end + + def create_db_files + build(:db) + end + + def create_doc_files + build(:doc) + end + + def create_lib_files + build(:lib) + end + + def create_log_files + build(:log) + end + + def create_public_files + build(:public) + end + + def create_public_image_files + build(:images) + end + + def create_public_stylesheets_files + build(:stylesheets) + empty_directory_with_gitkeep "public/stylesheets" + end + + def create_prototype_files + unless options[:skip_prototype] + build(:javascripts) + else + empty_directory_with_gitkeep "public/javascripts" + end + end + + def create_script_files + build(:script) + end + + def create_test_files + build(:test) unless options[:skip_testunit] + end + + def create_tmp_files + build(:tmp) + end + + def create_vendor_files + build(:vendor_plugins) + end + + def finish_template + build(:leftovers) + end + + def apply_rails_template + apply rails_template if rails_template + rescue Thor::Error, LoadError, Errno::ENOENT => e + raise Error, "The template [#{rails_template}] could not be loaded. Error: #{e}" + end + + def bundle_if_dev_or_edge + bundle_command = File.basename(Thor::Util.ruby_command).sub(/ruby/, 'bundle') + run "#{bundle_command} install" if dev_or_edge? + end protected @@ -193,6 +301,10 @@ module Rails::Generators "rails #{self.arguments.map(&:usage).join(' ')} [options]" end + def build(meth, *args) + @builder.send(meth, *args) if @builder.respond_to?(meth) + end + def set_default_accessors! self.rails_template = case options[:template] when /^http:\/\// @@ -274,5 +386,6 @@ module Rails::Generators empty_directory(destination, config) create_file("#{destination}/.gitkeep") unless options[:skip_git] end + end end end diff --git a/railties/test/generators/app_generator_test.rb b/railties/test/generators/app_generator_test.rb index 2e402c4f3a..1e5aa156ce 100644 --- a/railties/test/generators/app_generator_test.rb +++ b/railties/test/generators/app_generator_test.rb @@ -21,6 +21,10 @@ class AppGeneratorTest < Rails::Generators::TestCase run_generator %w( + .gitignore + Gemfile + Rakefile + config.ru app/controllers app/helpers app/models -- cgit v1.2.3