diff options
Diffstat (limited to 'railties/lib/rails/command.rb')
-rw-r--r-- | railties/lib/rails/command.rb | 121 |
1 files changed, 75 insertions, 46 deletions
diff --git a/railties/lib/rails/command.rb b/railties/lib/rails/command.rb index f7753cbb83..6065e78fd1 100644 --- a/railties/lib/rails/command.rb +++ b/railties/lib/rails/command.rb @@ -1,70 +1,99 @@ -require 'rails/commands/commands_tasks' +require "active_support" +require "active_support/dependencies/autoload" +require "active_support/core_ext/enumerable" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/hash/transform_values" + +require "thor" module Rails - class Command #:nodoc: - attr_reader :argv + module Command + extend ActiveSupport::Autoload - def initialize(argv = []) - @argv = argv + autoload :Behavior + autoload :Base - @option_parser = build_option_parser - @options = {} - end + include Behavior - def self.run(task_name, argv) - command_name = command_name_for(task_name) + class << self + def hidden_commands # :nodoc: + @hidden_commands ||= [] + end - if command = command_for(command_name) - command.new(argv).run(command_name) - else - Rails::CommandsTasks.new(argv).run_command!(task_name) + def environment # :nodoc: + ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development" end - end - def run(command_name) - parse_options_for(command_name) - @option_parser.parse! @argv + # Receives a namespace, arguments and the behavior to invoke the command. + def invoke(namespace, args = [], **config) + namespace = namespace.to_s + namespace = "help" if namespace.blank? || Thor::HELP_MAPPINGS.include?(namespace) + namespace = "version" if %w( -v --version ).include? namespace - public_send(command_name) - end - - def self.options_for(command_name, &options_to_parse) - @@command_options[command_name] = options_to_parse - end + if command = find_by_namespace(namespace) + command.perform(namespace, args, config) + else + find_by_namespace("rake").perform(namespace, args, config) + end + end - def self.set_banner(command_name, banner) - options_for(command_name) { |opts, _| opts.banner = banner } - end + # Rails finds namespaces similar to thor, it only adds one rule: + # + # Command names must end with "_command.rb". This is required because Rails + # looks in load paths and loads the command just before it's going to be used. + # + # find_by_namespace :webrat, :rails, :integration + # + # Will search for the following commands: + # + # "rails:webrat", "webrat:integration", "webrat" + # + # Notice that "rails:commands:webrat" could be loaded as well, what + # Rails looks for is the first and last parts of the namespace. + def find_by_namespace(name) # :nodoc: + lookups = [ name, "rails:#{name}" ] - private - @@commands = [] - @@command_options = {} + lookup(lookups) - def parse_options_for(command_name) - @@command_options.fetch(command_name, proc {}).call(@option_parser, @options) + namespaces = subclasses.index_by(&:namespace) + namespaces[(lookups & namespaces.keys).first] end - def build_option_parser - OptionParser.new do |opts| - opts.on('-h', '--help', 'Show this help.') do - puts opts - exit - end + # Returns the root of the Rails engine or app running the command. + def root + if defined?(ENGINE_ROOT) + Pathname.new(ENGINE_ROOT) + elsif defined?(APP_PATH) + Pathname.new(File.expand_path("../..", APP_PATH)) end end - def self.inherited(command) - @@commands << command + def print_commands # :nodoc: + sorted_groups.each { |b, n| print_list(b, n) } end - def self.command_name_for(task_name) - task_name.gsub(':', '_').to_sym + def sorted_groups # :nodoc: + lookup! + + groups = (subclasses - hidden_commands).group_by { |c| c.namespace.split(":").first } + groups.transform_values! { |commands| commands.flat_map(&:printing_commands).sort } + + rails = groups.delete("rails") + [[ "rails", rails ]] + groups.sort.to_a end - def self.command_for(command_name) - @@commands.find do |command| - command.public_instance_methods.include?(command_name) + protected + def command_type + @command_type ||= "command" end - end + + def lookup_paths + @lookup_paths ||= %w( rails/commands commands ) + end + + def file_lookup_paths + @file_lookup_paths ||= [ "{#{lookup_paths.join(',')}}", "**", "*_command.rb" ] + end + end end end |