require 'rails/generators/app_base'
module Rails
module ActionMethods # :nodoc:
attr_reader :options
def initialize(generator)
@generator = generator
@options = generator.options
end
private
%w(template copy_file directory empty_directory inside
empty_directory_with_keep_file create_file chmod shebang).each do |method|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{method}(*args, &block)
@generator.send(:#{method}, *args, &block)
end
RUBY
end
# TODO: Remove once this is fully in place
def method_missing(meth, *args, &block)
@generator.send(meth, *args, &block)
end
end
# The application builder allows you to override elements of the application
# generator without being forced to reverse the operations of the default
# generator.
#
# This allows you to override entire operations, like the creation of the
# Gemfile, README, or JavaScript files, without needing to know exactly
# what those operations do so you can create another template action.
class AppBuilder
def rakefile
template "Rakefile"
end
def readme
copy_file "README.md", "README.md"
end
def gemfile
template "Gemfile"
end
def configru
template "config.ru"
end
def gitignore
template "gitignore", ".gitignore"
end
def app
directory 'app'
keep_file 'app/assets/images'
keep_file 'app/mailers'
keep_file 'app/models'
keep_file 'app/controllers/concerns'
keep_file 'app/models/concerns'
end
def bin
directory "bin" do |content|
"#{shebang}\n" + content
end
chmod "bin", 0755 & ~File.umask, verbose: false
end
def config
empty_directory "config"
inside "config" do
template "routes.rb"
template "application.rb"
template "environment.rb"
template "secrets.yml"
directory "environments"
directory "initializers"
directory "locales"
end
end
def config_when_updating
cookie_serializer_config_exist = File.exist?('config/initializers/cookies_serializer.rb')
callback_terminator_config_exist = File.exist?('config/initializers/callback_terminator.rb')
active_record_belongs_to_required_by_default_config_exist = File.exist?('config/initializers/active_record_belongs_to_required_by_default.rb')
config
unless callback_terminator_config_exist
remove_file 'config/initializers/callback_terminator.rb'
end
unless cookie_serializer_config_exist
gsub_file 'config/initializers/cookies_serializer.rb', /json/, 'marshal'
end
unless active_record_belongs_to_required_by_default_config_exist
remove_file 'config/initializers/active_record_belongs_to_required_by_default.rb'
end
end
def database_yml
template "config/databases/#{options[:database]}.yml", "config/database.yml"
end
def db
directory "db"
end
def lib
empty_directory 'lib'
empty_directory_with_keep_file 'lib/tasks'
empty_directory_with_keep_file 'lib/assets'
end
def log
empty_directory_with_keep_file 'log'
end
def public_directory
directory "public", "public", recursive: false
end
def test
empty_directory_with_keep_file 'test/fixtures'
empty_directory_with_keep_file 'test/fixtures/files'
empty_directory_with_keep_file 'test/controllers'
empty_directory_with_keep_file 'test/mailers'
empty_directory_with_keep_file 'test/models'
empty_directory_with_keep_file 'test/helpers'
empty_directory_with_keep_file 'test/integration'
template 'test/test_helper.rb'
end
def tmp
empty_directory_with_keep_file "tmp"
empty_directory "tmp/cache"
empty_directory "tmp/cache/assets"
end
def vendor
vendor_javascripts
vendor_stylesheets
end
def vendor_javascripts
unless options[:skip_javascript]
empty_directory_with_keep_file 'vendor/assets/javascripts'
end
end
def vendor_stylesheets
empty_directory_with_keep_file 'vendor/assets/stylesheets'
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[application destroy plugin runner test]
class AppGenerator < AppBase # :nodoc:
add_shared_options_for "application"
# Add bin/rails options
class_option :version, type: :boolean, aliases: "-v", group: :rails,
desc: "Show Rails version number and quit"
class_option :api, type: :boolean,
desc: "Preconfigure smaller stack for API only apps"
def initialize(*args)
super
unless app_path
raise Error, "Application name should be provided in arguments. For details run: rails --help"
end
if !options[:skip_active_record] && !DATABASES.include?(options[:database])
raise Error, "Invalid value for --database option. Supported for preconfiguration are: #{DATABASES.join(", ")}."
end
# Force sprockets to be skipped when generating API only apps.
# Can't modify options hash as it's frozen by default.
self.options = options.merge(skip_sprockets: true, skip_javascript: true).freeze if options[:api]
end
public_task :set_default_accessors!
public_task :create_root
def create_root_files
build(:readme)
build(: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_bin_files
build(:bin)
end
def create_config_files
build(:config)
end
def update_config_files
build(:config_when_updating)
end
remove_task :update_config_files
def create_boot_file
template "config/boot.rb"
end
def create_active_record_files
return if options[:skip_active_record]
build(:database_yml)
end
def create_db_files
build(:db)
end
def create_lib_files
build(:lib)
end
def create_log_files
build(:log)
end
def create_public_files
build(:public_directory)
end
def create_test_files
build(:test) unless options[:skip_test]
end
def create_tmp_files
build(:tmp)
end
def create_vendor_files
build(:vendor)
end
def delete_app_assets_if_api_option
if options[:api]
remove_dir 'app/assets'
remove_dir 'lib/assets'
remove_dir 'tmp/cache/assets'
remove_dir 'vendor/assets'
end
end
def delete_app_helpers_if_api_option
if options[:api]
remove_dir 'app/helpers'
remove_dir 'test/helpers'
end
end
def delete_app_views_if_api_option
if options[:api]
remove_dir 'app/views'
end
end
def delete_js_folder_skipping_javascript
if options[:skip_javascript]
remove_dir 'app/assets/javascripts'
end
end
def delete_assets_initializer_skipping_sprockets
if options[:skip_sprockets]
remove_file 'config/initializers/assets.rb'
end
end
def delete_active_record_initializers_skipping_active_record
if options[:skip_active_record]
remove_file 'config/initializers/active_record_belongs_to_required_by_default.rb'
end
end
def delete_non_api_initializers_if_api_option
if options[:api]
remove_file 'config/initializers/session_store.rb'
remove_file 'config/initializers/cookies_serializer.rb'
end
end
def finish_template
build(:leftovers)
end
public_task :apply_rails_template, :run_bundle
public_task :generate_spring_binstubs
def run_after_bundle_callbacks
@after_bundle_callbacks.each(&:call)
end
protected
def self.banner
"rails new #{self.arguments.map(&:usage).join(' ')} [options]"
end
# Define file as an alias to create_file for backwards compatibility.
def file(*args, &block)
create_file(*args, &block)
end
def app_name
@app_name ||= (defined_app_const_base? ? defined_app_name : File.basename(destination_root)).tr('\\', '').tr(". ", "_")
end
def defined_app_name
defined_app_const_base.underscore
end
def defined_app_const_base
Rails.respond_to?(:application) && defined?(Rails::Application) &&
Rails.application.is_a?(Rails::Application) && Rails.application.class.name.sub(/::Application$/, "")
end
alias :defined_app_const_base? :defined_app_const_base
def app_const_base
@app_const_base ||= defined_app_const_base || app_name.gsub(/\W/, '_').squeeze('_').camelize
end
alias :camelized :app_const_base
def app_const
@app_const ||= "#{app_const_base}::Application"
end
def valid_const?
if app_const =~ /^\d/
raise Error, "Invalid application name #{app_name}. Please give a name which does not start with numbers."
elsif RESERVED_NAMES.include?(app_name)
raise Error, "Invalid application name #{app_name}. Please give a name which does not match one of the reserved rails words: #{RESERVED_NAMES}"
elsif Object.const_defined?(app_const_base)
raise Error, "Invalid application name #{app_name}, constant #{app_const_base} is already in use. Please choose another application name."
end
end
def app_secret
SecureRandom.hex(64)
end
def mysql_socket
@mysql_socket ||= [
"/tmp/mysql.sock", # default
"/var/run/mysqld/mysqld.sock", # debian/gentoo
"/var/tmp/mysql.sock", # freebsd
"/var/lib/mysql/mysql.sock", # fedora
"/opt/local/lib/mysql/mysql.sock", # fedora
"/opt/local/var/run/mysqld/mysqld.sock", # mac + darwinports + mysql
"/opt/local/var/run/mysql4/mysqld.sock", # mac + darwinports + mysql4
"/opt/local/var/run/mysql5/mysqld.sock", # mac + darwinports + mysql5
"/opt/lampp/var/mysql/mysql.sock" # xampp for linux
].find { |f| File.exist?(f) } unless RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
end
def get_builder_class
defined?(::AppBuilder) ? ::AppBuilder : Rails::AppBuilder
end
end
# This class handles preparation of the arguments before the AppGenerator is
# called. The class provides version or help information if they were
# requested, and also constructs the railsrc file (used for extra configuration
# options).
#
# This class should be called before the AppGenerator is required and started
# since it configures and mutates ARGV correctly.
class ARGVScrubber # :nodoc:
def initialize(argv = ARGV)
@argv = argv
end
def prepare!
handle_version_request!(@argv.first)
handle_invalid_command!(@argv.first, @argv) do
handle_rails_rc!(@argv.drop(1))
end
end
def self.default_rc_file
File.expand_path('~/.railsrc')
end
private
def handle_version_request!(argument)
if ['--version', '-v'].include?(argument)
require 'rails/version'
puts "Rails #{Rails::VERSION::STRING}"
exit(0)
end
end
def handle_invalid_command!(argument, argv)
if argument == "new"
yield
else
['--help'] + argv.drop(1)
end
end
def handle_rails_rc!(argv)
if argv.find { |arg| arg == '--no-rc' }
argv.reject { |arg| arg == '--no-rc' }
else
railsrc(argv) { |rc_argv, rc| insert_railsrc_into_argv!(rc_argv, rc) }
end
end
def railsrc(argv)
if (customrc = argv.index{ |x| x.include?("--rc=") })
fname = File.expand_path(argv[customrc].gsub(/--rc=/, ""))
yield(argv.take(customrc) + argv.drop(customrc + 1), fname)
else
yield argv, self.class.default_rc_file
end
end
def read_rc_file(railsrc)
extra_args = File.readlines(railsrc).flat_map(&:split)
puts "Using #{extra_args.join(" ")} from #{railsrc}"
extra_args
end
def insert_railsrc_into_argv!(argv, railsrc)
return argv unless File.exist?(railsrc)
extra_args = read_rc_file railsrc
argv.take(1) + extra_args + argv.drop(1)
end
end
end
end