module HammerCLI module Subcommand class Definition < Clamp::Subcommand::Definition def initialize(names, description, subcommand_class, options = {}) @names = Array(names) @description = description @subcommand_class = subcommand_class @hidden = options[:hidden] @warning = options[:warning] end def hidden? @hidden end def subcommand_class @warning ||= @subcommand_class.warning warn(@warning) if @warning @subcommand_class end def help names = HammerCLI.context[:full_help] ? @names.join(", ") : @names.first [names, description] end attr_reader :warning end class LazyDefinition < Definition def initialize(names, description, subcommand_class_name, path, options = {}) super(names, description, subcommand_class_name, options) @loaded = false @path = path end def loaded? @loaded end def subcommand_class unless @loaded require @path @loaded = true @constantized_class = @subcommand_class.constantize end @warning ||= @constantized_class.warning warn(@warning) if @warning @constantized_class end end def self.included(base) base.extend(ClassMethods) end module ClassMethods def remove_subcommand(name) self.recognised_subcommands.delete_if do |sc| if sc.is_called?(name) logger.info "subcommand #{name} (#{sc.subcommand_class}) was removed." true else false end end end def subcommand!(name, description, subcommand_class = self, options = {}, &block) remove_subcommand(name) subcommand(name, description, subcommand_class, options, &block) logger.info "subcommand #{name} (#{subcommand_class}) was created." end def subcommand(name, description, subcommand_class = self, options = {}, &block) definition = Definition.new(name, description, subcommand_class, options) define_subcommand(name, subcommand_class, definition, &block) end def lazy_subcommand(name, description, subcommand_class_name, path, options = {}) definition = LazyDefinition.new(name, description, subcommand_class_name, path, options) define_subcommand(name, Class, definition) end def lazy_subcommand!(name, description, subcommand_class_name, path, options = {}) remove_subcommand(name) self.lazy_subcommand(name, description, subcommand_class_name, path, options) logger.info "subcommand #{name} (#{subcommand_class_name}) was created." end def find_subcommand(name, fuzzy: true) subcommand = super(name) if subcommand.nil? && fuzzy find_subcommand_starting_with(name) else subcommand end end def find_subcommand_starting_with(name) subcommands = recognised_subcommands.select { |sc| sc.names.any? { |n| n.start_with?(name) } } if subcommands.size > 1 raise HammerCLI::CommandConflict, _('Found more than one command.') + "\n\n" + _('Did you mean one of these?') + "\n\t" + subcommands.collect(&:names).flatten.select { |n| n.start_with?(name) }.join("\n\t") end subcommands.first end def define_subcommand(name, subcommand_class, definition, &block) existing = find_subcommand(name, fuzzy: false) if existing raise HammerCLI::CommandConflict, _("Can't replace subcommand %s (%s) with %s (%s).") % { :name => name, :existing_class => existing.subcommand_class, :new_class => subcommand_class } end subcommand_class = Class.new(subcommand_class, &block) if block declare_subcommand_parameters unless has_subcommands? recognised_subcommands << definition end end end end