require 'rails/commands/rake_proxy' module Rails # This is a class which takes in a rails command and initiates the appropriate # initiation sequence. # # Warning: This class mutates ARGV because some commands require manipulating # it before they are run. class CommandsTasks # :nodoc: include Rails::RakeProxy attr_reader :argv HELP_MESSAGE = <<-EOT Usage: rails COMMAND [ARGS] The most common rails commands are: generate Generate new code (short-cut alias: "g") console Start the Rails console (short-cut alias: "c") server Start the Rails server (short-cut alias: "s") test Run tests (short-cut alias: "t") dbconsole Start a console for the database specified in config/database.yml (short-cut alias: "db") new Create a new Rails application. "rails new my_app" creates a new application called MyApp in "./my_app" All commands can be run with -h (or --help) for more information. In addition to those commands, there are: EOT ADDITIONAL_COMMANDS = [ [ 'destroy', 'Undo code generated with "generate" (short-cut alias: "d")' ], [ 'plugin new', 'Generates skeleton for developing a Rails plugin' ], [ 'runner', 'Run a piece of code in the application environment (short-cut alias: "r")' ] ] COMMAND_WHITELIST = %w(plugin generate destroy console server dbconsole runner new version help test) def initialize(argv) @argv = argv end def run_command!(command) command = parse_command(command) if COMMAND_WHITELIST.include?(command) send(command) else run_rake_task(command) end end def plugin require_command!("plugin") end def generate generate_or_destroy(:generate) end def destroy generate_or_destroy(:destroy) end def console require_command!("console") options = Rails::Console.parse_arguments(argv) # RAILS_ENV needs to be set before config/application is required ENV['RAILS_ENV'] = options[:environment] if options[:environment] # shift ARGV so IRB doesn't freak shift_argv! require_application_and_environment! Rails::Console.start(Rails.application, options) end def server set_application_directory! require_command!("server") Rails::Server.new.tap do |server| # We need to require application after the server sets environment, # otherwise the --environment option given to the server won't propagate. require APP_PATH Dir.chdir(Rails.application.root) server.start end end def test require_command!("test") end def dbconsole require_command!("dbconsole") Rails::DBConsole.start end def runner require_command!("runner") end def new if %w(-h --help).include?(argv.first) require_command!("application") else exit_with_initialization_warning! end end def version argv.unshift '--version' require_command!("application") end def help write_help_message write_commands ADDITIONAL_COMMANDS + formatted_rake_tasks end private def exit_with_initialization_warning! puts "Can't initialize a new Rails application within the directory of another, please change to a non-Rails directory first.\n" puts "Type 'rails' for help." exit(1) end def shift_argv! argv.shift if argv.first && argv.first[0] != '-' end def require_command!(command) require "rails/commands/#{command}" end def generate_or_destroy(command) require 'rails/generators' require_application_and_environment! Rails.application.load_generators require_command!(command) end # Change to the application's path if there is no config.ru file in current directory. # This allows us to run `rails server` from other directories, but still get # the main config.ru and properly set the tmp directory. def set_application_directory! Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exist?(File.expand_path("config.ru")) end def require_application_and_environment! require APP_PATH Rails.application.require_environment! end def write_help_message puts HELP_MESSAGE end def write_commands(commands) width = commands.map { |name, _| name.size }.max || 10 commands.each { |command| printf(" %-#{width}s %s\n", *command) } end def parse_command(command) case command when '--version', '-v' 'version' when '--help', '-h' 'help' else command end end end end