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
module Command
extend ActiveSupport::Autoload
autoload :Behavior
autoload :Base
include Behavior
HELP_MAPPINGS = %w(-h -? --help)
class << self
def hidden_commands # :nodoc:
@hidden_commands ||= []
end
def environment # :nodoc:
ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
end
# 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? || HELP_MAPPINGS.include?(namespace)
namespace = "version" if %w( -v --version ).include? namespace
if command = find_by_namespace(namespace)
command.perform(namespace, args, config)
else
find_by_namespace("rake").perform(namespace, args, config)
end
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}" ]
lookup(lookups)
namespaces = subclasses.index_by(&:namespace)
namespaces[(lookups & namespaces.keys).first]
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 print_commands # :nodoc:
sorted_groups.each { |b, n| print_list(b, n) }
end
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
private
def command_type # :doc:
@command_type ||= "command"
end
def lookup_paths # :doc:
@lookup_paths ||= %w( rails/commands commands )
end
def file_lookup_paths # :doc:
@file_lookup_paths ||= [ "{#{lookup_paths.join(',')}}", "**", "*_command.rb" ]
end
end
end
end