class Commander::Runner

def self.instance

def self.instance
  @instance ||= new
end

def self.separate_switches_from_description(*args)

def self.separate_switches_from_description(*args)
  switches = args.find_all { |arg| arg.to_s =~ /^-/ }
  description = args.last if args.last.is_a?(String) && !args.last.match(/^-/)
  [switches, description]
end

def self.switch_to_sym(switch)

def self.switch_to_sym(switch)
  switch.scan(/[\-\]](\w+)/).join('_').to_sym rescue nil
end

def active_command

def active_command
  @active_command ||= command(command_name_from_args)
end

def add_command(command)

def add_command(command)
  @commands[command.name] = command
end

def alias?(name)

def alias?(name)
  @aliases.include? name.to_s
end

def alias_command(alias_name, name, *args)

def alias_command(alias_name, name, *args)
  @commands[alias_name.to_s] = command name
  @aliases[alias_name.to_s] = args
end

def always_trace!

def always_trace!
  @always_trace = true
  @never_trace = false
end

def args_without_command_name

def args_without_command_name
  removed = []
  parts = command_name_from_args.split rescue []
  @args.dup.delete_if do |arg|
    removed << arg if parts.include?(arg) && !removed.include?(arg)
  end
end

def command(name, &block)

def command(name, &block)
  yield add_command(Commander::Command.new(name)) if block
  @commands[name.to_s]
end

def command_exists?(name)

def command_exists?(name)
  @commands[name.to_s]
end

def command_name_from_args

def command_name_from_args
  @command_name_from_args ||= (longest_valid_command_name_from(@args) || @default_command)
end

def create_default_commands

def create_default_commands
  command :help do |c|
    c.syntax = 'commander help [command]'
    c.description = 'Display global or [command] help documentation'
    c.example 'Display global help', 'command help'
    c.example "Display help for 'foo'", 'command help foo'
    c.when_called do |args, _options|
      UI.enable_paging if program(:help_paging)
      if args.empty?
        say help_formatter.render
      else
        command = command(longest_valid_command_name_from(args))
        begin
          require_valid_command command
        rescue InvalidCommandError => e
          abort "#{e}. Use --help for more information"
        end
        say help_formatter.render_command(command)
      end
    end
  end
end

def default_command(name)

def default_command(name)
  @default_command = name
end

def expand_optionally_negative_switches(switches)

properly detected and removed
'--blah' and '--no-blah' variants, so that they can be
expand switches of the style '--[no-]blah' into both their
def expand_optionally_negative_switches(switches)
  switches.reduce([]) do |memo, val|
    if val =~ /\[no-\]/
      memo << val.gsub(/\[no-\]/, '')
      memo << val.gsub(/\[no-\]/, 'no-')
    else
      memo << val
    end
  end
end

def global_option(*args, &block)

def global_option(*args, &block)
  switches, description = Runner.separate_switches_from_description(*args)
  @options << {
    args: args,
    proc: block,
    switches: switches,
    description: description,
  }
end

def global_option_proc(switches, &block)

def global_option_proc(switches, &block)
  lambda do |value|
    unless active_command.nil?
      active_command.global_options << [Runner.switch_to_sym(switches.last), value]
    end
    yield value if block && !value.nil?
  end
end

def help_formatter

def help_formatter
  @help_formatter ||= program(:help_formatter).new self
end

def help_formatter_alias_defaults

def help_formatter_alias_defaults
  {
    compact: HelpFormatter::TerminalCompact,
  }
end

def initialize(args = ARGV)

def initialize(args = ARGV)
  @args, @commands, @aliases, @options = args, {}, {}, []
  @help_formatter_aliases = help_formatter_alias_defaults
  @program = program_defaults
  @always_trace = false
  @never_trace = false
  create_default_commands
end

def longest_valid_command_name_from(args)

def longest_valid_command_name_from(args)
  valid_command_names_from(*args.dup).max
end

def never_trace!

def never_trace!
  @never_trace = true
  @always_trace = false
end

def parse_global_options

