class Pry::Method

This class wraps the normal `Method` and `UnboundMethod` classes to provide extra functionality useful to Pry.

Public Class Methods

all_from_class(klass, include_super=true) click to toggle source

Get all of the instance methods of a `Class` or `Module` @param [Class,Module] klass @param [Boolean] include_super Whether to include methods from ancestors. @return [Array]

# File lib/pry/method.rb, line 135
def all_from_class(klass, include_super=true)
  all_from_common(klass, :instance_method, include_super)
end
all_from_obj(obj, include_super=true) click to toggle source

Get all of the methods on an `Object` @param [Object] obj @param [Boolean] include_super Whether to include methods from ancestors. @return [Array]

# File lib/pry/method.rb, line 143
def all_from_obj(obj, include_super=true)
  all_from_common(obj, :method, include_super)
end
from_binding(b) click to toggle source

Given a `Binding`, try to extract the `::Method` it originated from and use it to instantiate a `Pry::Method`. Return `nil` if this isn’t possible.

@param [Binding] b @return [Pry::Method, nil]

# File lib/pry/method.rb, line 63
def from_binding(b)
  meth_name = b.eval('__method__')
  if [:__script__, nil].include?(meth_name)
    nil
  else
    method = begin
               new(b.eval("Object.instance_method(:method).bind(self).call(#{meth_name.to_s.inspect})"))
             rescue NameError, NoMethodError
               Disowned.new(b.eval('self'), meth_name.to_s)
             end

    # it's possible in some cases that the method we find by this approach is a sub-method of
    # the one we're currently in, consider:
    #
    # class A; def b; binding.pry; end; end
    # class B < A; def b; super; end; end
    #
    # Given that we can normally find the source_range of methods, and that we know which
    # __FILE__ and __LINE__ the binding is at, we can hope to disambiguate these cases.
    #
    # This obviously won't work if the source is unavaiable for some reason, or if both
    # methods have the same __FILE__ and __LINE__, or if we're in rbx where b.eval('__LINE__')
    # is broken.
    #
    guess = method

    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
      if (guess.source_file && guess.source_range rescue false) &&
          File.expand_path(guess.source_file) == File.expand_path(b.eval('__FILE__')) &&
          guess.source_range.include?(b.eval('__LINE__'))
        return guess
      else
        guess = guess.super
      end
    end

    # Uhoh... none of the methods in the chain had the right __FILE__ and __LINE__
    # This may be caused by rbx https://github.com/rubinius/rubinius/issues/953,
    # or other unknown circumstances (TODO: we should warn the user when this happens)
    method
  end
end
from_class(klass, name) click to toggle source

Given a `Class` or `Module` and the name of a method, try to instantiate a `Pry::Method` containing the instance method of that name. Return `nil` if no such method exists.

@param [Class, Module] klass @param [String] name @return [Pry::Method, nil]

# File lib/pry/method.rb, line 115
def from_class(klass, name)
  new(safe_send(klass, :instance_method, name)) rescue nil
end
Also aliased as: from_module
from_module(klass, name) click to toggle source
Alias for: from_class
from_obj(obj, name) click to toggle source

Given an object and the name of a method, try to instantiate a `Pry::Method` containing the method of that name bound to that object. Return `nil` if no such method exists.

@param [Object] obj @param [String] name @return [Pry::Method, nil]

# File lib/pry/method.rb, line 127
def from_obj(obj, name)
  new(safe_send(obj, :method, name)) rescue nil
end
from_str(name, target=TOPLEVEL_BINDING, options={}) click to toggle source

Given a string representing a method name and optionally a binding to search in, find and return the requested method wrapped in a `Pry::Method` instance.

@param [String, nil] name The name of the method to retrieve, or `nil` to

delegate to `from_binding` instead.

@param [Binding] target The context in which to search for the method. @param [Hash] options @option options [Boolean] :instance Look for an instance method if `name` doesn’t

contain any context.

@option options [Boolean] :methods Look for a bound/singleton method if `name` doesn’t

contain any context.

@return [Pry::Method, nil] A `Pry::Method` instance containing the requested

method, or `nil` if no method could be located matching the parameters.
# File lib/pry/method.rb, line 37
def from_str(name, target=TOPLEVEL_BINDING, options={})
  if name.nil?
    from_binding(target)
  elsif name.to_s =~ %r(.+)\#(\S+)\Z/
    context, meth_name = $1, $2
    from_module(target.eval(context), meth_name)
  elsif name.to_s =~ %r(.+)\.(\S+)\Z/
    context, meth_name = $1, $2
    from_obj(target.eval(context), meth_name)
  elsif options[:instance]
    from_module(target.eval("self"), name)
  elsif options[:methods]
    from_obj(target.eval("self"), name)
  else
    from_str(name, target, :instance => true) or
      from_str(name, target, :methods => true)
  end
