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, colorize_code, command_dependencies_met?, command_dependencies_met?, context_from_object_path, context_from_object_path, find_command, find_command, heading, heading, highlight, highlight, jruby?, jruby?, jruby_19?, jruby_19?, mri?, mri?, mri_19?, mri_19?, mri_20?, mri_20?, mri_21?, mri_21?, not_a_real_file?, not_a_real_file?, rbx?, rbx?, safe_send, safe_send, silence_warnings, silence_warnings, stagger_output, stagger_output, use_ansi_codes?, use_ansi_codes?, windows?, windows?, windows_ansi?, 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, get_comment_content, process_comment_markup, #process_comment_markup, #process_rdoc, process_rdoc, #process_yardoc, process_yardoc, process_yardoc_tag, #process_yardoc_tag, #strip_comments_from_c_code, strip_comments_from_c_code, #strip_leading_whitespace, strip_leading_whitespace

Constructor Details

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

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



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

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

- (Object) method_missing(method_name, *args, &block)

Delegate any unknown calls to the wrapped method.



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

def method_missing(method_name, *args, &block)
  @method.send(method_name, *args, &block)
end

Class Method Details

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

Get all of the instance methods of a Class or Module



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

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

+ (Object) all_from_common(obj, method_type = nil, include_super = true)

Deprecated.

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



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

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

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

Get all of the methods on an Object



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

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

+ (Pry::Method?) from_binding(b)

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.



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

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

+ (Pry::Method?) from_class(klass, name, target = TOPLEVEL_BINDING) 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.



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

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

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

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.



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

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

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

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.



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# 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, 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

+ (Boolean) instance_method_definition?(name, definition_line)



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

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

+ (Array[Class, Module]) instance_resolution_order(klass)

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.



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

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

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

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



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

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

+ (Boolean) method_definition?(name, definition_line)



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

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

+ (Array[Class, Module]) resolution_order(obj)

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



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

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

+ (Object) singleton_class_of(obj)



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

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

+ (Object) singleton_class_resolution_order(klass)

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.



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

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

+ (Boolean) singleton_method_definition?(name, definition_line)



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

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

- (Boolean) ==(obj)



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

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

- (Boolean) alias?



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

def alias?
  name != original_name
end

- (Array<String>) aliases



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

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

- (Boolean) bound_method?



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

def bound_method?
  is_a?(::Method)
end

- (Object) c_source (private)



525
526
527
528
529
530
# File 'lib/pry/method.rb', line 525

def c_source
  info = pry_doc_info
  if info and info.source
    strip_comments_from_c_code(info.source)
  end
end

- (Object) comment



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

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

- (String?) doc



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

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

- (Boolean) dynamically_defined?



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

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

- (Boolean) is_a?(klass) Also known as: kind_of?



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

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

- (String?) method_name_from_first_line(first_ln) (private)



511
512
513
514
515
516
517
518
519
520
521
522
523
# File 'lib/pry/method.rb', line 511

def method_name_from_first_line(first_ln)
  return nil if first_ln.strip !~ /^def /

  tokens = CodeRay.scan(first_ln, :ruby)
  tokens = tokens.tokens.each_slice(2) if tokens.respond_to?(:tokens)
  tokens.each_cons(2) do |t1, t2|
    if t2.last == :method || t2.last == :ident && t1 == [".", :operator]
      return t2.first
    end
  end

  nil
end

- (String) name

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



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

def name
  @method.name.to_s
end

- (String) name_with_owner

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

Examples:

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


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

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

- (String?) original_name



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

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

- (YARD::CodeObjects::MethodObject) pry_doc_info (private)

Raises:

  • (CommandError)

    when the method can't be found or pry-doc isn't installed.



482
483
484
485
486
487
488
489
490
491
492
# File 'lib/pry/method.rb', line 482

def pry_doc_info
  if Pry.config.has_pry_doc
    Pry::MethodInfo.info_for(@method) or raise CommandError, "Cannot locate this method: #{name}. (source_location returns nil)"
  else
    fail_msg = "Cannot locate this method: #{name}."
    if mri?
      fail_msg += ' Try `gem-install pry-doc` to get access to Ruby Core documentation.'
    end
    raise CommandError, fail_msg
  end
end

- (Boolean) pry_method?



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

def pry_method?
  source_file == Pry.eval_path
end

- (Object) redefine(source)

Update the live copy of the method's source.



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

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

- (Boolean) respond_to?(method_name)



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

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

- (Object) ruby_source (private)

Raises:

  • (SourceNotFoundError)


532
533
534
535
536
537
538
539
540
541
542
543
544
545
# File 'lib/pry/method.rb', line 532

def ruby_source
  # 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

- (String) signature



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

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

- (Boolean) singleton_method?



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

def singleton_method?
  wrapped_owner.singleton_class?
end

- (String?) source



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

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

- (Boolean) source?

Can we get the source code for this method?



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

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

- (String?) source_file



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

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

- (Fixnum?) source_line



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

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

- (Range?) source_range



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

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

- (Symbol) source_type



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

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

- (Pry::Method?) super(times = 1)



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

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

- (Method) super_using_ancestors(ancestors, times = 1) (private)



496
497
498
499
500
501
502
503
504
505
506
507
# File 'lib/pry/method.rb', line 496

def super_using_ancestors(ancestors, times=1)
  next_owner = self.owner
  times.times do
    i = ancestors.index(next_owner) + 1
    while ancestors[i] && !(ancestors[i].method_defined?(name) || ancestors[i].private_method_defined?(name))
      i += 1
    end
    next_owner = ancestors[i] or return nil
  end

  safe_send(next_owner, :instance_method, name) rescue nil
end

- (Boolean) unbound_method?



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

def unbound_method?
  is_a?(::UnboundMethod)
end

- (Boolean) undefined?

Is the method undefined? (aka Disowned)



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

def undefined?
  false
end

- (Symbol) visibility



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

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

- (Method, ...) wrapped

Get underlying object wrapped by this Pry::Method instance



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

def wrapped
  @method
end

- (Pry::Module) wrapped_owner

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



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

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