def parse_global_options
  parser = options.inject(OptionParser.new) do |options, option|
    options.on(*option[:args], &global_option_proc(option[:switches], &option[:proc]))
  end
  options = @args.dup
  begin
    parser.parse!(options)
  rescue OptionParser::InvalidOption => e
    # Remove the offending args and retry.
    options = options.reject { |o| e.args.include?(o) }
    retry
  end
end

def program(key, *args, &block)

def program(key, *args, &block)
  if key == :help && !args.empty?
    @program[:help] ||= {}
    @program[:help][args.first] = args.at(1)
  elsif key == :help_formatter && !args.empty?
    @program[key] = (@help_formatter_aliases[args.first] || args.first)
  elsif block
    @program[key] = block
  else
    unless args.empty?
      @program[key] = args.count == 1 ? args[0] : args
    end
    @program[key]
  end
end

def program_defaults

def program_defaults
  {
    help_formatter: HelpFormatter::Terminal,
    name: File.basename($PROGRAM_NAME),
    help_paging: true,
  }
end

def remove_global_options(options, args)

def remove_global_options(options, args)
  options.each do |option|
    switches = option[:switches]
    next if switches.empty?
    option_takes_argument = switches.any? { |s| s =~ /[ =]/ }
    switches = expand_optionally_negative_switches(switches)
    option_argument_needs_removal = false
    args.delete_if do |token|
      break if token == '--'
      # Use just the portion of the token before the = when
      # comparing switches.
      index_of_equals = token.index('=') if option_takes_argument
      token = token[0, index_of_equals] if index_of_equals
      token_contains_option_argument = !index_of_equals.nil?
      if switches.any? { |s| s[0, token.length] == token }
        option_argument_needs_removal =
          option_takes_argument && !token_contains_option_argument
        true
      elsif option_argument_needs_removal && token !~ /^-/
        option_argument_needs_removal = false
        true
      else
        option_argument_needs_removal = false
        false
      end
    end
  end
end

def require_program(*keys)

def require_program(*keys)
  keys.each do |key|
    fail CommandError, "program #{key} required" if program(key).nil? || program(key).empty?
  end
end

def require_valid_command(command = active_command)

def require_valid_command(command = active_command)
  fail InvalidCommandError, 'invalid command', caller if command.nil?
end

def run!

def run!
  trace = @always_trace || false
  require_program :version, :description
  trap('INT') { abort program(:int_message) } if program(:int_message)
  trap('INT') { program(:int_block).call } if program(:int_block)
  global_option('-h', '--help', 'Display help documentation') do
    args = @args - %w(-h --help)
    command(:help).run(*args)
    return
  end
  global_option('-v', '--version', 'Display version information') do
    say version
    return
  end
  global_option('-t', '--trace', 'Display backtrace when an error occurs') { trace = true } unless @never_trace || @always_trace
  parse_global_options
  remove_global_options options, @args
  if trace
    run_active_command
  else
    begin
      run_active_command
    rescue InvalidCommandError => e
      abort "#{e}. Use --help for more information"
    rescue \
      OptionParser::InvalidOption,
      OptionParser::InvalidArgument,
      OptionParser::MissingArgument => e
      abort e.to_s
    rescue StandardError => e
      if @never_trace
        abort "error: #{e}."
      else
        abort "error: #{e}. Use --trace to view backtrace"
      end
    end
  end
end

def run_active_command

def run_active_command
  require_valid_command
  if alias? command_name_from_args
    active_command.run(*(@aliases[command_name_from_args.to_s] + args_without_command_name))
  else
    active_command.run(*args_without_command_name)
  end
end

def say(*args) #:nodoc:

:nodoc:
def say(*args) #:nodoc:
  HighLine.default_instance.say(*args)
end

def valid_command_names_from(*args)

def valid_command_names_from(*args)
  remove_global_options options, args
  arg_string = args.delete_if { |value| value =~ /^-/ }.join ' '
  commands.keys.find_all { |name| name if arg_string =~ /^#{name}\b/ }
end

def version

def version
  format('%s %s', program(:name), program(:version))
end