module Turbot::Command

Public Class Methods

command_aliases() click to toggle source
# File lib/turbot/command.rb, line 22
def self.command_aliases
  @@command_aliases ||= {}
end
commands() click to toggle source
# File lib/turbot/command.rb, line 18
def self.commands
  @@commands ||= {}
end
current_command() click to toggle source
# File lib/turbot/command.rb, line 42
def self.current_command
  @current_command
end
extract_error(body, options = {}) { || ... } click to toggle source
# File lib/turbot/command.rb, line 117
def self.extract_error(body, options = {})
  if block_given?
    default_error = yield
  else
    default_error = 'Internal server error'
  end
  parse_error_json(body) || default_error
end
files() click to toggle source
# File lib/turbot/command.rb, line 26
def self.files
  @@files ||= Hash.new {|hash,key| hash[key] = File.readlines(key).map {|line| line.strip}}
end
load() click to toggle source
# File lib/turbot/command.rb, line 5
def self.load
  Dir[File.join(File.dirname(__FILE__), 'command', '*.rb')].each do |file|
    require file
  end
  unregister_commands_made_private_after_the_fact
end
namespaces() click to toggle source
# File lib/turbot/command.rb, line 30
def self.namespaces
  @@namespaces ||= {}
end
parse_error_json(body) click to toggle source
# File lib/turbot/command.rb, line 126
def self.parse_error_json(body)
  begin
    JSON.load(body.to_s)['message']
  rescue JSON::ParserError
    nil
  end
end
prepare_run(cmd, args=[]) click to toggle source
# File lib/turbot/command.rb, line 59
def self.prepare_run(cmd, args=[])
  command = commands[cmd] || commands[command_aliases[cmd]]
  @current_command = cmd

  opts = {}
  invalid_options = []

  parser = OptionParser.new do |parser|
    # remove OptionParsers Officious['version'] to avoid conflicts
    # see: https://github.com/ruby/ruby/blob/6860034546808d4f67ba8f407f3d7aced0c54c5a/lib/optparse.rb#L989
    parser.base.long.delete('version')
    if command && command[:options]
      command[:options].each do |option|
        parser.on(*option[:args]) do |value|
          opts[option[:name].gsub('-', '_').to_sym] = value
          ARGV.join(' ') =~ /(#{option[:args].map {|arg| arg.split(' ', 2).first}.join('|')})/
        end
      end
    end
  end

  begin
    parser.order!(args) do |nonopt|
      invalid_options << nonopt
    end
  rescue OptionParser::InvalidOption => e
    invalid_options << e.args.first
    retry
  end

  args.concat(invalid_options)
  @invalid_arguments = invalid_options

  if command
    command_instance = command[:klass].new(args.dup, opts.dup)
    [command_instance, command[:method]]
  else
    error([
      "`#{cmd}` is not a turbot command.",
      suggestion(cmd, commands.keys + command_aliases.keys),
      'See `turbot help` for a list of available commands.'
    ].compact.join("\n"))
  end
end
register_command(command) click to toggle source
# File lib/turbot/command.rb, line 34
def self.register_command(command)
  commands[command[:command]] = command
end
register_namespace(namespace) click to toggle source
# File lib/turbot/command.rb, line 38
def self.register_namespace(namespace)
  namespaces[namespace[:name]] = namespace
end
run(command, arguments=[]) click to toggle source
# File lib/turbot/command.rb, line 104
def self.run(command, arguments=[])
  object, method = prepare_run(command, arguments.dup)
  object.send(method)
rescue SocketError => e
  error 'Unable to connect to Turbot API, please check internet connectivity and try again.'
rescue OptionParser::ParseError
  if commands[command]
    run('help', [command])
  else
    run('help')
  end
end
unregister_commands_made_private_after_the_fact() click to toggle source
# File lib/turbot/command.rb, line 12
def self.unregister_commands_made_private_after_the_fact
  commands.values.
    select { |c| c[:klass].private_method_defined? c[:method] }.
    each { |c| commands.delete(c[:command]) }
end
validate_arguments!() click to toggle source
# File lib/turbot/command.rb, line 46
def self.validate_arguments!
  unless @invalid_arguments.empty?
    arguments = @invalid_arguments.map(&:inspect)
    if arguments.length == 1
      message = "Invalid argument: #{arguments.first}"
    else
      message = "Invalid arguments: #{arguments[0...-1].join(', ')} and #{arguments[-1]}"
    end
    run('help', [current_command])
    error message
  end
end

Private Class Methods

suggestion(actual, possibilities) click to toggle source
# File lib/turbot/command.rb, line 136
def self.suggestion(actual, possibilities)
  distances = Hash.new { |hash,key| hash[key] = [] }
  possibilities.each do |possibility|
    distances[Text::Levenshtein.distance(actual, possibility, 4)] << possibility
  end
  minimum_distance = distances.keys.min
  if minimum_distance < 4
    suggestions = distances[minimum_distance].sort
    if suggestions.length == 1
      "Perhaps you meant `#{suggestions.first}`."
    else
      "Perhaps you meant #{suggestions[0...-1].map { |suggestion| "`#{suggestion}`" }.join(', ')} or `#{suggestions.last}`."
    end
  end
end