Class: Pry::Method
- Includes:
- Helpers::DocumentationHelpers, RbxMethod
- Defined in:
- lib/pry/method.rb
Overview
This class wraps the normal Method and UnboundMethod classes
to provide extra functionality useful to Pry.
Direct Known Subclasses
Defined Under Namespace
Classes: Disowned
Class Method Summary collapse
-
.all_from_class(klass, include_super = true) ⇒ Array[Pry::Method]
Get all of the instance methods of a
ClassorModule. -
.all_from_common(obj, method_type, include_super = true) ⇒ Object
private
See all_from_class and all_from_obj.
-
.all_from_obj(obj, include_super = true) ⇒ Array[Pry::Method]
Get all of the methods on an
Object. -
.from_binding(b) ⇒ Pry::Method?
Given a
Binding, try to extract the::Methodit originated from and use it to instantiate aPry::Method. -
.from_class(klass, name) ⇒ Pry::Method?
(also: from_module)
Given a
ClassorModuleand the name of a method, try to instantiate aPry::Methodcontaining the instance method of that name. -
.from_obj(obj, name) ⇒ Pry::Method?
Given an object and the name of a method, try to instantiate a
Pry::Methodcontaining the method of that name bound to that object. -
.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::Methodinstance. -
.instance_resolution_order(klass) ⇒ Array[Class, Module]
Get every
ClassandModule, in order, that will be checked when looking for methods on instances of the givenClassorModule. -
.resolution_order(obj) ⇒ Array[Class, Module]
Get every
ClassandModule, in order, that will be checked when looking for an instance method to call on this object. -
.safe_send(obj, method, *args, &block) ⇒ Object
private
Acts like send but ignores any methods defined below Object or Class in the inheritance hierarchy.
- .singleton_class(obj) ⇒ Object private
-
.singleton_class_resolution_order(klass) ⇒ Object
private
Get the singleton classes of superclasses that could define methods on the given class object, and any modules they include.
Instance Method Summary collapse
- #==(obj) ⇒ Boolean
-
#alias? ⇒ Boolean
Is the method definitely an alias?.
-
#doc ⇒ String?
The documentation for the method, or
nilif it's unavailable. -
#doc_for_pry_method ⇒ Object
private
FIXME: a very similar method to this exists on WrappedModule: extract_doc_for_candidate.
-
#dynamically_defined? ⇒ Boolean
Was the method defined outside a source file?.
-
#initialize(method, known_info = {}) ⇒ Pry::Method
constructor
A new instance of
Pry::Methodwrapping the given::Method,UnboundMethod, orProc. - #is_a?(klass) ⇒ Boolean (also: #kind_of?)
-
#method_missing(method_name, *args, &block) ⇒ Object
Delegate any unknown calls to the wrapped method.
- #method_name_from_first_line(first_ln) ⇒ String? private
-
#name ⇒ String
Get the name of the method as a String, regardless of the underlying Method#name type.
-
#name_with_owner ⇒ String
Get the name of the method including the class on which it was defined.
-
#original_name ⇒ String?
The original name the method was defined under, before any aliasing, or
nilif it can't be determined. - #pry_doc_info ⇒ YARD::CodeObjects::MethodObject private
-
#pry_method? ⇒ Boolean
Was the method defined within the Pry REPL?.
- #respond_to?(method_name) ⇒ Boolean
-
#signature ⇒ String
A representation of the method's signature, including its name and parameters.
-
#source ⇒ String?
The source code of the method, or
nilif it's unavailable. -
#source? ⇒ Boolean
Can we get the source code for this method?.
-
#source_file ⇒ String?
The name of the file the method is defined in, or
nilif the filename is unavailable. -
#source_line ⇒ Fixnum?
The line of code in
source_filewhich begins the method's definition, ornilif that information is unavailable. - #source_location ⇒ Object
-
#source_range ⇒ Range?
The range of lines in
source_filewhich contain the method's definition, ornilif that information is unavailable. -
#source_type ⇒ Symbol
The source type of the method.
-
#super(times = 1) ⇒ Pry::Method?
The wrapped method that is called when you use "super" in the body of this method.
-
#super_using_ancestors(ancestors, times = 1) ⇒ Method
private
The unwrapped super-method.
-
#undefined? ⇒ Boolean
Is the method undefined? (aka
Disowned). -
#visibility ⇒ Symbol
The visibility of the method.
-
#wrapped_owner ⇒ Pry::Module
Get the owner of the method as a Pry::Module.
Methods included from Helpers::DocumentationHelpers
#process_comment_markup, #process_rdoc, #process_yardoc, #process_yardoc_tag, #strip_comments_from_c_code, #strip_leading_hash_and_whitespace_from_ruby_comments, #strip_leading_whitespace
Methods included from RbxMethod
Constructor Details
#initialize(method, known_info = {}) ⇒ Pry::Method
A new instance of Pry::Method wrapping the given ::Method, UnboundMethod, or Proc.
215 216 217 218 |
# File 'lib/pry/method.rb', line 215 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.
434 435 436 |
# File 'lib/pry/method.rb', line 434 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
136 137 138 |
# File 'lib/pry/method.rb', line 136 def all_from_class(klass, include_super=true) all_from_common(klass, :instance_method, include_super) end |
.all_from_common(obj, method_type, include_super = true) ⇒ Object (private)
See all_from_class and all_from_obj.
If method_type is :instance_method, obj must be a Class or a Module
If method_type is :method, obj can be any Object
N.B. we pre-cache the visibility here to avoid O(N²) behaviour in "ls".
178 179 180 181 182 183 184 |
# File 'lib/pry/method.rb', line 178 def all_from_common(obj, method_type, include_super=true) %w(public protected private).map do |visibility| safe_send(obj, :"#{visibility}_#{method_type}s", include_super).map do |method_name| new(safe_send(obj, method_type, method_name), :visibility => visibility.to_sym) end end.flatten(1) end |
.all_from_obj(obj, include_super = true) ⇒ Array[Pry::Method]
Get all of the methods on an Object
144 145 146 |
# File 'lib/pry/method.rb', line 144 def all_from_obj(obj, include_super=true) all_from_common(obj, :method, 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.
64 65 66 67 68 69 70 71 72 73 74 75 76 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 106 107 |
# File 'lib/pry/method.rb', line 64 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.(guess.source_file) == File.(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) ⇒ 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.
116 117 118 |
# File 'lib/pry/method.rb', line 116 def from_class(klass, name) new(safe_send(klass, :instance_method, name)) rescue nil end |
.from_obj(obj, name) ⇒ 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.
128 129 130 |
# File 'lib/pry/method.rb', line 128 def from_obj(obj, name) new(safe_send(obj, :method, name)) 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.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/pry/method.rb', line 38 def from_str(name, target=TOPLEVEL_BINDING, ={}) if name.nil? from_binding(target) elsif name.to_s =~ /(.+)\#(\S+)\Z/ context, meth_name = $1, $2 from_module(target.eval(context), meth_name) elsif name.to_s =~ /(.+)\.(\S+)\Z/ context, meth_name = $1, $2 from_obj(target.eval(context), meth_name) elsif [:instance] from_module(target.eval("self"), name) elsif [: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) ⇒ 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.
166 167 168 169 |
# File 'lib/pry/method.rb', line 166 def instance_resolution_order(klass) # include klass in case it is a singleton class, ([klass] + klass.ancestors).uniq 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.
152 153 154 155 156 157 158 159 |
# File 'lib/pry/method.rb', line 152 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) ⇒ Object (private)
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.
190 191 192 |
# File 'lib/pry/method.rb', line 190 def safe_send(obj, method, *args, &block) (Module === obj ? Module : Object).instance_method(method).bind(obj).call(*args, &block) end |
.singleton_class(obj) ⇒ Object (private)
207 |
# File 'lib/pry/method.rb', line 207 def singleton_class(obj); class << obj; self; end end |
.singleton_class_resolution_order(klass) ⇒ Object (private)
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.
199 200 201 202 203 204 205 |
# File 'lib/pry/method.rb', line 199 def singleton_class_resolution_order(klass) resolution_order = klass.ancestors.map do |anc| [singleton_class(anc)] + singleton_class(anc).included_modules if anc.is_a?(Class) end.compact.flatten(1) resolution_order.reverse.uniq.reverse - Class.included_modules end |
Instance Method Details
#==(obj) ⇒ Boolean
412 413 414 415 416 417 418 |
# File 'lib/pry/method.rb', line 412 def ==(obj) if obj.is_a? Pry::Method obj == @method else @method == obj end end |
#alias? ⇒ Boolean
Returns Is the method definitely an alias?.
407 408 409 |
# File 'lib/pry/method.rb', line 407 def alias? name != original_name end |
#doc ⇒ String?
Returns The documentation for the method, or nil if it's
unavailable.
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
# File 'lib/pry/method.rb', line 282 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 |
#doc_for_pry_method ⇒ Object (private)
FIXME: a very similar method to this exists on WrappedModule: extract_doc_for_candidate
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 |
# File 'lib/pry/method.rb', line 450 def doc_for_pry_method _, line_num = source_location buffer = "" Pry.line_buffer[0..(line_num - 1)].each do |line| # Add any line that is a valid ruby comment, # but clear as soon as we hit a non comment line. if (line =~ /^\s*#/) || (line =~ /^\s*$/) buffer << line.lstrip else buffer.replace("") end end buffer end |
#dynamically_defined? ⇒ Boolean
Returns Was the method defined outside a source file?.
397 398 399 |
# File 'lib/pry/method.rb', line 397 def dynamically_defined? !!(source_file and source_file =~ /(\(.*\))|<.*>/) end |
#is_a?(klass) ⇒ Boolean Also known as: kind_of?
422 423 424 |
# File 'lib/pry/method.rb', line 422 def is_a?(klass) klass == Pry::Method or @method.is_a?(klass) end |
#method_name_from_first_line(first_ln) ⇒ String? (private)
483 484 485 486 487 488 489 490 491 492 493 494 495 |
# File 'lib/pry/method.rb', line 483 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 |
#name ⇒ String
Get the name of the method as a String, regardless of the underlying Method#name type.
222 223 224 |
# File 'lib/pry/method.rb', line 222 def name @method.name.to_s end |
#name_with_owner ⇒ String
Get the name of the method including the class on which it was defined.
243 244 245 |
# File 'lib/pry/method.rb', line 243 def name_with_owner "#{wrapped_owner.method_prefix}#{name}" end |
#original_name ⇒ String?
Returns The original name the method was defined under,
before any aliasing, or nil if it can't be determined.
391 392 393 394 |
# File 'lib/pry/method.rb', line 391 def original_name return nil if source_type != :ruby method_name_from_first_line(source.lines.first) end |
#pry_doc_info ⇒ YARD::CodeObjects::MethodObject (private)
441 442 443 444 445 446 447 |
# File 'lib/pry/method.rb', line 441 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 raise CommandError, "Cannot locate this method: #{name}. Try `gem install pry-doc` to get access to Ruby Core documentation." end end |
#pry_method? ⇒ Boolean
Returns Was the method defined within the Pry REPL?.
402 403 404 |
# File 'lib/pry/method.rb', line 402 def pry_method? source_file == Pry.eval_path end |
#respond_to?(method_name) ⇒ Boolean
429 430 431 |
# File 'lib/pry/method.rb', line 429 def respond_to?(method_name) super or @method.respond_to?(method_name) end |
#signature ⇒ String
Returns 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.
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 |
# File 'lib/pry/method.rb', line 357 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 ⇒ String?
Returns The source code of the method, or nil if it's unavailable.
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
# File 'lib/pry/method.rb', line 248 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.) end strip_leading_whitespace(code) end end |
#source? ⇒ Boolean
Can we get the source code for this method?
273 274 275 276 277 |
# File 'lib/pry/method.rb', line 273 def source? !!source rescue MethodSource::SourceNotFoundError false end |
#source_file ⇒ String?
Returns The name of the file the method is defined in, or
nil if the filename is unavailable.
315 316 317 318 319 320 321 322 323 324 |
# File 'lib/pry/method.rb', line 315 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 ⇒ Fixnum?
Returns The line of code in source_file which begins
the method's definition, or nil if that information is unavailable.
328 329 330 |
# File 'lib/pry/method.rb', line 328 def source_line source_location.nil? ? nil : source_location.last end |
#source_location ⇒ Object
304 305 306 307 308 309 310 311 |
# File 'lib/pry/method.rb', line 304 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 ⇒ Range?
Returns The range of lines in source_file which contain
the method's definition, or nil if that information is unavailable.
334 335 336 |
# File 'lib/pry/method.rb', line 334 def source_range source_location.nil? ? nil : (source_line)..(source_line + source.lines.count - 1) end |
#source_type ⇒ Symbol
Returns The source type of the method. The options are
:ruby for Ruby methods or :c for methods written in C.
300 301 302 |
# File 'lib/pry/method.rb', line 300 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.
379 380 381 382 383 384 385 386 387 |
# File 'lib/pry/method.rb', line 379 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 |
#super_using_ancestors(ancestors, times = 1) ⇒ Method (private)
Returns The unwrapped super-method.
469 470 471 472 473 474 475 476 477 478 479 |
# File 'lib/pry/method.rb', line 469 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 next_owner.instance_method(name) rescue nil end |
#undefined? ⇒ Boolean
Is the method undefined? (aka Disowned)
234 235 236 |
# File 'lib/pry/method.rb', line 234 def undefined? false end |
#visibility ⇒ Symbol
Returns The visibility of the method. May be :public,
:protected, or :private.
340 341 342 343 344 345 346 347 348 349 350 |
# File 'lib/pry/method.rb', line 340 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 ⇒ Pry::Module
Get the owner of the method as a Pry::Module
228 229 230 |
# File 'lib/pry/method.rb', line 228 def wrapped_owner @wrapped_owner ||= Pry::WrappedModule.new(owner) end |