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

modify edit-method -p to support aliased methods that use super

This commit is contained in:
Ryan Fitzgerald 2011-10-15 22:07:52 -07:00
parent 231732616e
commit 509e908688
3 changed files with 102 additions and 7 deletions

View file

@ -225,8 +225,9 @@ class Pry
if opts.p? || meth.dynamically_defined?
lines = meth.source.lines.to_a
if lines[0] =~ /^def [^( \n]+/
lines[0] = "def #{meth.name}#{$'}"
if ((original_name = meth.original_name) &&
lines[0] =~ /^def (?:.*?\.)?#{original_name}(?=[\( ]|$)/)
lines[0] = "def #{original_name}#{$'}"
else
raise CommandError, "Pry can only patch methods created with the `def` keyword."
end
@ -235,7 +236,15 @@ class Pry
f.puts lines.join
f.flush
invoke_editor(f.path, 0)
Pry.new(:input => StringIO.new(File.read(f.path))).rep(meth.owner)
if meth.alias?
with_method_transaction(original_name, meth.owner) do
Pry.new(:input => StringIO.new(File.read(f.path))).rep(meth.owner)
Pry.binding_for(meth.owner).eval("alias #{meth.name} #{original_name}")
end
else
Pry.new(:input => StringIO.new(File.read(f.path))).rep(meth.owner)
end
end
next
end
@ -252,6 +261,17 @@ class Pry
end
end
helpers do
def with_method_transaction(meth_name, target=TOPLEVEL_BINDING)
target = Pry.binding_for(target)
temp_name = "__pry_#{meth_name}__"
target.eval("alias #{temp_name} #{meth_name}")
yield
target.eval("alias #{meth_name} #{temp_name}")
target.eval("undef #{temp_name}")
end
end
end
end
end

View file

@ -265,7 +265,7 @@ class Pry
"#{name}(#{args.join(', ')})"
end
# @return [Pry::Method, nil] The wrapped method that get's called when you
# @return [Pry::Method, nil] The wrapped method that is called when you
# use "super" in the body of this method.
def super(times=1)
if respond_to?(:receiver)
@ -277,6 +277,35 @@ class Pry
Pry::Method.new(sup) if sup
end
# @return [Symbol, nil] The original name the method was defined under,
# before any aliasing, or `nil` if it can't be determined.
def original_name
return nil if source_type != :ruby
first_line = source.lines.first
return nil if first_line.strip !~ /^def /
if RUBY_VERSION =~ /^1\.9/ && RUBY_ENGINE == "ruby"
require 'ripper'
tree = Ripper::SexpBuilder.new(first_line + ";end").parse
name = tree.flatten(2).each do |lst|
break lst[1] if lst[0] == :@ident
end
name.is_a?(String) ? name : nil
else
require 'ruby_parser'
tree = RubyParser.new.parse(first_line + ";end")
name = tree.each_cons(2) do |a, b|
break a if b.is_a?(Array) && b.first == :args
end
name.is_a?(Symbol) ? name.to_s : nil
end
end
# @return [Boolean] Was the method defined outside a source file?
def dynamically_defined?
!!(source_file and source_file =~ /(\(.*\))|<.*>/)
@ -287,6 +316,11 @@ class Pry
source_file == Pry.eval_path
end
# @return [Boolean] Is the method definitely an alias?
def alias?
name != original_name
end
# @return [Boolean]
def ==(obj)
if obj.is_a? Pry::Method

View file

@ -370,6 +370,10 @@ describe "Pry::DefaultCommands::Introspection" do
def a
:yup
end
def b
:kinda
end
end
class X
@ -382,6 +386,11 @@ describe "Pry::DefaultCommands::Introspection" do
def x
:nope
end
def b
super
end
alias c b
end
EOS
@tempfile.flush
@ -408,19 +417,19 @@ describe "Pry::DefaultCommands::Introspection" do
it "should correctly find a class method" do
mock_pry("edit-method X.x")
@file.should == @tempfile.path
@line.should == 10
@line.should == 14
end
it "should correctly find an instance method" do
mock_pry("edit-method X#x")
@file.should == @tempfile.path
@line.should == 14
@line.should == 18
end
it "should correctly find a method on an instance" do
mock_pry("x = X.new", "edit-method x.x")
@file.should == @tempfile.path
@line.should == 14
@line.should == 18
end
it "should correctly find a method from a module" do
@ -428,6 +437,12 @@ describe "Pry::DefaultCommands::Introspection" do
@file.should == @tempfile.path
@line.should == 2
end
it "should correctly find an aliased method" do
mock_pry("edit-method X#c")
@file.should == @tempfile.path
@line.should == 22
end
end
describe 'with -p' do
@ -478,6 +493,32 @@ describe "Pry::DefaultCommands::Introspection" do
X.new.a.should == :maybe
end
end
describe 'on an aliased method' do
before do
@old_editor = Pry.config.editor
Pry.config.editor = lambda do |file, line|
lines = File.read(file).lines.to_a
lines[1] = '"#{super}aa".to_sym' + "\n"
File.open(file, 'w') do |f|
f.write(lines.join)
end
nil
end
end
after do
Pry.config.editor = @old_editor
end
it "should change the alias, but not the original, without breaking super" do
mock_pry("edit-method -p X#c")
Pry::Method.from_str("X#c").alias?.should == true
X.new.b.should == :kinda
X.new.c.should == :kindaaa
end
end
end
end