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: 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" In addition to those, there are: 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") All commands can be run with -h (or --help) for more information. EOT COMMAND_WHITELIST = %w(plugin generate destroy console server dbconsole runner new version help test) def initialize(argv) @argv = argv @rails_command = Rails::Commands::Command.new(argv) end def run_command!(command) command = parse_command(command) if @rails_command.exists?(command) @rails_command.run(command) elsif COMMAND_WHITELIST.include?(command) send(command) else write_error_message(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 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 # Output an error message stating that the attempted command is not a valid rails command. # Run the attempted command as a rake command with the --dry-run flag. If successful, suggest # to the user that they possibly meant to run the given rails command as a rake command. # Append the help message. # # Example: # $ rails db:migrate # Error: Command 'db:migrate' not recognized # Did you mean: `$ rake db:migrate` ? # (Help message output) # def write_error_message(command) puts "Error: Command '#{command}' not recognized" if %x{rake #{command} --dry-run 2>&1 } && $?.success? puts "Did you mean: `$ rake #{command}` ?\n\n" end write_help_message exit(1) end def parse_command(command) case command when '--version', '-v' 'version' when '--help', '-h' 'help' else command end end end end