mirror of
https://github.com/pry/pry.git
synced 2022-11-09 12:35:05 -05:00
Added input_type method to determine where to dispatch show-source.
Enabled show-source to also work for any object that responds to source_location Local variables now takes precedence over methods that they shadow for show-source
This commit is contained in:
parent
98e32b1e11
commit
80bdcd44b0
6 changed files with 117 additions and 62 deletions
|
@ -144,8 +144,7 @@ class Pry
|
|||
# CommandErrors are caught by the REPL loop and displayed to the user. They
|
||||
# indicate an exceptional condition that's fatal to the current command.
|
||||
class CommandError < StandardError; end
|
||||
class NonMethodContextError < CommandError; end
|
||||
class NonMethodError < CommandError; end
|
||||
class MethodNotFound < CommandError; end
|
||||
|
||||
# indicates obsolete API
|
||||
class ObsoleteError < StandardError; end
|
||||
|
|
|
@ -189,7 +189,7 @@ class Pry
|
|||
|
||||
begin
|
||||
@method = method_object
|
||||
rescue NonMethodContextError => err
|
||||
rescue MethodNotFound => err
|
||||
end
|
||||
|
||||
if opts.present?(:patch) || (@method && @method.dynamically_defined?)
|
||||
|
|
|
@ -7,51 +7,72 @@ class Pry
|
|||
module ModuleIntrospectionHelpers
|
||||
attr_accessor :module_object
|
||||
|
||||
# is our target binding in a method?
|
||||
def method?
|
||||
!!method_object
|
||||
rescue NonMethodError,NonMethodContextError
|
||||
false
|
||||
def module_object
|
||||
name = args.first
|
||||
@module_object ||= WrappedModule.from_str(name, target)
|
||||
end
|
||||
|
||||
def module?(name)
|
||||
self.module_object = get_module(name)
|
||||
# @param [String]
|
||||
# @param [Binding] target The binding context of the input.
|
||||
# @return [Symbol] type of input
|
||||
def input_type(input,target)
|
||||
if input == ""
|
||||
:blank
|
||||
elsif target.eval("defined? #{input} ") =~ /variable/ &&
|
||||
target.eval(input).respond_to?(:source_location)
|
||||
:sourcable_object
|
||||
elsif Pry::Method.from_str(input,target)
|
||||
:method
|
||||
elsif Pry::WrappedModule.from_str(input, target)
|
||||
:module
|
||||
else
|
||||
:unknown
|
||||
end
|
||||
|
||||
def get_module(name)
|
||||
wrapped = Pry::WrappedModule.from_str(name, target)
|
||||
if !wrapped
|
||||
if args.empty? && internal_binding?(target)
|
||||
wrapped = Pry::WrappedModule(get_module_from_internal_binding)
|
||||
end
|
||||
end
|
||||
wrapped
|
||||
end
|
||||
|
||||
def get_module_from_internal_binding
|
||||
mod = target_self.is_a?(Module) ? target_self : target_self.class
|
||||
end
|
||||
|
||||
def proc?(name)
|
||||
target.eval(name).is_a? Proc
|
||||
rescue TypeError, NameError
|
||||
false
|
||||
end
|
||||
|
||||
def process(name)
|
||||
if module?(name)
|
||||
code_or_doc = process_module
|
||||
elsif method?
|
||||
code_or_doc = process_method
|
||||
elsif proc?(name)
|
||||
code_or_doc = process_proc
|
||||
input = args.join(" ")
|
||||
type = input_type(input, target)
|
||||
|
||||
code_or_doc = case type
|
||||
when :blank
|
||||
process_blank
|
||||
when :sourcable_object
|
||||
process_sourcable_object
|
||||
when :method
|
||||
process_method
|
||||
when :module
|
||||
process_module
|
||||
else
|
||||
command_error("method or module for '#{name}' could not be found or derived", false)
|
||||
command_error("method or module for '#{input}' could not be found or derived", false)
|
||||
end
|
||||
|
||||
render_output(code_or_doc, opts)
|
||||
end
|
||||
|
||||
def process_blank
|
||||
if mod = extract_module_from_internal_binding
|
||||
@module_object = mod
|
||||
process_module
|
||||
elsif meth = extract_method_from_binding
|
||||
@method_object = meth
|
||||
process_method
|
||||
else
|
||||
command_error("method or module for '' could not be derived", false)
|
||||
end
|
||||
end
|
||||
|
||||
def extract_module_from_internal_binding
|
||||
if args.empty? && internal_binding?(target)
|
||||
mod = target_self.is_a?(Module) ? target_self : target_self.class
|
||||
Pry::WrappedModule(mod)
|
||||
end
|
||||
end
|
||||
|
||||
def extract_method_from_binding
|
||||
Pry::Method.from_binding(target)
|
||||
end
|
||||
|
||||
def module_start_line(mod, candidate_rank=0)
|
||||
if opts.present?(:'base-one')
|
||||
1
|
||||
|
@ -256,6 +277,22 @@ class Pry
|
|||
opt.on :a, :all, "Show source for all definitions and monkeypatches of the module/class"
|
||||
end
|
||||
|
||||
def process_sourcable_object
|
||||
name = args.first
|
||||
object = target.eval(name)
|
||||
|
||||
file_name, line = object.source_location
|
||||
|
||||
source = Pry::Code.from_file(file_name).expression_at(line)
|
||||
code = Pry::Code.new(source).with_line_numbers(use_line_numbers?).to_s
|
||||
|
||||
result = ""
|
||||
result << "\n#{Pry::Helpers::Text.bold('From:')} #{file_name} @ line #{line}:\n"
|
||||
result << "#{Pry::Helpers::Text.bold('Number of lines:')} #{code.lines.count}\n\n"
|
||||
result << code
|
||||
result << "\n"
|
||||
end
|
||||
|
||||
def process_method
|
||||
raise CommandError, "Could not find method source" unless method_object.source
|
||||
|
||||
|
@ -313,24 +350,6 @@ class Pry
|
|||
result
|
||||
end
|
||||
|
||||
def process_proc
|
||||
name = args.first
|
||||
target_proc = target.eval(name)
|
||||
|
||||
file_name, line = target_proc.source_location
|
||||
|
||||
source = Pry::Code.from_file(file_name).expression_at(line)
|
||||
code = Pry::Code.new(source).with_line_numbers(use_line_numbers?).to_s
|
||||
#code = Pry::Code.new(target_proc.source, line).with_line_numbers(use_line_numbers?).to_s
|
||||
|
||||
|
||||
result = ""
|
||||
result << "\n#{Pry::Helpers::Text.bold('From:')} #{file_name} @ line #{line}:\n"
|
||||
result << "#{Pry::Helpers::Text.bold('Number of lines:')} #{code.lines.count}\n\n"
|
||||
result << code
|
||||
result << "\n"
|
||||
end
|
||||
|
||||
def use_line_numbers?
|
||||
opts.present?(:b) || opts.present?(:l)
|
||||
end
|
||||
|
|
|
@ -49,19 +49,19 @@ class Pry
|
|||
meth = Pry::Method.from_str(name, target, opts)
|
||||
|
||||
if name && !meth
|
||||
command_error("The method '#{name}' could not be found.", omit_help, NonMethodError)
|
||||
command_error("The method '#{name}' could not be found.", omit_help, MethodNotFound)
|
||||
end
|
||||
|
||||
(opts[:super] || 0).times do
|
||||
if meth.super
|
||||
meth = meth.super
|
||||
else
|
||||
command_error("'#{meth.name_with_owner}' has no super method.", omit_help, NonMethodError)
|
||||
command_error("'#{meth.name_with_owner}' has no super method.", omit_help, MethodNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
if !meth || (!name && internal_binding?(target))
|
||||
command_error("No method name given, and context is not a method.", omit_help, NonMethodContextError)
|
||||
command_error("No method name given, and context is not a method.", omit_help, MethodNotFound)
|
||||
end
|
||||
|
||||
set_file_and_dir_locals(meth.source_file)
|
||||
|
|
|
@ -126,6 +126,7 @@ end
|
|||
|
||||
def mock_pry(*args)
|
||||
|
||||
args.flatten!
|
||||
binding = args.first.is_a?(Binding) ? args.shift : binding()
|
||||
|
||||
input = InputTester.new(*args)
|
||||
|
|
|
@ -149,7 +149,7 @@ if !mri18_and_no_real_source_location?
|
|||
it "should not raise an exception when a non-extant super method is requested" do
|
||||
def @o.foo(*bars); end
|
||||
|
||||
mock_pry(binding, "show-source --super @o.foo").should =~ /'@o.foo' could not be found/
|
||||
mock_pry(binding, "show-source --super @o.foo").should =~ /'self.foo' has no super method/
|
||||
end
|
||||
|
||||
# dynamically defined method source retrieval is only supported in
|
||||
|
@ -194,7 +194,7 @@ if !mri18_and_no_real_source_location?
|
|||
end
|
||||
end
|
||||
|
||||
describe "on procs/lambdas" do
|
||||
describe "on sourcable objects" do
|
||||
|
||||
if RUBY_VERSION =~ /1.9/
|
||||
it "should output source defined inside pry" do
|
||||
|
@ -206,11 +206,47 @@ if !mri18_and_no_real_source_location?
|
|||
end
|
||||
end
|
||||
|
||||
it "should output source" do
|
||||
it "should output source for procs/lambdas" do
|
||||
hello = proc { puts 'hello world!' }
|
||||
mock_pry(binding, "show-source hello").should =~ /proc { puts 'hello world!' }/
|
||||
end
|
||||
|
||||
it "should output source for method objects" do
|
||||
def @o.hi; puts 'hi world'; end
|
||||
meth = @o.method(:hi)
|
||||
mock_pry(binding, "show-source meth").should =~ /puts 'hi world'/
|
||||
end
|
||||
|
||||
describe "on variables that shadow methods" do
|
||||
before do
|
||||
@method_shadow = [
|
||||
"class TestHost ",
|
||||
"def hello",
|
||||
"hello = proc { ' smile ' }",
|
||||
"binding.pry",
|
||||
"end",
|
||||
"end",
|
||||
"TestHost.new.hello"
|
||||
]
|
||||
end
|
||||
|
||||
after do
|
||||
Object.remove_const(:TestHost)
|
||||
end
|
||||
|
||||
it "source of variable should take precedence over method that is being shadowed" do
|
||||
string = mock_pry(@method_shadow,"show-source hello","exit-all")
|
||||
string.include?("def hello").should == false
|
||||
string =~ /proc { ' smile ' }/
|
||||
end
|
||||
|
||||
it "source of method being shadowed should take precedence over variable
|
||||
if given self.meth_name syntax" do
|
||||
string = mock_pry(@method_shadow,"show-source self.hello","exit-all")
|
||||
string.include?("def hello").should == true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "on modules" do
|
||||
|
|
Loading…
Reference in a new issue