2019-05-02 18:33:56 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2012-08-29 04:23:29 -04:00
|
|
|
require 'set'
|
2011-09-19 04:18:57 -04:00
|
|
|
|
|
|
|
describe Pry::Method do
|
2011-10-02 03:02:59 -04:00
|
|
|
it "should use String names for compatibility" do
|
|
|
|
klass = Class.new { def hello; end }
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(Pry::Method.new(klass.instance_method(:hello)).name).to eq "hello"
|
2011-10-02 03:02:59 -04:00
|
|
|
end
|
|
|
|
|
2011-09-19 04:18:57 -04:00
|
|
|
describe ".from_str" do
|
2019-03-03 10:37:58 -05:00
|
|
|
it 'looks up instance methods if no methods available and no options provided' do
|
2011-09-19 04:18:57 -04:00
|
|
|
klass = Class.new { def hello; end }
|
|
|
|
meth = Pry::Method.from_str(:hello, Pry.binding_for(klass))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth).to eq klass.instance_method(:hello)
|
2011-09-19 04:18:57 -04:00
|
|
|
end
|
|
|
|
|
2019-03-03 10:37:58 -05:00
|
|
|
it 'looks up methods if no instance methods available and no options provided' do
|
2011-09-19 04:18:57 -04:00
|
|
|
klass = Class.new { def self.hello; end }
|
|
|
|
meth = Pry::Method.from_str(:hello, Pry.binding_for(klass))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth).to eq klass.method(:hello)
|
2011-09-19 04:18:57 -04:00
|
|
|
end
|
|
|
|
|
2019-03-03 10:37:58 -05:00
|
|
|
it(
|
|
|
|
'looks up instance methods first even if methods available and no ' \
|
|
|
|
'options provided'
|
|
|
|
) do
|
2018-10-14 02:23:34 -04:00
|
|
|
klass = Class.new do
|
|
|
|
def hello; end
|
|
|
|
|
|
|
|
def self.hello; end
|
|
|
|
end
|
2011-09-19 04:18:57 -04:00
|
|
|
meth = Pry::Method.from_str(:hello, Pry.binding_for(klass))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth).to eq klass.instance_method(:hello)
|
2011-09-19 04:18:57 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should look up instance methods if "instance-methods" option provided' do
|
2018-10-14 02:23:34 -04:00
|
|
|
klass = Class.new do
|
|
|
|
def hello; end
|
|
|
|
|
|
|
|
def self.hello; end
|
|
|
|
end
|
2019-03-03 10:37:58 -05:00
|
|
|
meth = Pry::Method.from_str(
|
|
|
|
:hello, Pry.binding_for(klass), "instance-methods" => true
|
|
|
|
)
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth).to eq klass.instance_method(:hello)
|
2011-09-19 04:18:57 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should look up methods if :methods option provided' do
|
2018-10-14 02:23:34 -04:00
|
|
|
klass = Class.new do
|
|
|
|
def hello; end
|
|
|
|
|
|
|
|
def self.hello; end
|
|
|
|
end
|
2019-02-26 18:02:08 -05:00
|
|
|
meth = Pry::Method.from_str(:hello, Pry.binding_for(klass), methods: true)
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth).to eq klass.method(:hello)
|
2011-09-19 04:18:57 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should look up instance methods using the Class#method syntax' do
|
2018-10-14 02:23:34 -04:00
|
|
|
klass = Class.new do
|
|
|
|
def hello; end
|
|
|
|
|
|
|
|
def self.hello; end
|
|
|
|
end
|
2011-09-19 04:18:57 -04:00
|
|
|
meth = Pry::Method.from_str("klass#hello", Pry.binding_for(binding))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth).to eq klass.instance_method(:hello)
|
2011-09-19 04:18:57 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should look up methods using the object.method syntax' do
|
2018-10-14 02:23:34 -04:00
|
|
|
klass = Class.new do
|
|
|
|
def hello; end
|
|
|
|
|
|
|
|
def self.hello; end
|
|
|
|
end
|
2011-09-19 04:18:57 -04:00
|
|
|
meth = Pry::Method.from_str("klass.hello", Pry.binding_for(binding))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth).to eq klass.method(:hello)
|
2011-09-19 04:18:57 -04:00
|
|
|
end
|
|
|
|
|
2019-03-03 10:37:58 -05:00
|
|
|
it(
|
|
|
|
'should NOT look up instance methods using the Class#method syntax if ' \
|
|
|
|
'no instance methods defined'
|
|
|
|
) do
|
2018-10-12 12:54:00 -04:00
|
|
|
_klass = Class.new { def self.hello; end }
|
2015-01-22 16:52:20 -05:00
|
|
|
meth = Pry::Method.from_str("_klass#hello", Pry.binding_for(binding))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth).to eq nil
|
2011-09-19 04:18:57 -04:00
|
|
|
end
|
|
|
|
|
2019-03-03 10:37:58 -05:00
|
|
|
it(
|
|
|
|
'should NOT look up methods using the object.method syntax if no ' \
|
|
|
|
'methods defined'
|
|
|
|
) do
|
2018-10-12 12:54:00 -04:00
|
|
|
_klass = Class.new { def hello; end }
|
2015-01-22 16:52:20 -05:00
|
|
|
meth = Pry::Method.from_str("_klass.hello", Pry.binding_for(binding))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth).to eq nil
|
2011-09-19 04:18:57 -04:00
|
|
|
end
|
|
|
|
|
2013-12-11 11:44:49 -05:00
|
|
|
it 'should look up methods using klass.new.method syntax' do
|
2015-01-22 16:52:20 -05:00
|
|
|
_klass = Class.new { def hello; :hello; end }
|
|
|
|
meth = Pry::Method.from_str("_klass.new.hello", Pry.binding_for(binding))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth.name).to eq "hello"
|
2011-09-19 04:18:57 -04:00
|
|
|
end
|
|
|
|
|
2013-12-11 05:13:05 -05:00
|
|
|
it 'should take care of corner cases like mongo[] e.g Foo::Bar.new[]- issue 998' do
|
2015-01-22 16:52:20 -05:00
|
|
|
_klass = Class.new { def []; :hello; end }
|
|
|
|
meth = Pry::Method.from_str("_klass.new[]", Pry.binding_for(binding))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth.name).to eq "[]"
|
2013-12-11 05:13:05 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should take care of cases like $ mongo[] - issue 998' do
|
2013-12-11 06:09:52 -05:00
|
|
|
f = Class.new { def []; :hello; end }.new
|
2013-12-11 05:13:05 -05:00
|
|
|
meth = Pry::Method.from_str("f[]", Pry.binding_for(binding))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth).to eq f.method(:[])
|
2013-12-11 05:13:05 -05:00
|
|
|
end
|
|
|
|
|
2011-09-19 04:18:57 -04:00
|
|
|
it 'should look up instance methods using klass.meth#method syntax' do
|
2015-01-22 16:52:20 -05:00
|
|
|
_klass = Class.new { def self.meth; Class.new; end }
|
|
|
|
meth = Pry::Method.from_str("_klass.meth#initialize", Pry.binding_for(binding))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth.name).to eq "initialize"
|
2011-09-19 04:18:57 -04:00
|
|
|
end
|
2012-11-13 23:32:31 -05:00
|
|
|
|
|
|
|
it 'should look up methods using instance::bar syntax' do
|
2018-11-04 04:34:24 -05:00
|
|
|
_klass = Class.new { def self.meth; Class.new; end }
|
2015-01-22 16:52:20 -05:00
|
|
|
meth = Pry::Method.from_str("_klass::meth", Pry.binding_for(binding))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth.name).to eq "meth"
|
2012-11-13 23:32:31 -05:00
|
|
|
end
|
2012-12-22 16:45:33 -05:00
|
|
|
|
|
|
|
it 'should not raise an exception if receiver does not exist' do
|
2019-03-03 10:37:58 -05:00
|
|
|
expect { Pry::Method.from_str("random_klass.meth", Pry.binding_for(binding)) }
|
|
|
|
.to_not raise_error
|
2012-12-22 16:45:33 -05:00
|
|
|
end
|
2011-09-19 04:18:57 -04:00
|
|
|
end
|
2011-10-02 02:30:33 -04:00
|
|
|
|
2011-12-23 17:44:01 -05:00
|
|
|
describe '.from_binding' do
|
|
|
|
it 'should be able to pick a method out of a binding' do
|
2019-03-03 10:37:58 -05:00
|
|
|
klass = Class.new { def self.foo; binding; end }.foo
|
|
|
|
expect(Pry::Method.from_binding(klass).name).to eq('foo')
|
2011-12-23 17:44:01 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should NOT find a method from the toplevel binding' do
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(Pry::Method.from_binding(TOPLEVEL_BINDING)).to eq nil
|
2011-12-23 17:44:01 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should find methods that have been undef'd" do
|
2013-02-02 11:45:20 -05:00
|
|
|
c = Class.new do
|
2011-12-23 17:44:01 -05:00
|
|
|
def self.bar
|
|
|
|
class << self; undef bar; end
|
|
|
|
binding
|
|
|
|
end
|
2013-02-02 11:45:20 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
m = Pry::Method.from_binding(c.bar)
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(m.name).to eq "bar"
|
2011-12-23 17:44:01 -05:00
|
|
|
end
|
|
|
|
|
2018-10-06 12:58:53 -04:00
|
|
|
it 'should find the super method correctly' do
|
2018-10-14 02:23:34 -04:00
|
|
|
# rubocop:disable Layout/EmptyLineBetweenDefs
|
|
|
|
a = Class.new { def gag33; binding; end; def self.line; __LINE__; end }
|
|
|
|
# rubocop:enable Layout/EmptyLineBetweenDefs
|
|
|
|
|
2018-11-04 04:34:24 -05:00
|
|
|
b = Class.new(a) { def gag33; super; end }
|
2018-10-06 12:58:53 -04:00
|
|
|
|
|
|
|
g = b.new.gag33
|
|
|
|
m = Pry::Method.from_binding(g)
|
|
|
|
|
|
|
|
expect(m.owner).to eq a
|
|
|
|
expect(m.source_line).to eq a.line
|
|
|
|
expect(m.name).to eq "gag33"
|
2011-12-23 17:44:01 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should find the right method if a super method exists' do
|
2018-11-04 04:34:24 -05:00
|
|
|
a = Class.new { def gag; binding; end; }
|
2018-10-14 02:23:34 -04:00
|
|
|
|
|
|
|
# rubocop:disable Layout/EmptyLineBetweenDefs
|
|
|
|
b = Class.new(a) { def gag; super; binding; end; def self.line; __LINE__; end }
|
|
|
|
# rubocop:enable Layout/EmptyLineBetweenDefs
|
2011-12-23 17:44:01 -05:00
|
|
|
|
|
|
|
m = Pry::Method.from_binding(b.new.gag)
|
|
|
|
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(m.owner).to eq b
|
|
|
|
expect(m.source_line).to eq b.line
|
|
|
|
expect(m.name).to eq "gag"
|
2011-12-23 17:44:01 -05:00
|
|
|
end
|
2012-09-23 23:54:35 -04:00
|
|
|
|
2018-10-06 12:58:53 -04:00
|
|
|
it "should find the right method from a BasicObject" do
|
2018-10-14 02:23:34 -04:00
|
|
|
# rubocop:disable Layout/EmptyLineBetweenDefs
|
|
|
|
a = Class.new(BasicObject) do
|
|
|
|
def gag; ::Kernel.binding; end; def self.line; __LINE__; end
|
|
|
|
end
|
|
|
|
# rubocop:enable Layout/EmptyLineBetweenDefs
|
2012-09-23 23:54:35 -04:00
|
|
|
|
2018-10-06 12:58:53 -04:00
|
|
|
m = Pry::Method.from_binding(a.new.gag)
|
|
|
|
expect(m.owner).to eq a
|
|
|
|
expect(m.source_file).to eq __FILE__
|
|
|
|
expect(m.source_line).to eq a.line
|
2012-09-23 23:54:35 -04:00
|
|
|
end
|
2013-02-02 11:45:20 -05:00
|
|
|
|
|
|
|
it 'should find the right method even if it was renamed and replaced' do
|
|
|
|
o = Object.new
|
|
|
|
class << o
|
|
|
|
def borscht
|
2015-01-22 16:52:20 -05:00
|
|
|
@nips = "nips"
|
2013-02-02 11:45:20 -05:00
|
|
|
binding
|
|
|
|
end
|
2019-02-26 18:00:16 -05:00
|
|
|
alias_method :paella, :borscht
|
2013-02-02 11:45:20 -05:00
|
|
|
def borscht() paella end
|
|
|
|
end
|
|
|
|
|
|
|
|
m = Pry::Method.from_binding(o.borscht)
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(m.source).to eq Pry::Method(o.method(:paella)).source
|
2013-02-02 11:45:20 -05:00
|
|
|
end
|
2011-12-23 17:44:01 -05:00
|
|
|
end
|
|
|
|
|
2012-02-01 01:46:59 -05:00
|
|
|
describe 'super' do
|
|
|
|
it 'should be able to find the super method on a bound method' do
|
2018-11-04 04:34:24 -05:00
|
|
|
a = Class.new { def rar; 4; end }
|
|
|
|
b = Class.new(a) { def rar; super; end }
|
2012-02-01 01:46:59 -05:00
|
|
|
|
|
|
|
obj = b.new
|
|
|
|
|
|
|
|
zuper = Pry::Method(obj.method(:rar)).super
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(zuper.owner).to eq a
|
|
|
|
expect(zuper.receiver).to eq obj
|
2012-02-01 01:46:59 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should be able to find the super method of an unbound method' do
|
2018-11-04 04:34:24 -05:00
|
|
|
a = Class.new { def rar; 4; end }
|
|
|
|
b = Class.new(a) { def rar; super; end }
|
2012-02-01 01:46:59 -05:00
|
|
|
|
|
|
|
zuper = Pry::Method(b.instance_method(:rar)).super
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(zuper.owner).to eq a
|
2012-02-01 01:46:59 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should return nil if no super method exists' do
|
2018-11-04 04:34:24 -05:00
|
|
|
a = Class.new { def rar; super; end }
|
2012-02-01 01:46:59 -05:00
|
|
|
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(Pry::Method(a.instance_method(:rar)).super).to eq nil
|
2012-02-01 01:46:59 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should be able to find super methods defined on modules' do
|
2018-11-04 04:34:24 -05:00
|
|
|
m = Module.new { def rar; 4; end }
|
|
|
|
a = Class.new { def rar; super; end; include m }
|
2012-02-01 01:46:59 -05:00
|
|
|
|
|
|
|
zuper = Pry::Method(a.new.method(:rar)).super
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(zuper.owner).to eq m
|
2012-02-01 01:46:59 -05:00
|
|
|
end
|
|
|
|
|
2019-03-03 10:37:58 -05:00
|
|
|
it(
|
|
|
|
'should be able to find super methods defined on super-classes when ' \
|
|
|
|
'there are modules in the way'
|
|
|
|
) do
|
2018-11-04 04:34:24 -05:00
|
|
|
a = Class.new { def rar; 4; end }
|
|
|
|
m = Module.new { def mooo; 4; end }
|
|
|
|
b = Class.new(a) { def rar; super; end; include m }
|
2012-02-01 01:46:59 -05:00
|
|
|
|
|
|
|
zuper = Pry::Method(b.new.method(:rar)).super
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(zuper.owner).to eq a
|
2012-02-01 01:46:59 -05:00
|
|
|
end
|
|
|
|
|
2019-03-03 10:37:58 -05:00
|
|
|
it 'jumps up multiple levels of bound method, even through modules' do
|
2018-11-04 04:34:24 -05:00
|
|
|
a = Class.new { def rar; 4; end }
|
|
|
|
m = Module.new { def rar; 4; end }
|
|
|
|
b = Class.new(a) { def rar; super; end; include m }
|
2012-02-01 01:46:59 -05:00
|
|
|
|
|
|
|
zuper = Pry::Method(b.new.method(:rar)).super
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(zuper.owner).to eq m
|
|
|
|
expect(zuper.super.owner).to eq a
|
2012-02-01 01:46:59 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-10-02 02:30:33 -04:00
|
|
|
describe 'all_from_class' do
|
|
|
|
def should_find_method(name)
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(Pry::Method.all_from_class(@class).map(&:name)).to include name
|
2011-10-02 02:30:33 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should be able to find public instance methods defined in a class' do
|
2018-11-04 04:34:24 -05:00
|
|
|
@class = Class.new { def meth; 1; end }
|
2011-10-02 02:30:33 -04:00
|
|
|
should_find_method('meth')
|
|
|
|
end
|
|
|
|
|
2019-03-03 10:37:58 -05:00
|
|
|
it 'finds private and protected instance methods defined in a class' do
|
2019-02-24 12:52:27 -05:00
|
|
|
@class = Class.new do
|
|
|
|
protected
|
2019-02-24 17:24:19 -05:00
|
|
|
|
2019-02-24 12:52:27 -05:00
|
|
|
def prot; 1; end
|
|
|
|
|
|
|
|
private
|
2019-02-24 17:24:19 -05:00
|
|
|
|
2019-02-24 12:52:27 -05:00
|
|
|
def priv; 1; end
|
|
|
|
end
|
2011-10-02 02:30:33 -04:00
|
|
|
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
|
2018-11-04 04:34:24 -05:00
|
|
|
@class = Class.new(Class.new { def meth; 1; end }) {}
|
2011-10-02 02:30:33 -04:00
|
|
|
should_find_method('meth')
|
|
|
|
end
|
|
|
|
|
2019-03-03 10:37:58 -05:00
|
|
|
it 'finds instance methods defined in modules included into this class' do
|
2018-10-15 16:38:17 -04:00
|
|
|
@class = Class.new do
|
|
|
|
include(Module.new { def meth; 1; end })
|
|
|
|
end
|
2011-10-02 02:30:33 -04:00
|
|
|
should_find_method('meth')
|
|
|
|
end
|
|
|
|
|
2019-03-03 10:37:58 -05:00
|
|
|
it 'finds instance methods defined in modules included into super-classes' do
|
2018-10-15 16:38:17 -04:00
|
|
|
super_class = Class.new do
|
|
|
|
include(Module.new { def meth; 1; end })
|
|
|
|
end
|
|
|
|
@class = Class.new(super_class)
|
2011-10-02 02:30:33 -04:00
|
|
|
should_find_method('meth')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should attribute overridden methods to the sub-class' do
|
2018-10-15 16:38:17 -04:00
|
|
|
super_class = Class.new do
|
|
|
|
include(Module.new { def meth; 1; end })
|
|
|
|
end
|
|
|
|
@class = Class.new(super_class) { def meth; 2; end }
|
2019-03-03 10:37:58 -05:00
|
|
|
expect(Pry::Method.all_from_class(@class).detect { |x| x.name == 'meth' }.owner)
|
|
|
|
.to eq @class
|
2011-10-02 02:30:33 -04:00
|
|
|
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
|
2018-11-04 04:34:24 -05:00
|
|
|
@class = (class << Class.new { def meth; 1; end }.new; self; end)
|
2011-10-02 02:30:33 -04:00
|
|
|
should_find_method('meth')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe 'all_from_obj' do
|
|
|
|
describe 'on normal objects' do
|
|
|
|
def should_find_method(name)
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(Pry::Method.all_from_obj(@obj).map(&:name)).to include name
|
2011-10-02 02:30:33 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should find methods defined in the object's class" do
|
2018-11-04 04:34:24 -05:00
|
|
|
@obj = Class.new { def meth; 1; end }.new
|
2011-10-02 02:30:33 -04:00
|
|
|
should_find_method('meth')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should find methods defined in modules included into the object's class" do
|
2018-11-17 11:36:09 -05:00
|
|
|
@obj = Class.new do
|
2018-10-15 16:38:17 -04:00
|
|
|
include(Module.new { def meth; 1; end })
|
2018-11-17 11:36:09 -05:00
|
|
|
end.new
|
2011-10-02 02:30:33 -04:00
|
|
|
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
|
2018-10-15 16:38:17 -04:00
|
|
|
@obj.extend(Module.new { def meth; 1; end })
|
2011-10-02 02:30:33 -04:00
|
|
|
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
|
2018-11-04 04:34:24 -05:00
|
|
|
@obj = Class.new { class << self; def meth; 1; end; end }.new
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(Pry::Method.all_from_obj(@obj).map(&:name)).not_to include 'meth'
|
2011-10-02 02:30:33 -04:00
|
|
|
end
|
2011-10-08 03:58:44 -04:00
|
|
|
|
|
|
|
it "should work in the face of an overridden send" do
|
2018-11-17 11:36:09 -05:00
|
|
|
@obj = Class.new do
|
2018-10-14 02:23:34 -04:00
|
|
|
def meth; 1; end
|
|
|
|
|
|
|
|
def send; raise EOFError; end
|
2018-11-17 11:36:09 -05:00
|
|
|
end.new
|
2011-10-08 03:58:44 -04:00
|
|
|
should_find_method('meth')
|
|
|
|
end
|
2011-10-02 02:30:33 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
describe 'on classes' do
|
|
|
|
def should_find_method(name)
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(Pry::Method.all_from_obj(@class).map(&:name)).to include name
|
2011-10-02 02:30:33 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should find methods defined in the class' singleton class" do
|
2018-11-04 04:34:24 -05:00
|
|
|
@class = Class.new { class << self; def meth; 1; end; end }
|
2011-10-02 02:30:33 -04:00
|
|
|
should_find_method('meth')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should find methods defined on modules extended into the class" do
|
2018-10-15 16:38:17 -04:00
|
|
|
@class = Class.new do
|
|
|
|
extend(Module.new { def meth; 1; end })
|
|
|
|
end
|
2011-10-02 02:30:33 -04:00
|
|
|
should_find_method('meth')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should find methods defined on the singleton class of super-classes" do
|
2018-11-04 04:34:24 -05:00
|
|
|
@class = Class.new(Class.new { class << self; def meth; 1; end; end })
|
2011-10-02 02:30:33 -04:00
|
|
|
should_find_method('meth')
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should not find methods defined within the class" do
|
2018-11-04 04:34:24 -05:00
|
|
|
@class = Class.new { def meth; 1; end }
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(Pry::Method.all_from_obj(@class).map(&:name)).not_to include 'meth'
|
2011-10-02 02:30:33 -04:00
|
|
|
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
|
2019-03-03 10:37:58 -05:00
|
|
|
@class = Class.new(Class.new { class << self; def meth; 1; end; end }) do
|
|
|
|
class << self; def meth; 1; end; end
|
|
|
|
end
|
|
|
|
expect(Pry::Method.all_from_obj(@class).detect { |x| x.name == 'meth' }.owner)
|
|
|
|
.to eq(class << @class; self; end)
|
2011-10-02 02:30:33 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should attrbute overridden methods to the class not the module" do
|
2018-10-15 16:38:17 -04:00
|
|
|
@class = Class.new do
|
|
|
|
class << self
|
|
|
|
def meth; 1; end
|
|
|
|
end
|
|
|
|
extend(Module.new { def meth; 1; end })
|
|
|
|
end
|
2019-03-03 10:37:58 -05:00
|
|
|
expect(Pry::Method.all_from_obj(@class).detect { |x| x.name == 'meth' }.owner)
|
|
|
|
.to eq(class << @class; self; end)
|
2011-10-02 02:30:33 -04:00
|
|
|
end
|
|
|
|
|
2019-03-03 10:37:58 -05:00
|
|
|
it(
|
|
|
|
"attributes overridden methods to the relevant singleton class in " \
|
|
|
|
"preference to Class"
|
|
|
|
) do
|
2011-10-02 02:30:33 -04:00
|
|
|
@class = Class.new { class << self; def allocate; 1; end; end }
|
2019-03-03 10:37:58 -05:00
|
|
|
expect(Pry::Method.all_from_obj(@class).detect { |x| x.name == 'allocate' }.owner)
|
|
|
|
.to eq(class << @class; self; end)
|
2011-10-02 02:30:33 -04:00
|
|
|
end
|
|
|
|
end
|
2011-10-05 04:08:17 -04:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2015-02-16 15:10:00 -05:00
|
|
|
def eigen_class(obj); class << obj; self; end; end
|
2011-10-05 04:08:17 -04:00
|
|
|
|
|
|
|
it "should look at a class and then its superclass" do
|
2019-03-03 10:37:58 -05:00
|
|
|
expect(Pry::Method.instance_resolution_order(LS::Next))
|
|
|
|
.to eq [LS::Next] + Pry::Method.instance_resolution_order(LS::Top)
|
2011-10-05 04:08:17 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should include the included modules between a class and its superclass" do
|
2019-03-03 10:37:58 -05:00
|
|
|
expect(Pry::Method.instance_resolution_order(LS::Low)).to eq(
|
|
|
|
[LS::Low, LS::P, LS::N, LS::M] + Pry::Method.instance_resolution_order(LS::Next)
|
|
|
|
)
|
2011-10-05 04:08:17 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should not include modules extended into the class" do
|
2019-03-03 10:37:58 -05:00
|
|
|
expect(Pry::Method.instance_resolution_order(LS::Bottom)).to eq(
|
|
|
|
[LS::Bottom] + Pry::Method.instance_resolution_order(LS::Lower)
|
|
|
|
)
|
2011-10-05 04:08:17 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should include included modules for Modules" do
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(Pry::Method.instance_resolution_order(LS::O)).to eq [LS::O, LS::M]
|
2011-10-05 04:08:17 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should include the singleton class of objects" do
|
|
|
|
obj = LS::Low.new
|
2019-03-03 10:37:58 -05:00
|
|
|
expect(Pry::Method.resolution_order(obj)).to eq(
|
|
|
|
[eigen_class(obj)] + Pry::Method.instance_resolution_order(LS::Low)
|
|
|
|
)
|
2011-10-05 04:08:17 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should not include singleton classes of numbers" do
|
2017-06-03 07:10:36 -04:00
|
|
|
target_class = 4.class
|
2019-03-03 10:37:58 -05:00
|
|
|
expect(Pry::Method.resolution_order(4)).to eq(
|
|
|
|
Pry::Method.instance_resolution_order(target_class)
|
|
|
|
)
|
2011-10-05 04:08:17 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should include singleton classes for classes" do
|
2019-03-03 10:37:58 -05:00
|
|
|
expect(Pry::Method.resolution_order(LS::Low)).to eq(
|
|
|
|
[eigen_class(LS::Low)] + Pry::Method.resolution_order(LS::Next)
|
|
|
|
)
|
2011-10-05 04:08:17 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should include modules included into singleton classes" do
|
2019-03-03 10:37:58 -05:00
|
|
|
expect(Pry::Method.resolution_order(LS::Lower)).to eq(
|
|
|
|
[eigen_class(LS::Lower), LS::N, LS::M] + Pry::Method.resolution_order(LS::Low)
|
|
|
|
)
|
2011-10-05 04:08:17 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should include modules at most once" do
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(Pry::Method.resolution_order(LS::Bottom).count(LS::M)).to eq 1
|
2011-10-05 04:08:17 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "should include modules at the point which they would be reached" do
|
2019-03-03 10:37:58 -05:00
|
|
|
expect(Pry::Method.resolution_order(LS::Bottom)).to eq(
|
|
|
|
[eigen_class(LS::Bottom), LS::O] + Pry::Method.resolution_order(LS::Lower)
|
|
|
|
)
|
2011-10-05 04:08:17 -04:00
|
|
|
end
|
|
|
|
|
2019-03-03 10:37:58 -05:00
|
|
|
it(
|
|
|
|
"includes the Pry::Method.instance_resolution_order of Class after " \
|
|
|
|
"the singleton classes"
|
|
|
|
) do
|
2019-02-24 17:31:59 -05:00
|
|
|
singleton_classes = [
|
|
|
|
eigen_class(LS::Top), eigen_class(Object), eigen_class(BasicObject),
|
|
|
|
*Pry::Method.instance_resolution_order(Class)
|
|
|
|
]
|
|
|
|
expect(Pry::Method.resolution_order(LS::Top)).to eq(singleton_classes)
|
2011-10-05 04:08:17 -04:00
|
|
|
end
|
|
|
|
end
|
2011-10-02 02:30:33 -04:00
|
|
|
end
|
2011-11-26 21:33:13 -05:00
|
|
|
|
|
|
|
describe 'method_name_from_first_line' do
|
|
|
|
it 'should work in all simple cases' do
|
|
|
|
meth = Pry::Method.new(nil)
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth.send(:method_name_from_first_line, "def x")).to eq "x"
|
|
|
|
expect(meth.send(:method_name_from_first_line, "def self.x")).to eq "x"
|
|
|
|
expect(meth.send(:method_name_from_first_line, "def ClassName.x")).to eq "x"
|
|
|
|
expect(meth.send(:method_name_from_first_line, "def obj_name.x")).to eq "x"
|
2011-11-26 21:33:13 -05:00
|
|
|
end
|
|
|
|
end
|
2012-08-29 04:23:29 -04:00
|
|
|
|
|
|
|
describe 'method aliases' do
|
|
|
|
before do
|
2018-11-17 11:36:09 -05:00
|
|
|
@class = Class.new do
|
2019-02-28 18:34:50 -05:00
|
|
|
def eat; end
|
2012-08-29 04:23:29 -04:00
|
|
|
|
2019-02-26 18:00:16 -05:00
|
|
|
alias_method :fress, :eat
|
2012-08-29 04:23:29 -04:00
|
|
|
alias_method :omnomnom, :fress
|
|
|
|
|
2019-02-28 18:34:50 -05:00
|
|
|
def eruct; end
|
2018-11-17 11:36:09 -05:00
|
|
|
end
|
2012-08-29 04:23:29 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should be able to find method aliases' do
|
|
|
|
meth = Pry::Method(@class.new.method(:eat))
|
|
|
|
aliases = Set.new(meth.aliases)
|
|
|
|
|
2019-03-02 10:02:32 -05:00
|
|
|
expect(aliases).to eq Set.new(%w[fress omnomnom])
|
2012-08-29 04:23:29 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should return an empty Array if cannot find aliases' do
|
|
|
|
meth = Pry::Method(@class.new.method(:eruct))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth.aliases).to be_empty
|
2012-08-29 04:23:29 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should not include the own name in the list of aliases' do
|
|
|
|
meth = Pry::Method(@class.new.method(:eat))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth.aliases).not_to include "eat"
|
2012-08-29 04:23:29 -04:00
|
|
|
end
|
|
|
|
|
2013-11-15 21:37:42 -05:00
|
|
|
it 'should find aliases for top-level methods' do
|
|
|
|
# top-level methods get added as private instance methods on Object
|
|
|
|
class Object
|
|
|
|
private
|
2019-02-24 17:24:19 -05:00
|
|
|
|
2019-02-25 17:47:08 -05:00
|
|
|
def my_top_level_method; end
|
2013-11-15 21:37:42 -05:00
|
|
|
alias my_other_top_level_method my_top_level_method
|
|
|
|
end
|
|
|
|
|
|
|
|
meth = Pry::Method.new(method(:my_top_level_method))
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(meth.aliases).to include 'my_other_top_level_method'
|
2013-11-21 18:34:19 -05:00
|
|
|
|
|
|
|
class Object
|
|
|
|
remove_method :my_top_level_method
|
|
|
|
end
|
2013-11-15 21:37:42 -05:00
|
|
|
end
|
|
|
|
|
2013-10-24 01:58:26 -04:00
|
|
|
it 'should be able to find aliases for methods implemented in C' do
|
2019-02-28 18:31:34 -05:00
|
|
|
meth = Pry::Method({}.method(:key?))
|
2013-10-24 01:58:26 -04:00
|
|
|
aliases = Set.new(meth.aliases)
|
2012-08-29 04:23:29 -04:00
|
|
|
|
2015-03-10 16:49:29 -04:00
|
|
|
expect(aliases).to eq Set.new(["include?", "member?", "has_key?"])
|
2012-08-29 04:23:29 -04:00
|
|
|
end
|
|
|
|
end
|
2018-02-21 12:10:32 -05:00
|
|
|
|
|
|
|
describe '.signature' do
|
|
|
|
before do
|
2018-11-17 11:36:09 -05:00
|
|
|
@class = Class.new do
|
2018-02-21 12:10:32 -05:00
|
|
|
def self.standard_arg(arg) end
|
2018-10-14 02:23:34 -04:00
|
|
|
|
2018-02-21 12:10:32 -05:00
|
|
|
def self.block_arg(&block) end
|
2018-10-14 02:23:34 -04:00
|
|
|
|
2018-02-21 12:10:32 -05:00
|
|
|
def self.rest(*splat) end
|
2018-10-14 02:23:34 -04:00
|
|
|
|
2018-11-04 04:34:24 -05:00
|
|
|
def self.optional(option = nil) end
|
2018-11-17 11:36:09 -05:00
|
|
|
end
|
2018-02-21 12:10:32 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'should print the name of regular args' do
|
|
|
|
signature = Pry::Method.new(@class.method(:standard_arg)).signature
|
|
|
|
expect(signature).to eq("standard_arg(arg)")
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should print the name of block args, with an & label' do
|
|
|
|
signature = Pry::Method.new(@class.method(:block_arg)).signature
|
|
|
|
expect(signature).to eq("block_arg(&block)")
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should print the name of additional args, with an * label' do
|
|
|
|
signature = Pry::Method.new(@class.method(:rest)).signature
|
|
|
|
expect(signature).to eq("rest(*splat)")
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should print the name of optional args, with =? after the arg name' do
|
|
|
|
signature = Pry::Method.new(@class.method(:optional)).signature
|
|
|
|
expect(signature).to eq("optional(option=?)")
|
|
|
|
end
|
2018-02-22 19:13:38 -05:00
|
|
|
|
|
|
|
# keyword args are only on >= Ruby 2.1
|
|
|
|
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.1")
|
|
|
|
it 'should print the name of keyword args, with :? after the arg name' do
|
2019-03-23 13:06:27 -04:00
|
|
|
eval <<-RUBY, binding, __FILE__, __LINE__ + 1
|
|
|
|
def @class.keyword(keyword_arg: '')
|
|
|
|
end
|
|
|
|
RUBY
|
2018-02-22 19:13:38 -05:00
|
|
|
signature = Pry::Method.new(@class.method(:keyword)).signature
|
|
|
|
expect(signature).to eq("keyword(keyword_arg:?)")
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'should print the name of keyword args, with : after the arg name' do
|
2019-03-23 13:06:27 -04:00
|
|
|
eval <<-RUBY, binding, __FILE__, __LINE__ + 1
|
|
|
|
def @class.required_keyword(required_key:)
|
|
|
|
end
|
|
|
|
RUBY
|
2018-02-22 19:13:38 -05:00
|
|
|
signature = Pry::Method.new(@class.method(:required_keyword)).signature
|
|
|
|
expect(signature).to eq("required_keyword(required_key:)")
|
|
|
|
end
|
|
|
|
end
|
2018-02-21 12:10:32 -05:00
|
|
|
end
|
2020-03-21 04:16:38 -04:00
|
|
|
|
|
|
|
describe "#owner" do
|
|
|
|
context "when it is overriden in Object" do
|
|
|
|
before do
|
|
|
|
module OwnerMod
|
|
|
|
def owner
|
|
|
|
:fail
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
Object.__send__(:include, OwnerMod)
|
|
|
|
end
|
|
|
|
|
|
|
|
after { Object.remove_const(:OwnerMod) }
|
|
|
|
|
|
|
|
it "correctly reports the owner" do
|
|
|
|
method = described_class.new(method(:puts))
|
|
|
|
expect(method.owner).not_to eq(:fail)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "#parameters" do
|
|
|
|
context "when it is overriden in Object" do
|
|
|
|
before do
|
|
|
|
module ParametersMod
|
|
|
|
def parameters
|
|
|
|
:fail
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
Object.__send__(:include, ParametersMod)
|
|
|
|
end
|
|
|
|
|
|
|
|
after { Object.remove_const(:ParametersMod) }
|
|
|
|
|
|
|
|
it "correctly reports the parameters" do
|
|
|
|
method = described_class.new(method(:puts))
|
|
|
|
expect(method.parameters).not_to eq(:fail)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "#receiver" do
|
|
|
|
context "when it is overriden in Object" do
|
|
|
|
before do
|
|
|
|
module ReceiverMod
|
|
|
|
def receiver
|
|
|
|
:fail
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
Object.__send__(:include, ReceiverMod)
|
|
|
|
end
|
|
|
|
|
|
|
|
after { Object.remove_const(:ReceiverMod) }
|
|
|
|
|
|
|
|
it "correctly reports the receiver" do
|
|
|
|
method = described_class.new(method(:puts))
|
|
|
|
expect(method.receiver).not_to eq(:fail)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2011-09-19 04:18:57 -04:00
|
|
|
end
|