1
0
Fork 0
mirror of https://github.com/pry/pry.git synced 2022-11-09 12:35:05 -05:00

Add all_from_(obj|class) methods to Pry::Method

This is the core part of an "ls" implementation.
This commit is contained in:
Conrad Irwin 2011-10-01 23:30:33 -07:00
parent 4dc9d27cf6
commit f140c5379a
2 changed files with 184 additions and 10 deletions

View file

@ -74,14 +74,45 @@ class Pry
def from_obj(obj, name)
new(obj.method(name)) rescue nil
end
# Get all of the instance methods of a `Class` or `Module`
# @param [Class,Module] klass
# @return [Array[Pry::Method]]
def all_from_class(klass)
all_from_common(klass, :instance_method)
end
# Get all of the methods on an `Object`
# @param [Object] obj
# @return [Array[Pry::Method]]
def all_from_obj(obj)
all_from_common(obj, :method)
end
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".
def all_from_common(obj, method_type)
%w(public protected private).map do |visibility|
obj.send(:"#{visibility}_#{method_type}s").map do |method_name|
new(obj.send(method_type, method_name), :visibility => visibility.to_sym)
end
end.flatten(1)
end
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]
def initialize(method)
def initialize(method, known_info={})
@method = method
@visibility = known_info[:visibility]
end
# Get the name of the method as a String, regardless of the underlying Method#name type.
@ -162,15 +193,15 @@ class Pry
# @return [Symbol] The visibility of the method. May be `:public`,
# `:protected`, or `:private`.
def visibility
if owner.public_instance_methods.include?(name)
:public
elsif owner.protected_instance_methods.include?(name)
:protected
elsif owner.private_instance_methods.include?(name)
:private
else
:none
end
@visibility ||= if owner.public_instance_methods.include?(name)
:public
elsif owner.protected_instance_methods.include?(name)
:protected
elsif owner.private_instance_methods.include?(name)
:private
else
:none
end
end
# @return [String] A representation of the method's signature, including its

View file

@ -73,5 +73,148 @@ describe Pry::Method do
meth.name.should == "initialize"
end
end
describe 'all_from_class' do
def should_find_method(name)
Pry::Method.all_from_class(@class).map(&:name).should.include(name)
end
it 'should be able to find public instance methods defined in a class' do
@class = Class.new{ def meth; 1; end }
should_find_method('meth')
end
it 'should be able to find private and protected instance methods defined in a class' do
@class = Class.new { protected; def prot; 1; end; private; def priv; 1; end }
should_find_method('priv')
should_find_method('prot')
end
it 'should find methods all the way up to Kernel' do
@class = Class.new
should_find_method('exit!')
end
it 'should be able to find instance methods defined in a super-class' do
@class = Class.new(Class.new{ def meth; 1; end }) {}
should_find_method('meth')
end
it 'should be able to find instance methods defined in modules included into this class' do
@class = Class.new{ include Module.new{ def meth; 1; end; } }
should_find_method('meth')
end
it 'should be able to find instance methods defined in modules included into super-classes' do
@class = Class.new(Class.new{ include Module.new{ def meth; 1; end; } })
should_find_method('meth')
end
it 'should attribute overridden methods to the sub-class' do
@class = Class.new(Class.new{ include Module.new{ def meth; 1; end; } }) { def meth; 2; end }
Pry::Method.all_from_class(@class).detect{ |x| x.name == 'meth' }.owner.should == @class
end
it 'should be able to find methods defined on a singleton class' do
@class = (class << Object.new; def meth; 1; end; self; end)
should_find_method('meth')
end
it 'should be able to find methods on super-classes when given a singleton class' do
@class = (class << Class.new{ def meth; 1; end}.new; self; end)
should_find_method('meth')
end
end
describe 'all_from_obj' do
describe 'on normal objects' do
def should_find_method(name)
Pry::Method.all_from_obj(@obj).map(&:name).should.include(name)
end
it "should find methods defined in the object's class" do
@obj = Class.new{ def meth; 1; end }.new
should_find_method('meth')
end
it "should find methods defined in modules included into the object's class" do
@obj = Class.new{ include Module.new{ def meth; 1; end } }.new
should_find_method('meth')
end
it "should find methods defined in the object's singleton class" do
@obj = Object.new
class << @obj; def meth; 1; end; end
should_find_method('meth')
end
it "should find methods in modules included into the object's singleton class" do
@obj = Object.new
@obj.extend Module.new{ def meth; 1; end }
should_find_method('meth')
end
it "should find methods all the way up to Kernel" do
@obj = Object.new
should_find_method('exit!')
end
it "should not find methods defined on the classes singleton class" do
@obj = Class.new{ class << self; def meth; 1; end; end }.new
Pry::Method.all_from_obj(@obj).map(&:name).should.not.include('meth')
end
end
describe 'on classes' do
def should_find_method(name)
Pry::Method.all_from_obj(@class).map(&:name).should.include(name)
end
it "should find methods defined in the class' singleton class" do
@class = Class.new{ class << self; def meth; 1; end; end }
should_find_method('meth')
end
it "should find methods defined on modules extended into the class" do
@class = Class.new{ extend Module.new{ def meth; 1; end; } }
should_find_method('meth')
end
it "should find methods defined on the singleton class of super-classes" do
@class = Class.new(Class.new{ class << self; def meth; 1; end; end })
should_find_method('meth')
end
it "should not find methods defined within the class" do
@class = Class.new{ def meth; 1; end }
Pry::Method.all_from_obj(@obj).map(&:name).should.not.include('meth')
end
it "should find methods defined on Class" do
@class = Class.new
should_find_method('allocate')
end
it "should find methods defined on Kernel" do
@class = Class.new
should_find_method('exit!')
end
it "should attribute overridden methods to the sub-class' singleton class" do
@class = Class.new(Class.new{ class << self; def meth; 1; end; end }) { class << self; def meth; 1; end; end }
Pry::Method.all_from_obj(@class).detect{ |x| x.name == 'meth' }.owner.should == (class << @class; self; end)
end
it "should attrbute overridden methods to the class not the module" do
@class = Class.new { class << self; def meth; 1; end; end; extend Module.new{ def meth; 1; end; } }
Pry::Method.all_from_obj(@class).detect{ |x| x.name == 'meth' }.owner.should == (class << @class; self; end)
end
it "should attribute overridden methods to the relevant singleton class in preference to Class" do
@class = Class.new { class << self; def allocate; 1; end; end }
Pry::Method.all_from_obj(@class).detect{ |x| x.name == 'allocate' }.owner.should == (class << @class; self; end)
end
end
end
end