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:
parent
4dc9d27cf6
commit
f140c5379a
2 changed files with 184 additions and 10 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue