mirror of
https://github.com/pry/pry.git
synced 2022-11-09 12:35:05 -05:00
Pry::Method.from_binding support for super methods. [Fixes #378]
This commit is contained in:
parent
322460f06d
commit
26cef7e411
2 changed files with 92 additions and 4 deletions
|
@ -49,11 +49,43 @@ class Pry
|
|||
if [:__script__, nil, :__binding__, :__binding_impl__].include?(meth_name)
|
||||
nil
|
||||
else
|
||||
begin
|
||||
new(b.eval("method(#{meth_name.to_s.inspect})"))
|
||||
rescue NameError, NoMethodError
|
||||
Disowned.new(b.eval('self'), meth_name.to_s)
|
||||
method = begin
|
||||
new(b.eval("method(#{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
|
||||
|
||||
|
@ -256,6 +288,12 @@ class Pry
|
|||
source_location.nil? ? nil : source_location.last
|
||||
end
|
||||
|
||||
# @return [Range, nil] The range of lines in `source_file` which contain
|
||||
# the method's definition, or `nil` if that information is unavailable.
|
||||
def source_range
|
||||
source_location.nil? ? nil : (source_line)...(source_line + source.lines.count)
|
||||
end
|
||||
|
||||
# @return [Symbol] The visibility of the method. May be `:public`,
|
||||
# `:protected`, or `:private`.
|
||||
def visibility
|
||||
|
|
|
@ -74,6 +74,56 @@ describe Pry::Method do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.from_binding' do
|
||||
it 'should be able to pick a method out of a binding' do
|
||||
Pry::Method.from_binding(Class.new{ def self.foo; binding; end }.foo).name.should == "foo"
|
||||
end
|
||||
|
||||
it 'should NOT find a method from the special pry bindings' do
|
||||
Pry::Method.from_binding(5.__binding__).should == nil
|
||||
end
|
||||
|
||||
it 'should NOT find a method from the toplevel binding' do
|
||||
Pry::Method.from_binding(TOPLEVEL_BINDING).should == nil
|
||||
end
|
||||
|
||||
it "should find methods that have been undef'd" do
|
||||
m = Pry::Method.from_binding(Class.new do
|
||||
def self.bar
|
||||
class << self; undef bar; end
|
||||
binding
|
||||
end
|
||||
end.bar)
|
||||
m.name.should == "bar"
|
||||
end
|
||||
|
||||
# Our source_location trick doesn't work, due to https://github.com/rubinius/rubinius/issues/953
|
||||
unless defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /rbx/
|
||||
it 'should find the super method correctly' do
|
||||
a = Class.new{ def gag; binding; end; def self.line; __LINE__; end }
|
||||
b = Class.new(a){ def gag; super; end }
|
||||
|
||||
g = b.new.gag
|
||||
m = Pry::Method.from_binding(g)
|
||||
|
||||
m.owner.should == a
|
||||
m.source_line.should == a.line
|
||||
m.name.should == "gag"
|
||||
end
|
||||
end
|
||||
|
||||
it 'should find the right method if a super method exists' do
|
||||
a = Class.new{ def gag; binding; end; }
|
||||
b = Class.new(a){ def gag; super; binding; end; def self.line; __LINE__; end }
|
||||
|
||||
m = Pry::Method.from_binding(b.new.gag)
|
||||
|
||||
m.owner.should == b
|
||||
m.source_line.should == b.line
|
||||
m.name.should == "gag"
|
||||
end
|
||||
end
|
||||
|
||||
describe 'all_from_class' do
|
||||
def should_find_method(name)
|
||||
Pry::Method.all_from_class(@class).map(&:name).should.include(name)
|
||||
|
|
Loading…
Reference in a new issue