Class: Pry::Method

Inherits:
Object show all
Extended by:
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

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Helpers::BaseHelpers

colorize_code, command_dependencies_met?, find_command, heading, highlight, jruby?, jruby_19?, mri?, mri_19?, mri_20?, mri_21?, mri_2?, not_a_real_file?, rbx?, safe_send, safe_send, silence_warnings, stagger_output, use_ansi_codes?, windows?, windows_ansi?

Methods included from CodeObject::Helpers

#c_method?, #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`.


236
237
238
239
# File 'lib/pry/method.rb', line 236

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.


469
470
471
# File 'lib/pry/method.rb', line 469

def method_missing(method_name, *args, &block)
  @method.send(method_name, *args, &block)
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`


142
143
144
145
146
147
148
# File 'lib/pry/method.rb', line 142

def all_from_class(klass, include_super=true)
  %w(public protected private).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.flatten(1)
end

.all_from_common(obj, method_type = nil, include_super = true) ⇒ Object

Deprecated.

please use #all_from_obj instead. the `method_type` argument is ignored.


169
170
171
# File 'lib/pry/method.rb', line 169

def all_from_common(obj, method_type = nil, include_super=true)
  all_from_obj(obj, include_super)
end

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

Get all of the methods on an `Object`


160
161
162
# File 'lib/pry/method.rb', line 160

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

.from_binding(b) ⇒ 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.


74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/pry/method.rb', line 74

def from_binding(b)
  meth_name = b.eval('::Kernel.__method__')
  if [:__script__, nil].include?(meth_name)
    nil
  else
    method = begin
               if Object === b.eval('self')
                 new(Kernel.instance_method(:method).bind(b.eval("self")).call(meth_name))
               else
                 new(b.eval('class << self; self; end.instance_method(::Kernel.__method__).bind(self)'))
               end
             rescue NameError, NoMethodError
               Disowned.new(b.eval('self'), meth_name.to_s)
             end

    if WeirdMethodLocator.weird_method?(method, b)
      WeirdMethodLocator.new(method, b).get_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.


121
122
123
# File 'lib/pry/method.rb', line 121

def from_class(klass, name, target=TOPLEVEL_BINDING)
  new(lookup_method_via_binding(klass, name, :instance_method, target)) rescue 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.


134
135
136
# File 'lib/pry/method.rb', line 134

def from_obj(obj, name, target=TOPLEVEL_BINDING)
  new(lookup_method_via_binding(obj, name, :method, target)) rescue 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.

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.


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

def from_str(name, target=TOPLEVEL_BINDING, options={})
  if name.nil?
    nil
  elsif name.to_s =~ /(.+)\#(\S+)\Z/
    context, meth_name = $1, $2
    from_module(target.eval(context), meth_name, target)
  elsif name.to_s =~ /(.+)(\[\])\Z/
    context, meth_name = $1, $2
    from_obj(target.eval(context), meth_name, target)
  elsif name.to_s =~ /(.+)(\.|::)(\S+)\Z/
    context, meth_name = $1, $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) or
      from_str(name, target, :methods => true)
  end

rescue Pry::RescuableException
  nil
end

.instance_method_definition?(name, definition_line) ⇒ Boolean


205
206
207
# File 'lib/pry/method.rb', line 205

def instance_method_definition?(name, definition_line)
  /^define_method\(?\s*[:\"\']#{Regexp.escape(name)}|^def\s*#{Regexp.escape(name)}/ =~ 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.


191
192
193
194
# File 'lib/pry/method.rb', line 191

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.


104
105
106
107
108
109
110
111
# File 'lib/pry/method.rb', line 104

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


196
197
198
199
# File 'lib/pry/method.rb', line 196

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.


177
178
179
180
181
182
183
184
# File 'lib/pry/method.rb', line 177

def resolution_order(obj)
  if Class === obj
    singleton_class_resolution_order(obj) + instance_resolution_order(Class)
  else
    klass = singleton_class_of(obj) rescue obj.class
    instance_resolution_order(klass)
  end
end

.singleton_class_of(obj) ⇒ Object


222
223
224
225
226
227
228
# File 'lib/pry/method.rb', line 222

def singleton_class_of(obj)
  begin
    class << obj; self; end
  rescue TypeError # can't define singleton. Fixnum, Symbol, Float, ...
    obj.class
  end
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.


213
214
215
216
217
218
219
220
# File 'lib/pry/method.rb', line 213

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

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

.singleton_method_definition?(name, definition_line) ⇒ Boolean


201
202
203
# File 'lib/pry/method.rb', line 201

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

Instance Method Details

#==(obj) ⇒ Boolean


447
448
449
450
451
452
453
# File 'lib/pry/method.rb', line 447

def ==(obj)
  if obj.is_a? Pry::Method
    obj == @method
  else
    @method == obj
  end
end

#alias?Boolean


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

def alias?
  name != original_name
end

#aliasesArray<String>


425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
# File 'lib/pry/method.rb', line 425

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


410
411
412
# File 'lib/pry/method.rb', line 410

def bound_method?
  is_a?(::Method)
end

#commentObject


473
474
475
# File 'lib/pry/method.rb', line 473

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

#docString?


300
301
302
303
304
305
306
307
308
# File 'lib/pry/method.rb', line 300

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


400
401
402
# File 'lib/pry/method.rb', line 400

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

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


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

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

#nameString

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


243
244
245
# File 'lib/pry/method.rb', line 243

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"

270
271
272
# File 'lib/pry/method.rb', line 270

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

#original_nameString?


394
395
396
397
# File 'lib/pry/method.rb', line 394

def original_name
  return nil if source_type != :ruby
  method_name_from_first_line(source.lines.first)
end

#pry_method?Boolean


420
421
422
# File 'lib/pry/method.rb', line 420

def pry_method?
  source_file == Pry.eval_path
end

#redefine(source) ⇒ Object

Update the live copy of the method's source.


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

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

#respond_to?(method_name) ⇒ Boolean


464
465
466
# File 'lib/pry/method.rb', line 464

def respond_to?(method_name)
  super or @method.respond_to?(method_name)
end

#signatureString


360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
# File 'lib/pry/method.rb', line 360

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

#singleton_method?Boolean


415
416
417
# File 'lib/pry/method.rb', line 415

def singleton_method?
  wrapped_owner.singleton_class?
end

#sourceString?


275
276
277
278
279
280
281
282
# File 'lib/pry/method.rb', line 275

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?


292
293
294
295
296
# File 'lib/pry/method.rb', line 292

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

#source_fileString?


318
319
320
321
322
323
324
325
326
327
# File 'lib/pry/method.rb', line 318

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

#source_lineFixnum?


331
332
333
# File 'lib/pry/method.rb', line 331

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

#source_rangeRange?


337
338
339
# File 'lib/pry/method.rb', line 337

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

#source_typeSymbol


312
313
314
# File 'lib/pry/method.rb', line 312

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

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


382
383
384
385
386
387
388
389
390
# File 'lib/pry/method.rb', line 382

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

#unbound_method?Boolean


405
406
407
# File 'lib/pry/method.rb', line 405

def unbound_method?
  is_a?(::UnboundMethod)
end

#undefined?Boolean

Is the method undefined? (aka `Disowned`)


261
262
263
# File 'lib/pry/method.rb', line 261

def undefined?
  false
end

#visibilitySymbol


343
344
345
346
347
348
349
350
351
352
353
# File 'lib/pry/method.rb', line 343

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


255
256
257
# File 'lib/pry/method.rb', line 255

def wrapped
  @method
end

#wrapped_ownerPry::Module

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


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

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