Add (instance_)resolution_order to Pry::Method

This commit is contained in:
Conrad Irwin 2011-10-05 01:08:17 -07:00
parent 1c0a82f888
commit fd26a55627
2 changed files with 103 additions and 0 deletions

View File

@ -89,6 +89,29 @@ class Pry
all_from_common(obj, :method)
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]]
def resolution_order(obj)
if obj.is_a?(Class)
singleton_class_resolution_order(obj) + instance_resolution_order(Class)
else
klass = singleton_class(obj) rescue obj.class
instance_resolution_order(klass)
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]]
def instance_resolution_order(klass)
# include klass in case it is a singleton class,
([klass] + klass.ancestors).uniq
end
private
# See all_from_class and all_from_obj.
@ -103,6 +126,20 @@ class Pry
end
end.flatten(1)
end
# 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.
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
def singleton_class(obj); class << obj; self; end end
end
# A new instance of `Pry::Method` wrapping the given `::Method`, `UnboundMethod`, or `Proc`.

View File

@ -215,6 +215,72 @@ describe Pry::Method do
Pry::Method.all_from_obj(@class).detect{ |x| x.name == 'allocate' }.owner.should == (class << @class; self; end)
end
end
describe 'method resolution order' do
module LS
class Top; end
class Next < Top; end
module M; end
module N; include M; end
module O; include M; end
module P; end
class Low < Next; include N; include P; end
class Lower < Low; extend N; end
class Bottom < Lower; extend O; end
end
def singleton_class(obj); class << obj; self; end; end
it "should look at a class and then its superclass" do
Pry::Method.instance_resolution_order(LS::Next).should == [LS::Next] + Pry::Method.instance_resolution_order(LS::Top)
end
it "should include the included modules between a class and its superclass" do
Pry::Method.instance_resolution_order(LS::Low).should == [LS::Low, LS::P, LS::N, LS::M] + Pry::Method.instance_resolution_order(LS::Next)
end
it "should not include modules extended into the class" do
Pry::Method.instance_resolution_order(LS::Bottom).should == [LS::Bottom] + Pry::Method.instance_resolution_order(LS::Lower)
end
it "should include included modules for Modules" do
Pry::Method.instance_resolution_order(LS::O).should == [LS::O, LS::M]
end
it "should include the singleton class of objects" do
obj = LS::Low.new
Pry::Method.resolution_order(obj).should == [singleton_class(obj)] + Pry::Method.instance_resolution_order(LS::Low)
end
it "should not include singleton classes of numbers" do
Pry::Method.resolution_order(4).should == Pry::Method.instance_resolution_order(Fixnum)
end
it "should include singleton classes for classes" do
Pry::Method.resolution_order(LS::Low).should == [singleton_class(LS::Low)] + Pry::Method.resolution_order(LS::Next)
end
it "should include modules included into singleton classes" do
Pry::Method.resolution_order(LS::Lower).should == [singleton_class(LS::Lower), LS::N, LS::M] + Pry::Method.resolution_order(LS::Low)
end
it "should include modules at most once" do
Pry::Method.resolution_order(LS::Bottom).count(LS::M).should == 1
end
it "should include modules at the point which they would be reached" do
Pry::Method.resolution_order(LS::Bottom).should == [singleton_class(LS::Bottom), LS::O] + (Pry::Method.resolution_order(LS::Lower))
end
it "should include the Pry::Method.instance_resolution_order of Class after the singleton classes" do
Pry::Method.resolution_order(LS::Top).should ==
[singleton_class(LS::Top), singleton_class(Object), (defined? BasicObject) && singleton_class(BasicObject)].compact +
Pry::Method.instance_resolution_order(Class)
end
end
end
end