mirror of
https://github.com/pry/pry.git
synced 2022-11-09 12:35:05 -05:00
edit command: add --method option
* --method doesn't accept any parameters, it only edits the 'current' method associated with the binding. It's equivalent to 'edit-method' (with no args). * This option is necessary as 'edit' by itself edits the last expression. * Note that --method doesn't just edit the current method, if no method exists (i.e binding.pry was not put inside a method context) then it edits the current OBJECT instead. TODO: * explicitly restrict --method to *just* methods and not allow it to fall back to objects? * allow --method to take a parameter that must be a method object? e.g --method Pry#repl works but --method Pry would fail ?
This commit is contained in:
parent
7ae55b3a8a
commit
503e6bb63f
2 changed files with 105 additions and 28 deletions
|
@ -1,11 +1,4 @@
|
|||
class Pry
|
||||
# Uses the following state variables:
|
||||
# - dynamical_ex_file [Array<String>]
|
||||
# Utilised in `edit --ex --patch` operations. Contains the source code
|
||||
# of a monkey patched file, in which an exception was raised. We store
|
||||
# the entire source code because an exception may happen anywhere in the
|
||||
# code and there is no way to predict that. So we simply superimpose
|
||||
# everything (admittedly, doing extra job).
|
||||
class Command::Edit < Pry::ClassCommand
|
||||
require 'pry/commands/edit/method_patcher'
|
||||
require 'pry/commands/edit/exception_patcher'
|
||||
|
@ -24,6 +17,7 @@ class Pry
|
|||
edit sample.rb
|
||||
edit sample.rb --line 105
|
||||
edit MyClass#my_method
|
||||
edit --method
|
||||
edit -p MyClass#my_method
|
||||
edit YourClass
|
||||
edit --ex`
|
||||
|
@ -43,11 +37,12 @@ class Pry
|
|||
opt.on :c, :current, "Open the current __FILE__ and at __LINE__ (as returned by `whereami`)"
|
||||
opt.on :r, :reload, "Reload the edited code immediately (default for ruby files)"
|
||||
opt.on :p, :patch, "Instead of editing the object's file, try to edit in a tempfile and apply as a monkey patch"
|
||||
opt.on :m, :method, "Explicitly edit the _current_ method (when inside a method context)."
|
||||
end
|
||||
|
||||
def process
|
||||
if bad_option_combination?
|
||||
raise CommandError, "Only one of --ex, --temp, --in and FILE may be specified."
|
||||
raise CommandError, "Only one of --ex, --temp, --in, --method and FILE may be specified."
|
||||
end
|
||||
|
||||
if repl_edit?
|
||||
|
@ -62,6 +57,11 @@ class Pry
|
|||
end
|
||||
end
|
||||
|
||||
def repl_edit?
|
||||
!opts.present?(:ex) && !opts.present?(:current) && !opts.present?(:method) &&
|
||||
filename_argument.empty?
|
||||
end
|
||||
|
||||
def repl_edit
|
||||
content = Pry::Editor.edit_tempfile_with_content(initial_temp_file_content,
|
||||
initial_temp_file_content.lines.count)
|
||||
|
@ -72,10 +72,13 @@ class Pry
|
|||
end
|
||||
end
|
||||
|
||||
def runtime_patch?
|
||||
opts.present?(:patch) || pry_method?(code_object)
|
||||
end
|
||||
|
||||
def apply_runtime_patch
|
||||
if patch_exception?
|
||||
ex_file_and_line = FileAndLineLocator.from_exception(_pry_.last_exception, opts[:ex].to_i)
|
||||
ExceptionPatcher.new(_pry_, state, ex_file_and_line).perform_patch
|
||||
ExceptionPatcher.new(_pry_, state, file_and_line_for_current_exception).perform_patch
|
||||
else
|
||||
if code_object.is_a?(Pry::Method)
|
||||
MethodPatcher.new(_pry_, code_object).perform_patch
|
||||
|
@ -86,20 +89,24 @@ class Pry
|
|||
end
|
||||
|
||||
def ensure_file_name_is_valid(file_name)
|
||||
raise CommandError, "Cannot find a valid file for #{args.first}" if !file_name
|
||||
raise CommandError, "Cannot find a valid file for #{filename_argument}" if !file_name
|
||||
raise CommandError, "#{file_name} is not a valid file name, cannot edit!" if not_a_real_file?(file_name)
|
||||
end
|
||||
|
||||
def file_and_line_for_current_exception
|
||||
FileAndLineLocator.from_exception(_pry_.last_exception, opts[:ex].to_i)
|
||||
end
|
||||
|
||||
def file_and_line
|
||||
file_name, line = if opts.present?(:current)
|
||||
FileAndLineLocator.from_binding(target)
|
||||
elsif opts.present?(:ex)
|
||||
FileAndLineLocator.from_exception(_pry_.last_exception, opts[:ex].to_i)
|
||||
file_and_line_for_current_exception
|
||||
elsif code_object
|
||||
FileAndLineLocator.from_code_object(code_object, args.first)
|
||||
FileAndLineLocator.from_code_object(code_object, filename_argument)
|
||||
else
|
||||
# when file and line are passed as a single arg, e.g my_file.rb:30
|
||||
FileAndLineLocator.from_filename_argument(args.first)
|
||||
FileAndLineLocator.from_filename_argument(filename_argument)
|
||||
end
|
||||
|
||||
[file_name, opts.present?(:line) ? opts[:l].to_i : line]
|
||||
|
@ -107,6 +114,7 @@ class Pry
|
|||
|
||||
def file_edit
|
||||
file_name, line = file_and_line
|
||||
|
||||
ensure_file_name_is_valid(file_name)
|
||||
|
||||
# Sanitize blanks.
|
||||
|
@ -122,22 +130,18 @@ class Pry
|
|||
end
|
||||
end
|
||||
|
||||
def filename_argument
|
||||
args.first || ""
|
||||
end
|
||||
|
||||
def code_object
|
||||
@code_object ||= args.first && !probably_a_file?(args.first) &&
|
||||
Pry::CodeObject.lookup(args.first, target, _pry_)
|
||||
@code_object ||= !probably_a_file?(filename_argument) &&
|
||||
Pry::CodeObject.lookup(filename_argument, _pry_)
|
||||
end
|
||||
|
||||
def repl_edit?
|
||||
!opts.present?(:ex) && !opts.present?(:current) && args.empty?
|
||||
end
|
||||
|
||||
def runtime_patch?
|
||||
opts.present?(:patch) || dynamically_defined_method?
|
||||
end
|
||||
|
||||
def dynamically_defined_method?
|
||||
def pry_method?(code_object)
|
||||
code_object.is_a?(Pry::Method) &&
|
||||
code_object.dynamically_defined?
|
||||
code_object.pry_method?
|
||||
end
|
||||
|
||||
def patch_exception?
|
||||
|
@ -146,7 +150,7 @@ class Pry
|
|||
|
||||
def bad_option_combination?
|
||||
[opts.present?(:ex), opts.present?(:temp),
|
||||
opts.present?(:in), !args.empty?].count(true) > 1
|
||||
opts.present?(:in), opts.present?(:method), !filename_argument.empty?].count(true) > 1
|
||||
end
|
||||
|
||||
def input_expression
|
||||
|
|
|
@ -307,7 +307,7 @@ describe "edit" do
|
|||
proc {
|
||||
pry_eval 'edit ruby.rb -i'
|
||||
}.should.raise(Pry::CommandError).
|
||||
message.should =~ /Only one of --ex, --temp, --in and FILE/
|
||||
message.should =~ /Only one of --ex, --temp, --in, --method and FILE/
|
||||
end
|
||||
|
||||
it "should not work with nonsense" do
|
||||
|
@ -623,4 +623,77 @@ describe "edit" do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "--method flag" do
|
||||
before do
|
||||
@t = pry_tester
|
||||
class BinkyWink
|
||||
eval %{
|
||||
def tits_macgee
|
||||
binding
|
||||
end
|
||||
}
|
||||
|
||||
def tots_macgee
|
||||
:jeremy_jones
|
||||
binding
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
after do
|
||||
Object.remove_const(:BinkyWink)
|
||||
end
|
||||
|
||||
it 'should edit method context' do
|
||||
old_editor = Pry.editor
|
||||
Pry.editor = lambda do |file, line|
|
||||
[file, line].should == BinkyWink.instance_method(:tots_macgee).source_location
|
||||
nil
|
||||
end
|
||||
|
||||
t = pry_tester(BinkyWink.new.tots_macgee)
|
||||
t.process_command "edit -m -n"
|
||||
Pry.editor = old_editor
|
||||
end
|
||||
|
||||
it 'errors when cannot find method context' do
|
||||
old_editor = Pry.editor
|
||||
Pry.editor = lambda do |file, line|
|
||||
[file, line].should == BinkyWink.instance_method(:tits_macgee).source_location
|
||||
nil
|
||||
end
|
||||
|
||||
t = pry_tester(BinkyWink.new.tits_macgee)
|
||||
lambda { t.process_command "edit -m -n" }.should.
|
||||
raise(Pry::CommandError).message.should.match(/Cannot find a file for/)
|
||||
Pry.editor = old_editor
|
||||
end
|
||||
|
||||
it 'errors when a filename arg is passed with --method' do
|
||||
lambda { @t.process_command "edit -m Pry#repl" }.should.
|
||||
raise(Pry::CommandError).message.should.match(/Only one of/)
|
||||
end
|
||||
end
|
||||
|
||||
describe "pretty error messages" do
|
||||
before do
|
||||
@t = pry_tester
|
||||
class TrinkyDink
|
||||
eval %{
|
||||
def claudia_linklater
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
after do
|
||||
Object.remove_const(:TrinkyDink)
|
||||
end
|
||||
|
||||
it 'should display a nice error message when cannot open a file' do
|
||||
lambda { @t.process_command "edit TrinkyDink#claudia_linklater" }.should.
|
||||
raise(Pry::CommandError).message.should.match(/Cannot find a file for/)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue