Class: Pry::Method

Inherits:
Object show all
Extended by:
Forwardable, Helpers::BaseHelpers
Includes:
CodeObject::Helpers, Helpers::BaseHelpers, Helpers::DocumentationHelpers
Defined in:
lib/pry/method.rb,
lib/pry/method/patcher.rb,
lib/pry/method/disowned.rb,
lib/pry/method/weird_method_locator.rb

Overview

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

Direct Known Subclasses

Disowned

Defined Under Namespace

Classes: Disowned, Patcher, WeirdMethodLocator

Constant Summary

Constants included from Helpers::DocumentationHelpers

Helpers::DocumentationHelpers::YARD_TAGS

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers::BaseHelpers

colorize_code, find_command, heading, highlight, not_a_real_file?, safe_send, silence_warnings, stagger_output, use_ansi_codes?

Methods included from Forwardable

def_private_delegators

Methods included from CodeObject::Helpers

#c_method?, #c_module?, #command?, #module_with_yard_docs?, #real_method_object?

Methods included from Helpers::DocumentationHelpers

get_comment_content, process_comment_markup, process_rdoc, process_yardoc, process_yardoc_tag, strip_comments_from_c_code, strip_leading_whitespace

Constructor Details

#initialize(method, known_info = {}) ⇒ Pry::Method

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

Parameters:

  • method (::Method, UnboundMethod, Proc)
  • known_info (Hash) (defaults to: {})

    Can be used to pre-cache expensive to compute stuff.



263
264
265
266
# File 'lib/pry/method.rb', line 263

def initialize(method, known_info = {})
  @method = method
  @visibility = known_info[:visibility]
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_name, *args, &block) ⇒ Object

Delegate any unknown calls to the wrapped method.



503
504
505
506
507
508
509
# File 'lib/pry/method.rb', line 503

def method_missing(method_name, *args, &block)
  if @method.respond_to?(method_name)
    @method.__send__(method_name, *args, &block)
  else
    super
  end
end

Class Method Details

.all_from_class(klass, include_super = true) ⇒ Array[Pry::Method]

Get all of the instance methods of a ‘Class` or `Module`

Parameters:

  • klass (Class, Module)
  • include_super (Boolean) (defaults to: true)

    Whether to include methods from ancestors.

Returns:



161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/pry/method.rb', line 161

def all_from_class(klass, include_super = true)
  %w[public protected private].flat_map do |visibility|
    safe_send(
      klass, :"#{visibility}_instance_methods", include_super
    ).map do |method_name|
      new(
        safe_send(klass, :instance_method, method_name),
        visibility: visibility.to_sym
      )
    end
  end
end

.all_from_obj(obj, include_super = true) ⇒ Array[Pry::Method]

Get all of the methods on an ‘Object`

Parameters:

  • obj (Object)
  • include_super (Boolean) (defaults to: true)

    indicates whether or not to include methods from ancestors.

Returns:



184
185
186
# File 'lib/pry/method.rb', line 184

def all_from_obj(obj, include_super = true)
  all_from_class(singleton_class_of(obj), include_super)
end

.from_binding(binding) ⇒ Pry::Method?

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.

Parameters:

  • binding (Binding)

Returns:



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/pry/method.rb', line 77

def from_binding(binding)
  meth_name = binding.eval('::Kernel.__method__')
  if [:__script__, nil].include?(meth_name)
    nil
  else
    method =
      begin
        if Object === binding.eval('self') # rubocop:disable Style/CaseEquality
          new(
            Kernel.instance_method(:method)
              .bind(binding.eval("self"))
              .call(meth_name)
          )
        else
          str = 'class << self; self; end' \
                '.instance_method(::Kernel.__method__).bind(self)'
          new(binding.eval(str))
        end
      rescue NameError, NoMethodError # rubocop:disable Lint/ShadowedException
        Disowned.new(binding.eval('self'), meth_name.to_s)
      end

    if WeirdMethodLocator.weird_method?(method, binding)
      WeirdMethodLocator.new(method, binding).find_method || method
    else
      method
    end
  end
end

.from_class(klass, name, target = TOPLEVEL_BINDING) ⇒ Pry::Method? Also known as: from_module

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.

Parameters:

  • klass (Class, Module)
  • name (String)
  • target (Binding) (defaults to: TOPLEVEL_BINDING)

    The binding where the method is looked up.

Returns:



136
137
138
139
140
# File 'lib/pry/method.rb', line 136

def from_class(klass, name, target = TOPLEVEL_BINDING)
  new(lookup_method_via_binding(klass, name, :instance_method, target))
rescue StandardError
  nil
end

.from_obj(obj, name, target = TOPLEVEL_BINDING) ⇒ Pry::Method?

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.

Parameters:

  • obj (Object)
  • name (String)
  • target (Binding) (defaults to: TOPLEVEL_BINDING)

    The binding where the method is looked up.

Returns:



151
152
153
154
155
# File 'lib/pry/method.rb', line 151

def from_obj(obj, name, target = TOPLEVEL_BINDING)
  new(lookup_method_via_binding(obj, name, :method, target))
rescue StandardError
  nil
end

.from_str(name, target = TOPLEVEL_BINDING, options = {}) ⇒ Pry::Method?

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.

Parameters:

  • name (String)

    The name of the method to retrieve.

  • target (Binding) (defaults to: TOPLEVEL_BINDING)

    The context in which to search for the method.

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :instance (Boolean)

    Look for an instance method if ‘name` doesn’t contain any context.

  • :methods (Boolean)

    Look for a bound/singleton method if ‘name` doesn’t contain any context.

Returns:

  • (Pry::Method, nil)

    A ‘Pry::Method` instance containing the requested method, or `nil` if name is `nil` or no method could be located matching the parameters.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/pry/method.rb', line 43

def from_str(name, target = TOPLEVEL_BINDING, options = {})
  if name.nil?
    nil
  elsif name.to_s =~ /(.+)\#(\S+)\Z/
    context = Regexp.last_match(1)
    meth_name = Regexp.last_match(2)
    from_module(target.eval(context), meth_name, target)
  elsif name.to_s =~ /(.+)(\[\])\Z/
    context = Regexp.last_match(1)
    meth_name = Regexp.last_match(2)
    from_obj(target.eval(context), meth_name, target)
  elsif name.to_s =~ /(.+)(\.|::)(\S+)\Z/
    context = Regexp.last_match(1)
    meth_name = Regexp.last_match(3)
    from_obj(target.eval(context), meth_name, target)
  elsif options[:instance]
    from_module(target.eval("self"), name, target)
  elsif options[:methods]
    from_obj(target.eval("self"), name, target)
  else
    from_str(name, target, instance: true) ||
      from_str(name, target, methods: true)
  end
rescue Pry::RescuableException
  nil
end

.instance_method_definition?(name, definition_line) ⇒ Boolean

Returns:

  • (Boolean)


227
228
229
230
231
232
# File 'lib/pry/method.rb', line 227

def instance_method_definition?(name, definition_line)
  regexp =
    /^define_method\(?\s*[:\"\']#{Regexp.escape(name)}|
     ^def\s*#{Regexp.escape(name)}/x
  regexp =~ definition_line.strip
end

.instance_resolution_order(klass) ⇒ Array[Class, Module]

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.

Parameters:

  • klass (Class, Module)

Returns:

  • (Array[Class, Module])


210
211
212
213
# File 'lib/pry/method.rb', line 210

def instance_resolution_order(klass)
  # include klass in case it is a singleton class,
  ([klass] + Pry::Method.safe_send(klass, :ancestors)).uniq
end

.lookup_method_via_binding(obj, method_name, method_type, target = TOPLEVEL_BINDING) ⇒ Method, UnboundMethod

In order to support 2.0 Refinements we need to look up methods inside the relevant Binding.

Parameters:

  • obj (Object)

    The owner/receiver of the method.

  • method_name (Symbol)

    The name of the method.

  • method_type (Symbol)

    The type of method: :method or :instance_method

  • target (Binding) (defaults to: TOPLEVEL_BINDING)

    The binding where the method is looked up.

Returns:

  • (Method, UnboundMethod)

    The ‘refined’ method object.



114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/pry/method.rb', line 114

def lookup_method_via_binding(
  obj, method_name, method_type, target = TOPLEVEL_BINDING
)
  Pry.current[:obj] = obj
  Pry.current[:name] = method_name
  receiver = obj.is_a?(Module) ? "Module" : "Kernel"
  target.eval(
    "::#{receiver}.instance_method(:#{method_type})" \
    ".bind(Pry.current[:obj]).call(Pry.current[:name])"
  )
ensure
  Pry.current[:obj] = Pry.current[:name] = nil
end

.method_definition?(name, definition_line) ⇒ Boolean

Returns:

  • (Boolean)


215
216
217
218
# File 'lib/pry/method.rb', line 215

def method_definition?(name, definition_line)
  singleton_method_definition?(name, definition_line) ||
    instance_method_definition?(name, definition_line)
end

.resolution_order(obj) ⇒ Array[Class, Module]

Get every ‘Class` and `Module`, in order, that will be checked when looking for an instance method to call on this object.

Parameters:

Returns:

  • (Array[Class, Module])


192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/pry/method.rb', line 192

def resolution_order(obj)
  if Class === obj # rubocop:disable Style/CaseEquality
    singleton_class_resolution_order(obj) + instance_resolution_order(Class)
  else
    klass = begin
              singleton_class_of(obj)
            rescue StandardError
              obj.class
            end
    instance_resolution_order(klass)
  end
end

.singleton_class_of(obj) ⇒ Object



247
248
249
250
251
# File 'lib/pry/method.rb', line 247

def singleton_class_of(obj)
  class << obj; self; end
rescue TypeError # can't define singleton. Fixnum, Symbol, Float, ...
  obj.class
end

.singleton_class_resolution_order(klass) ⇒ Object

Get the singleton classes of superclasses that could define methods on the given class object, and any modules they include. If a module is included at multiple points in the ancestry, only the lowest copy will be returned.



238
239
240
241
242
243
244
245
# File 'lib/pry/method.rb', line 238

def singleton_class_resolution_order(klass)
  ancestors = Pry::Method.safe_send(klass, :ancestors)
  resolution_order = ancestors.grep(Class).flat_map do |anc|
    [singleton_class_of(anc), *singleton_class_of(anc).included_modules]
  end

  resolution_order.reverse.uniq.reverse - Class.included_modules
end

.singleton_method_definition?(name, definition_line) ⇒ Boolean

Returns:

  • (Boolean)


220
221
222
223
224
225
# File 'lib/pry/method.rb', line 220

def singleton_method_definition?(name, definition_line)
  regexp =
    /^define_singleton_method\(?\s*[:\"\']#{Regexp.escape(name)}|
     ^def\s*self\.#{Regexp.escape(name)}/x
  regexp =~ definition_line.strip
end

Instance Method Details

#==(other) ⇒ Boolean

Returns:

  • (Boolean)


483
484
485
486
487
# File 'lib/pry/method.rb', line 483

def ==(other)
  return other == @method if other.is_a?(Pry::Method)

  @method == other
end

#alias?Boolean

Returns Is the method definitely an alias?.

Returns:

  • (Boolean)

    Is the method definitely an alias?



478
479
480
# File 'lib/pry/method.rb', line 478

def alias?
  name != original_name
end

#aliasesArray<String>

Returns All known aliases for the method.

Returns:

  • (Array<String>)

    All known aliases for the method.



461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
# File 'lib/pry/method.rb', line 461

def aliases
  owner = @method.owner
  # Avoid using `to_sym` on {Method#name}, which returns a `String`, because
  # it won't be garbage collected.
  name = @method.name

  all_methods_to_compare = owner.instance_methods | owner.private_instance_methods
  alias_list = all_methods_to_compare.combination(2).select do |pair|
    pair.include?(name) &&
      owner.instance_method(pair.first) == owner.instance_method(pair.last)
  end.flatten
  alias_list.delete(name)

  alias_list.map(&:to_s)
end

#bound_method?Boolean

Returns Whether the method is bound.

Returns:

  • (Boolean)

    Whether the method is bound.



446
447
448
# File 'lib/pry/method.rb', line 446

def bound_method?
  is_a?(::Method)
end

#commentObject



515
516
517
# File 'lib/pry/method.rb', line 515

def comment
  Pry::Code.from_file(source_file).comment_describing(source_line)
end

#docString?

Returns The documentation for the method, or ‘nil` if it’s unavailable.

Returns:

  • (String, nil)

    The documentation for the method, or ‘nil` if it’s unavailable.



329
330
331
332
333
334
335
336
337
338
# File 'lib/pry/method.rb', line 329

def doc
  @doc ||=
    case source_type
    when :c
      info = pry_doc_info
      info.docstring if info
    when :ruby
      get_comment_content(comment)
    end
end

#dynamically_defined?Boolean

Returns Was the method defined outside a source file?.

Returns:

  • (Boolean)

    Was the method defined outside a source file?



436
437
438
# File 'lib/pry/method.rb', line 436

def dynamically_defined?
  !!(source_file && source_file =~ /(\(.*\))|<.*>/)
end

#is_a?(klass) ⇒ Boolean Also known as: kind_of?

Parameters:

  • klass (Class)

Returns:

  • (Boolean)


491
492
493
# File 'lib/pry/method.rb', line 491

def is_a?(klass)
  (klass == Pry::Method) || @method.is_a?(klass)
end

#nameString

Get the name of the method as a String, regardless of the underlying Method#name type.

Returns:

  • (String)


272
273
274
# File 'lib/pry/method.rb', line 272

def name
  @method.name.to_s
end

#name_with_ownerString

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

Examples:

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

Returns:

  • (String)


299
300
301
# File 'lib/pry/method.rb', line 299

def name_with_owner
  "#{wrapped_owner.method_prefix}#{name}"
end

#original_nameString?

Returns The original name the method was defined under, before any aliasing, or ‘nil` if it can’t be determined.

Returns:

  • (String, nil)

    The original name the method was defined under, before any aliasing, or ‘nil` if it can’t be determined.



429
430
431
432
433
# File 'lib/pry/method.rb', line 429

def original_name
  return nil if source_type != :ruby

  method_name_from_first_line(source.lines.first)
end

#pry_method?Boolean

Returns Was the method defined within the Pry REPL?.

Returns:

  • (Boolean)

    Was the method defined within the Pry REPL?



456
457
458
# File 'lib/pry/method.rb', line 456

def pry_method?
  source_file == Pry.eval_path
end

#redefine(source) ⇒ Object

Update the live copy of the method’s source.



314
315
316
317
# File 'lib/pry/method.rb', line 314

def redefine(source)
  Patcher.new(self).patch_in_ram source
  Pry::Method(owner.instance_method(name))
end

#respond_to?(method_name, include_all = false) ⇒ Boolean

Parameters:

  • method_name (String, Symbol)

Returns:

  • (Boolean)


498
499
500
# File 'lib/pry/method.rb', line 498

def respond_to?(method_name, include_all = false)
  super || @method.respond_to?(method_name, include_all)
end

#respond_to_missing?(method_name, include_private = false) ⇒ Boolean

Returns:

  • (Boolean)


511
512
513
# File 'lib/pry/method.rb', line 511

def respond_to_missing?(method_name, include_private = false)
  @method.respond_to?(method_name) || super
end

#signatureString

Returns A representation of the method’s signature, including its name and parameters. Optional and “rest” parameters are marked with ‘*` and block parameters with `&`. Keyword arguments are shown with `:` If the parameter names are unavailable, they’re given numbered names instead. Paraphrased from ‘awesome_print` gem.

Returns:

  • (String)

    A representation of the method’s signature, including its name and parameters. Optional and “rest” parameters are marked with ‘*` and block parameters with `&`. Keyword arguments are shown with `:` If the parameter names are unavailable, they’re given numbered names instead. Paraphrased from ‘awesome_print` gem.



391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
# File 'lib/pry/method.rb', line 391

def signature
  if respond_to?(:parameters)
    args = parameters.inject([]) do |args_array, (arg_type, name)|
      name ||= (arg_type == :block ? 'block' : "arg#{args_array.size + 1}")
      args_array.push(
        case arg_type
        when :req    then name.to_s
        when :opt    then "#{name}=?"
        when :rest   then "*#{name}"
        when :block  then "&#{name}"
        when :key    then "#{name}:?"
        when :keyreq 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

#singleton_method?Boolean

Returns Whether the method is a singleton method.

Returns:

  • (Boolean)

    Whether the method is a singleton method.



451
452
453
# File 'lib/pry/method.rb', line 451

def singleton_method?
  wrapped_owner.singleton_class?
end

#sourceString?

Returns The source code of the method, or ‘nil` if it’s unavailable.

Returns:

  • (String, nil)

    The source code of the method, or ‘nil` if it’s unavailable.



304
305
306
307
308
309
310
311
# File 'lib/pry/method.rb', line 304

def source
  @source ||= case source_type
              when :c
                c_source
              when :ruby
                ruby_source
              end
end

#source?Boolean

Can we get the source code for this method?

Returns:

  • (Boolean)


321
322
323
324
325
# File 'lib/pry/method.rb', line 321

def source?
  !!source
rescue MethodSource::SourceNotFoundError
  false
end

#source_fileString?

Returns The name of the file the method is defined in, or ‘nil` if the filename is unavailable.

Returns:

  • (String, nil)

    The name of the file the method is defined in, or ‘nil` if the filename is unavailable.



348
349
350
351
352
353
354
355
356
357
# File 'lib/pry/method.rb', line 348

def source_file
  if source_location.nil?
    if source_type == :c
      info = pry_doc_info
      info.file if info
    end
  else
    source_location.first
  end
end

#source_lineFixnum?

Returns The line of code in ‘source_file` which begins the method’s definition, or ‘nil` if that information is unavailable.

Returns:

  • (Fixnum, nil)

    The line of code in ‘source_file` which begins the method’s definition, or ‘nil` if that information is unavailable.



361
362
363
# File 'lib/pry/method.rb', line 361

def source_line
  source_location.nil? ? nil : source_location.last
end

#source_rangeRange?

Returns The range of lines in ‘source_file` which contain the method’s definition, or ‘nil` if that information is unavailable.

Returns:

  • (Range, nil)

    The range of lines in ‘source_file` which contain the method’s definition, or ‘nil` if that information is unavailable.



367
368
369
# File 'lib/pry/method.rb', line 367

def source_range
  source_location.nil? ? nil : (source_line)..(source_line + source.lines.count - 1)
end

#source_typeSymbol

Returns The source type of the method. The options are ‘:ruby` for Ruby methods or `:c` for methods written in C.

Returns:

  • (Symbol)

    The source type of the method. The options are ‘:ruby` for Ruby methods or `:c` for methods written in C.



342
343
344
# File 'lib/pry/method.rb', line 342

def source_type
  source_location.nil? ? :c : :ruby
end

#super(times = 1) ⇒ Pry::Method?

Returns The wrapped method that is called when you use “super” in the body of this method.

Returns:

  • (Pry::Method, nil)

    The wrapped method that is called when you use “super” in the body of this method.



417
418
419
420
421
422
423
424
425
# File 'lib/pry/method.rb', line 417

def super(times = 1)
  if @method.is_a?(UnboundMethod)
    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

#unbound_method?Boolean

Returns Whether the method is unbound.

Returns:

  • (Boolean)

    Whether the method is unbound.



441
442
443
# File 'lib/pry/method.rb', line 441

def unbound_method?
  is_a?(::UnboundMethod)
end

#undefined?Boolean

Is the method undefined? (aka ‘Disowned`)

Returns:

  • (Boolean)

    false



290
291
292
# File 'lib/pry/method.rb', line 290

def undefined?
  false
end

#visibilitySymbol

Returns The visibility of the method. May be ‘:public`, `:protected`, or `:private`.

Returns:

  • (Symbol)

    The visibility of the method. May be ‘:public`, `:protected`, or `:private`.



373
374
375
376
377
378
379
380
381
382
383
384
# File 'lib/pry/method.rb', line 373

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

#wrappedMethod, ...

Get underlying object wrapped by this Pry::Method instance

Returns:

  • (Method, UnboundMethod, Proc)


284
285
286
# File 'lib/pry/method.rb', line 284

def wrapped
  @method
end

#wrapped_ownerPry::Module

Get the owner of the method as a Pry::Module

Returns:

  • (Pry::Module)


278
279
280
# File 'lib/pry/method.rb', line 278

def wrapped_owner
  @wrapped_owner ||= Pry::WrappedModule.new(owner)
end