end
instance_resolution_order(klass) click to toggle source

Get every `Class` and `Module`, in order, that will be checked when looking for methods on instances of the given `Class` or `Module`. This does not treat singleton classes of classes specially. @param [Class, Module] klass @return [Array[Class, Module]]

# File lib/pry/method.rb, line 165
def instance_resolution_order(klass)
  # include klass in case it is a singleton class,
  ([klass] + klass.ancestors).uniq
end
new(method, known_info={}) click to toggle source

A new instance of `Pry::Method` wrapping the given `::Method`, `UnboundMethod`, or `Proc`.

@param [::Method, UnboundMethod, Proc] method @param [Hash] known_info Can be used to pre-cache expensive to compute stuff. @return [Pry::Method]

# File lib/pry/method.rb, line 214
def initialize(method, known_info={})
  @method = method
  @visibility = known_info[:visibility]
end
resolution_order(obj) click to toggle source

Get every `Class` and `Module`, in order, that will be checked when looking for an instance method to call on this object. @param [Object] obj @return [Array[Class, Module]]

# File lib/pry/method.rb, line 151
def resolution_order(obj)
  if Class === obj
    singleton_class_resolution_order(obj) + instance_resolution_order(Class)
  else
    klass = singleton_class(obj) rescue obj.class
    instance_resolution_order(klass)
  end
end
safe_send(obj, method, *args, &block) click to toggle source

Acts like send but ignores any methods defined below Object or Class in the inheritance hierarchy. This is required to introspect methods on objects like Net::HTTP::Get that have overridden the `method` method.

# File lib/pry/method.rb, line 189
def safe_send(obj, method, *args, &block)
  (Module === obj ? Module : Object).instance_method(method).bind(obj).call(*args, &block)
end

Public Instance Methods

==(obj) click to toggle source

@return [Boolean]

# File lib/pry/method.rb, line 411
def ==(obj)
  if obj.is_a? Pry::Method
    obj == @method
  else
    @method == obj
  end
end
alias?() click to toggle source

@return [Boolean] Is the method definitely an alias?

# File lib/pry/method.rb, line 406
def alias?
  name != original_name
end
doc() click to toggle source

@return [String, nil] The documentation for the method, or `nil` if it’s

unavailable.

@raise [CommandError] Raises when the method was defined in the REPL.

# File lib/pry/method.rb, line 281
def doc
  @doc ||= case source_type
    when :c
      info = pry_doc_info
      info.docstring if info
    when :ruby
      if Helpers::BaseHelpers.rbx? && !pry_method?
        strip_leading_hash_and_whitespace_from_ruby_comments(core_doc)
      elsif pry_method?
        strip_leading_hash_and_whitespace_from_ruby_comments(doc_for_pry_method)
      else
        strip_leading_hash_and_whitespace_from_ruby_comments(@method.comment)
      end
    end
end
dynamically_defined?() click to toggle source

@return [Boolean] Was the method defined outside a source file?

# File lib/pry/method.rb, line 396
def dynamically_defined?
  !!(source_file and source_file =~ %r(\(.*\))|<.*>/)
end
is_a?(klass) click to toggle source

@param [Class] klass @return [Boolean]

# File lib/pry/method.rb, line 421
def is_a?(klass)
  klass == Pry::Method or @method.is_a?(klass)
end
Also aliased as: kind_of?
kind_of?(klass) click to toggle source
Alias for: is_a?
method_missing(method_name, *args, &block) click to toggle source

Delegate any unknown calls to the wrapped method.

# File lib/pry/method.rb, line 433
def method_missing(method_name, *args, &block)
  @method.send(method_name, *args, &block)
end
name() click to toggle source

Get the name of the method as a String, regardless of the underlying #name type. @return [String]

# File lib/pry/method.rb, line 221
def name
  @method.name.to_s
end
name_with_owner() click to toggle source

Get the name of the method including the class on which it was defined. @example

method(:puts).method_name
=> "Kernel.puts"

@return [String]

# File lib/pry/method.rb, line 242
def name_with_owner
  "#{wrapped_owner.method_prefix}#{name}"
end
original_name() click to toggle source

@return [String, nil] The original name the method was defined under,

before any aliasing, or `nil` if it can't be determined.
# File lib/pry/method.rb, line 390
def original_name
  return nil if source_type != :ruby
  method_name_from_first_line(source.lines.first)
end
pry_method?() click to toggle source

@return [Boolean] Was the method defined within the Pry REPL?

# File lib/pry/method.rb, line 401
def pry_method?
  source_file == Pry.eval_path
end
respond_to?(method_name) click to toggle source

@param [String, Symbol] method_name @return [Boolean]

# File lib/pry/method.rb, line 428
def respond_to?(method_name)
  super or @method.respond_to?(method_name)
