class Pry::Method::WeirdMethodLocator

Pry::Method and return it, or return nil if we fail.
When we locate the method that matches the Binding we wrap it in
method table.
inheritance chain, and for 2. we search laterally along the object’s
was renamed to something else. For 1. we search vertically up the
2. The Pry::Method represents a method of the same name while the original
1. The Pry::Method is from a subclass
the Binding:
there are primarily two situations where the seed method doesn’t match
Given a ‘Binding` from inside a method and a ’seed’ Pry::Method object,
object captured by a binding.
This class is responsible for locating the real ‘Pry::Method`

def all_methods_for(obj)

def all_methods_for(obj)
  obj.public_methods(false) +
    obj.private_methods(false) +
    obj.protected_methods(false)
end

def expanded_source_location(source_location)

def expanded_source_location(source_location)
  return unless source_location
  if pry_file?
    source_location
  else
    [File.expand_path(source_location.first), source_location.last]
  end
end

def find_method

Returns:
  • (Pry::Method, nil) - The Pry::Method that matches the
def find_method
  find_method_in_superclass || find_renamed_method
end

def find_method_in_superclass

Returns:
  • (Pry::Method, nil) - The Pry::Method representing the
def find_method_in_superclass
  guess = method
  return guess if skip_superclass_search?
  while guess
    # needs rescue if this is a Disowned method or a C method or something...
    # TODO: Fix up the exception handling so we don't need a bare rescue
    return guess if normal_method?(guess)
    break if guess == guess.super
    guess = guess.super
  end
  # Uhoh... none of the methods in the chain had the right `__FILE__` and
  # `__LINE__` due to unknown circumstances.
  # TODO: we should warn the user when this happens.
  nil
end

def find_renamed_method

Returns:
  • (Pry::Method, nil) - The Pry::Method representing the
def find_renamed_method
  return unless valid_file?(target_file)
  alias_name = all_methods_for(target_self).find do |v|
    location = target_self.method(v).source_location
    location && expanded_source_location(location) == renamed_method_source_location
  end
  alias_name && Pry::Method(target_self.method(alias_name))
end

def index_to_line_number(index)

def index_to_line_number(index)
  # Pry.line_buffer is 0-indexed
  pry_file? ? index : index + 1
end

def initialize(method, target)

Parameters:
  • target (Binding) -- The Binding that captures the method
  • method (Pry::Method) -- The seed method.
def initialize(method, target)
  @method = method
  @target = target
end

def lines_for_file(file)

def lines_for_file(file)
  @lines_for_file ||= {}
  @lines_for_file[file] ||= if Pry.eval_path == file
                              Pry.line_buffer
                            else
                              File.readlines(file)
                            end
end

def lost_method?

Returns:
  • (Boolean) - Whether the Pry::Method is unrecoverable
def lost_method?
  !!(find_method.nil? && renamed_method_source_location)
end

def normal_method?(method, binding)

Returns:
  • (Boolean) -

Parameters:
  • binding (Binding) --
  • method (Pry::Method) --
def normal_method?(method, binding)
  if method && method.source_file && method.source_range
    if binding.respond_to?(:source_location)
      binding_file, binding_line = binding.source_location
    else
      binding_file = binding.eval('__FILE__')
      binding_line = binding.eval('__LINE__')
    end
    (File.expand_path(method.source_file) == File.expand_path(binding_file)) &&
      method.source_range.include?(binding_line)
  end
rescue StandardError
  false
end

def normal_method?(method)

def normal_method?(method)
  self.class.normal_method?(method, target)
end

def pry_file?

def pry_file?
  file =
    if target.respond_to?(:source_location)
      target.source_location.first
    else
      target.eval('__FILE__')
    end
  Pry.eval_path == file
end

def renamed_method_source_location

Returns:
  • (Array) - The `source_location` of the
def renamed_method_source_location
  if defined?(@original_method_source_location)
    return @original_method_source_location
  end
  source_index = lines_for_file(target_file)[0..(target_line - 1)].rindex do |v|
    Pry::Method.method_definition?(method.name, v)
  end
  @original_method_source_location =
    source_index && [target_file, index_to_line_number(source_index)]
end

def skip_superclass_search?

def skip_superclass_search?
  target_mod = @target.eval('self').class
  target_mod.ancestors.take_while { |mod| mod != target_mod }.any?
end

def target_file

def target_file
  file =
    if target.respond_to?(:source_location)
      target.source_location.first
    else
      target.eval('__FILE__')
    end
  pry_file? ? file : File.expand_path(file)
end

def target_line

def target_line
  if target.respond_to?(:source_location)
    target.source_location.last
  else
    target.eval('__LINE__')
  end
end

def target_self

def target_self
  target.eval('self')
end

def valid_file?(file)

def valid_file?(file)
  (File.exist?(file) && !File.directory?(file)) || Pry.eval_path == file
end

def weird_method?(method, binding)

def weird_method?(method, binding)
  !normal_method?(method, binding)
end