This class wraps the normal `Method` and `UnboundMethod` classes to provide extra functionality useful to Pry.
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
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
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
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
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
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 =~ /(.+)\#(\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 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
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
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
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
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
@return [Boolean]
# File lib/pry/method.rb, line 411 def ==(obj) if obj.is_a? Pry::Method obj == @method else @method == obj end end
@return [Boolean] Is the method definitely an alias?
# File lib/pry/method.rb, line 406 def alias? name != original_name end
@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
@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 =~ /(\(.*\))|<.*>/) end
@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
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
Get the name of the method as a String, regardless of the underlying Method#name type. @return [String]
# File lib/pry/method.rb, line 221 def name @method.name.to_s end
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
@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
@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
@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
@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
@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
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
@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
@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
# 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
@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
@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
@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
Is the method undefined? (aka `Disowned`) @return [Boolean] false
# File lib/pry/method.rb, line 233 def undefined? false end
@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
Generated with the Darkfish Rdoc Generator 2.