end
signature() click to toggle source

@return [String] A representation of the method’s signature, including its

name and parameters. Optional and "rest" parameters are marked with `*`
and block parameters with `&`. If the parameter names are unavailable,
they're given numbered names instead.
Paraphrased from `awesome_print` gem.
# File lib/pry/method.rb, line 356
def signature
  if respond_to?(:parameters)
    args = parameters.inject([]) do |arr, (type, name)|
      name ||= (type == :block ? 'block' : "arg#{arr.size + 1}")
      arr << case type
             when :req   then name.to_s
             when :opt   then "#{name}=?"
             when :rest  then "*#{name}"
             when :block then "&#{name}"
             else '?'
             end
    end
  else
    args = (1..arity.abs).map { |i| "arg#{i}" }
    args[-1] = "*#{args[-1]}" if arity < 0
  end

  "#{name}(#{args.join(', ')})"
end
source() click to toggle source

@return [String, nil] The source code of the method, or `nil` if it’s unavailable.

# File lib/pry/method.rb, line 247
def source
  @source ||= case source_type
              when :c
                info = pry_doc_info
                if info and info.source
                  code = strip_comments_from_c_code(info.source)
                end
              when :ruby
                # clone of MethodSource.source_helper that knows to use our
                # hacked version of source_location for rbx core methods, and
                # our input buffer for methods defined in (pry)
                file, line = *source_location
                raise SourceNotFoundError, "Could not locate source for #{name_with_owner}!" unless file

                begin
                  code = Pry::Code.from_file(file).expression_at(line)
                rescue SyntaxError => e
                  raise MethodSource::SourceNotFoundError.new(e.message)
                end
                strip_leading_whitespace(code)
              end
end
source?() click to toggle source

Can we get the source code for this method? @return [Boolean]

# File lib/pry/method.rb, line 272
def source?
  !!source
rescue MethodSource::SourceNotFoundError
  false
end
source_file() click to toggle source

@return [String, nil] The name of the file the method is defined in, or

`nil` if the filename is unavailable.
# File lib/pry/method.rb, line 314
def source_file
  if source_location.nil?
    if !Helpers::BaseHelpers.rbx? and source_type == :c
      info = pry_doc_info
      info.file if info
    end
  else
    source_location.first
  end
end
source_line() click to toggle source

@return [Fixnum, nil] The line of code in `#source_file` which begins

the method's definition, or `nil` if that information is unavailable.
# File lib/pry/method.rb, line 327
def source_line
  source_location.nil? ? nil : source_location.last
end
source_location() click to toggle source
# File lib/pry/method.rb, line 303
def source_location
  if @method.source_location && Helpers::BaseHelpers.rbx?
    file, line = @method.source_location
    [RbxPath.convert_path_to_full(file), line]
  else
    @method.source_location
  end
end
source_range() click to toggle source

@return [Range, nil] The range of lines in `#source_file` which contain

the method's definition, or `nil` if that information is unavailable.
# File lib/pry/method.rb, line 333
def source_range
  source_location.nil? ? nil : (source_line)..(source_line + source.lines.count - 1)
end
source_type() click to toggle source

@return [Symbol] The source type of the method. The options are

`:ruby` for Ruby methods or `:c` for methods written in C.
# File lib/pry/method.rb, line 299
def source_type
  source_location.nil? ? :c : :ruby
end
super(times=1) click to toggle source

@return [Pry::Method, nil] The wrapped method that is called when you

use "super" in the body of this method.
# File lib/pry/method.rb, line 378
def super(times=1)
  if UnboundMethod === @method
    sup = super_using_ancestors(Pry::Method.instance_resolution_order(owner), times)
  else
    sup = super_using_ancestors(Pry::Method.resolution_order(receiver), times)
    sup &&= sup.bind(receiver)
  end
  Pry::Method.new(sup) if sup
end
undefined?() click to toggle source

Is the method undefined? (aka `Disowned`) @return [Boolean] false

# File lib/pry/method.rb, line 233
def undefined?
  false
end
visibility() click to toggle source

@return [Symbol] The visibility of the method. May be `:public`,

`:protected`, or `:private`.
# File lib/pry/method.rb, line 339
def visibility
 @visibility ||= if owner.public_instance_methods.any? { |m| m.to_s == name }
                   :public
                 elsif owner.protected_instance_methods.any? { |m| m.to_s == name }
                   :protected
                 elsif owner.private_instance_methods.any? { |m| m.to_s == name }
                   :private
                 else
                   :none
                 end
end
wrapped_owner() click to toggle source

Get the owner of the method as a Pry::Module @return [Pry::Module]

# File lib/pry/method.rb, line 227
def wrapped_owner
  @wrapped_owner ||= Pry::WrappedModule.new(owner)
end