Skip to content
Browse files

Merge branch 'show_source_proc' Fixes #600

  • Loading branch information...
2 parents 94e77ef + 80bdcd4 commit 94b8b0e5cad07e4a39a896ae50db23a3fb5e2b06 @redgetan redgetan committed Jul 18, 2012
View
2 lib/pry.rb
@@ -144,7 +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 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
87 lib/pry/default_commands/introspection.rb
@@ -7,39 +7,72 @@ module DefaultCommands
module ModuleIntrospectionHelpers
attr_accessor :module_object
- def module?(name)
- self.module_object = Pry::WrappedModule.from_str(name, target)
+ def module_object
+ name = args.first
+ @module_object ||= WrappedModule.from_str(name, target)
end
- def method?
- !!method_object
- rescue CommandError
- false
+ # @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
end
def process(name)
- if module?(name)
- code_or_doc = process_module
- elsif method?
- code_or_doc = process_method
- else
- code_or_doc = process_alternatives
- end
+ 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
render_output(code_or_doc, opts)
end
- def process_alternatives
- if args.empty? && internal_binding?(target)
- mod = target_self.is_a?(Module) ? target_self : target_self.class
- self.module_object = Pry::WrappedModule(mod)
-
+ def process_blank
+ if mod = extract_module_from_internal_binding
+ @module_object = mod
process_module
- else
+ 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
@@ -244,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
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)
+ 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)
+ 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
55 test/test_default_commands/test_show_source.rb
@@ -194,6 +194,61 @@ def @o.foo(*bars); end
end
end
+ describe "on sourcable objects" do
+
+ if RUBY_VERSION =~ /1.9/
+ it "should output source defined inside pry" do
+ redirect_pry_io(InputTester.new("hello = proc { puts 'hello world!' }", "show-source hello"), @str_output) do
+ TOPLEVEL_BINDING.pry
+ end
+
+ @str_output.string.should =~ /proc { puts 'hello world!' }/
+ end
+ end
+
+ 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
before do
class ShowSourceTestClass

0 comments on commit 94b8b0e

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