Skip to content
Browse files

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
  • Loading branch information...
1 parent 98e32b1 commit 80bdcd44b08fc92ec2debeaf77616cc02d0a2f48 @redgetan redgetan committed Jul 17, 2012
View
3 lib/pry.rb
@@ -144,8 +144,7 @@ def self.===(exception)
# 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
View
2 lib/pry/default_commands/editing.rb
@@ -189,7 +189,7 @@ def process
begin
@method = method_object
- rescue NonMethodContextError => err
+ rescue MethodNotFound => err
end
if opts.present?(:patch) || (@method && @method.dynamically_defined?)
View
119 lib/pry/default_commands/introspection.rb
@@ -7,49 +7,70 @@ module DefaultCommands
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)
- 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
+ # @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
- wrapped
end
- def get_module_from_internal_binding
- mod = target_self.is_a?(Module) ? target_self : target_self.class
- end
+ def process(name)
+ 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 '#{input}' could not be found or derived", false)
+ end
- def proc?(name)
- target.eval(name).is_a? Proc
- rescue TypeError, NameError
- false
+ render_output(code_or_doc, opts)
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
+ 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 '#{name}' could not be found or derived", false)
+ command_error("method or module for '' could not be derived", false)
end
+ end
- render_output(code_or_doc, opts)
+ 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)
@@ -256,6 +277,22 @@ def options(opt)
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 @@ def all_modules
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
View
6 lib/pry/helpers/command_helpers.rb
@@ -49,19 +49,19 @@ def get_method_or_raise(name, target, opts={}, omit_help=false)
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)
View
1 test/helper.rb
@@ -126,6 +126,7 @@ def redirect_pry_io(new_in, new_out = StringIO.new)
def mock_pry(*args)
+ args.flatten!
binding = args.first.is_a?(Binding) ? args.shift : binding()
input = InputTester.new(*args)
View
42 test/test_default_commands/test_show_source.rb
@@ -149,7 +149,7 @@ def o.foo(*bars)
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 @@ def @o.foo(*bars); end
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 @@ def @o.foo(*bars); end
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

0 comments on commit 80bdcd4

Please sign in to comment.
Something went wrong with that request. Please try again.