class Pry::InputCompleter

def build_path(input)

path is a proc that takes an input and builds a full path.
input is the partial string that should be completed
build_path seperates the input into two parts: path and input.
def build_path(input)
  # check to see if the input is a regex
  return proc { |i| i.to_s }, input if input[%r{/\.}]
  trailing_slash = input.end_with?('/')
  contexts = input.chomp('/').split(%r{/})
  input = contexts[-1]
  path = proc do |i|
    p = contexts[0..-2].push(i).join('/')
    p += '/' if trailing_slash && !i.nil?
    p
  end
  [path, input]
end

def call(str, options = {})

rubocop:disable Metrics/AbcSize, Metrics/MethodLength
Return a new completion proc for use by Readline.
def call(str, options = {})
  custom_completions = options[:custom_completions] || []
  # if there are multiple contexts e.g. cd 1/2/3
  # get new target for 1/2 and find candidates for 3
  path, input = build_path(str)
  if path.call.empty?
    target = options[:target]
  else
    # Assume the user is tab-completing the 'cd' command
    begin
      target = Pry::ObjectPath.new(path.call, @pry.binding_stack).resolve.last
    # but if that doesn't work, assume they're doing division with no spaces
    rescue Pry::CommandError
      target = options[:target]
    end
  end
  begin
    bind = target
    # Complete stdlib symbols
    case input
    when REGEX_REGEXP # Regexp
      receiver = Regexp.last_match(1)
      message = Regexp.quote(Regexp.last_match(2))
      candidates = Regexp.instance_methods.collect(&:to_s)
      select_message(path, receiver, message, candidates)
    when ARRAY_REGEXP # Array
      receiver = Regexp.last_match(1)
      message = Regexp.quote(Regexp.last_match(2))
      candidates = Array.instance_methods.collect(&:to_s)
      select_message(path, receiver, message, candidates)
    when PROC_OR_HASH_REGEXP # Proc or Hash
      receiver = Regexp.last_match(1)
      message = Regexp.quote(Regexp.last_match(2))
      candidates = Proc.instance_methods.collect(&:to_s)
      candidates |= Hash.instance_methods.collect(&:to_s)
      select_message(path, receiver, message, candidates)
    when SYMBOL_REGEXP # Symbol
      if Symbol.respond_to?(:all_symbols)
        sym = Regexp.quote(Regexp.last_match(1))
        candidates = Symbol.all_symbols.collect { |s| ":" + s.id2name }
        candidates.grep(/^#{sym}/)
      else
        []
      end
    when TOPLEVEL_LOOKUP_REGEXP # Absolute Constant or class methods
      receiver = Regexp.last_match(1)
      candidates = Object.constants.collect(&:to_s)
      candidates.grep(/^#{receiver}/).collect { |e| "::" + e }
    when CONSTANT_REGEXP # Constant
      message = Regexp.last_match(1)
      begin
        context = target.eval("self")
        context = context.class unless context.respond_to? :constants
        candidates = context.constants.collect(&:to_s)
      rescue StandardError
        candidates = []
      end
      candidates = candidates.grep(/^#{message}/).collect(&path)
    when CONSTANT_OR_METHOD_REGEXP # Constant or class methods
      receiver = Regexp.last_match(1)
      message = Regexp.quote(Regexp.last_match(2))
      begin
        candidates = eval( # rubocop:disable Security/Eval
          "#{receiver}.constants.collect(&:to_s)", bind, __FILE__, __LINE__
        )
        candidates |= eval( # rubocop:disable Security/Eval
          "#{receiver}.methods.collect(&:to_s)", bind, __FILE__, __LINE__
        )
      rescue Pry::RescuableException
        candidates = []
      end
      candidates.grep(/^#{message}/).collect { |e| receiver + "::" + e }
    when SYMBOL_METHOD_CALL_REGEXP # method call on a Symbol
      receiver = Regexp.last_match(1)
      message = Regexp.quote(Regexp.last_match(2))
      candidates = Symbol.instance_methods.collect(&:to_s)
      select_message(path, receiver, message, candidates)
    when NUMERIC_REGEXP
      # Numeric
      receiver = Regexp.last_match(1)
      message = Regexp.quote(Regexp.last_match(5))
      begin
        # rubocop:disable Security/Eval
        candidates = eval(receiver, bind).methods.collect(&:to_s)
        # rubocop:enable Security/Eval
      rescue Pry::RescuableException
        candidates = []
      end
      select_message(path, receiver, message, candidates)
    when HEX_REGEXP
      # Numeric(0xFFFF)
      receiver = Regexp.last_match(1)
      message = Regexp.quote(Regexp.last_match(2))
      begin
        # rubocop:disable Security/Eval
        candidates = eval(receiver, bind).methods.collect(&:to_s)
        # rubocop:enable Security/Eval
      rescue Pry::RescuableException
        candidates = []
      end
      select_message(path, receiver, message, candidates)
    when GLOBALVARIABLE_REGEXP # global
      regmessage = Regexp.new(Regexp.quote(Regexp.last_match(1)))
      candidates = global_variables.collect(&:to_s).grep(regmessage)
    when VARIABLE_REGEXP # variable
      receiver = Regexp.last_match(1)
      message = Regexp.quote(Regexp.last_match(2))
      gv = eval("global_variables", bind, __FILE__, __LINE__).collect(&:to_s)
      lv = eval("local_variables", bind, __FILE__, __LINE__).collect(&:to_s)
      cv = eval("self.class.constants", bind, __FILE__, __LINE__).collect(&:to_s)
      if (gv | lv | cv).include?(receiver) || /^[A-Z]/ =~ receiver && /\./ !~ receiver
        # foo.func and foo is local var. OR
        # Foo::Bar.func
        begin
          candidates = eval( # rubocop:disable Security/Eval
            "#{receiver}.methods", bind, __FILE__, __LINE__
          ).collect(&:to_s)
        rescue Pry::RescuableException
          candidates = []
        end
      else
        # func1.func2
        require 'set'
        candidates = Set.new
        to_ignore = ignored_modules
        ObjectSpace.each_object(Module) do |m|
          next if begin
                    to_ignore.include?(m)
                  rescue StandardError
                    true
                  end
          # jruby doesn't always provide #instance_methods() on each
          # object.
          if m.respond_to?(:instance_methods)
            candidates.merge m.instance_methods(false).collect(&:to_s)
          end
        end
      end
      select_message(path, receiver, message, candidates.sort)
    when /^\.([^.]*)$/
      # Unknown(maybe String)
      receiver = ""
      message = Regexp.quote(Regexp.last_match(1))
      candidates = String.instance_methods(true).collect(&:to_s)
      select_message(path, receiver, message, candidates)
    else
      candidates = eval(
        "methods | private_methods | local_variables | " \
        "self.class.constants | instance_variables",
        bind, __FILE__, __LINE__ - 2
      ).collect(&:to_s)
      if eval("respond_to?(:class_variables)", bind, __FILE__, __LINE__)
        candidates += eval(
          "class_variables", bind, __FILE__, __LINE__
        ).collect(&:to_s)
      end
      candidates =
        (candidates | RESERVED_WORDS | custom_completions)
          .grep(/^#{Regexp.quote(input)}/)
      candidates.collect(&path)
    end
  rescue Pry::RescuableException
    []
  end
end

def ignored_modules

def ignored_modules
  # We could cache the result, but IRB is not loaded by default.
  # And this is very fast anyway.
  # By using this approach, we avoid Module#name calls, which are
  # relatively slow when there are a lot of anonymous modules defined.
  s = Set.new
  scanner = lambda do |m|
    next if s.include?(m) # IRB::ExtendCommandBundle::EXCB recurses.
    s << m
    m.constants(false).each do |c|
      value = m.const_get(c)
      scanner.call(value) if value.is_a?(Module)
    end
  end
  # FIXME: Add Pry here as well?
  %i[IRB SLex RubyLex RubyToken].each do |module_name|
    next unless Object.const_defined?(module_name)
    scanner.call(Object.const_get(module_name))
  end
  s.delete(IRB::Context) if defined?(IRB::Context)
  s
end

def initialize(input, pry = nil)

def initialize(input, pry = nil)
  @pry = pry
  @input = input
  if @input.respond_to?(:basic_word_break_characters=)
    @input.basic_word_break_characters = WORD_ESCAPE_STR
  end
  return unless @input.respond_to?(:completion_append_character=)
  @input.completion_append_character = nil
end

def select_message(path, receiver, message, candidates)

def select_message(path, receiver, message, candidates)
  candidates.grep(/^#{message}/).collect do |e|
    next unless e =~ /^[a-zA-Z_]/
    path.call(receiver + "." + e)
  end.compact
end