show-source/show-doc: Show the first module candidate with source/docs

Prior to this change `show-source ActiveRecord::Base` would fail, as the highest ranked
candidate couldn't be discovered.
This commit is contained in:
John Mair 2013-01-29 01:12:18 +01:00
parent 6e3800fa74
commit b7e70db004
4 changed files with 57 additions and 42 deletions

View File

@ -19,24 +19,40 @@ class Pry
def process def process
code_object = Pry::CodeObject.lookup(obj_name, _pry_, :super => opts[:super]) code_object = Pry::CodeObject.lookup(obj_name, _pry_, :super => opts[:super])
raise Pry::CommandError, "Couldn't locate #{obj_name}!" if !code_object cannot_locate_source_error if !code_object
if show_all_modules?(code_object) if show_all_modules?(code_object)
# show all monkey patches for a module # show all monkey patches for a module
@all_modules = true
result = content_and_headers_for_all_module_candidates(code_object) result = content_and_headers_for_all_module_candidates(code_object)
else else
# show a specific code object # show a specific code object
@all_modules = false co = code_object_with_accessible_source(code_object)
result = content_and_header_for_code_object(code_object) result = content_and_header_for_code_object(co)
end end
set_file_and_dir_locals(code_object.source_file) set_file_and_dir_locals(code_object.source_file)
stagger_output result stagger_output result
end end
# This method checks whether the `code_object` is a WrappedModule,
# if it is, then it returns the first candidate (monkeypatch) with
# accessible source (or docs). If `code_object` is not a WrappedModule (i.e a
# method or a command) then the `code_object` itself is just
# returned.
#
# @return [Pry::WrappedModule, Pry::Method, Pry::Command]
def code_object_with_accessible_source(code_object)
if code_object.is_a?(WrappedModule)
code_object.candidates.find(&:source).tap do |candidate|
cannot_locate_source_error if !candidate
end
else
code_object
end
end
def content_and_header_for_code_object(code_object) def content_and_header_for_code_object(code_object)
header(code_object) + content_for(code_object) header(code_object) + content_for(code_object)
end end
@ -58,6 +74,10 @@ class Pry
result result
end end
def cannot_locate_source_error
raise CommandError, "Couldn't locate a definition for #{obj_name}!"
end
# Generate a header (meta-data information) for all the code # Generate a header (meta-data information) for all the code
# object types: methods, modules, commands, procs... # object types: methods, modules, commands, procs...
def header(code_object) def header(code_object)
@ -124,10 +144,6 @@ class Pry
end end
end end
def all_modules?
@all_modules
end
def complete(input) def complete(input)
if input =~ /([^ ]*)#([a-z0-9_]*)\z/ if input =~ /([^ ]*)#([a-z0-9_]*)\z/
prefix, search = [$1, $2] prefix, search = [$1, $2]

View File

@ -25,6 +25,8 @@ class Pry
# The source for code_object prepared for display. # The source for code_object prepared for display.
def content_for(code_object) def content_for(code_object)
cannot_locate_source_error if !code_object.source
Code.new(code_object.source, start_line_for(code_object)). Code.new(code_object.source, start_line_for(code_object)).
with_line_numbers(use_line_numbers?).to_s with_line_numbers(use_line_numbers?).to_s
end end

View File

@ -279,34 +279,34 @@ if !PryTestHelpers.mri18_and_no_real_source_location?
# FIXME: THis is nto a good spec anyway, because i dont think it # FIXME: THis is nto a good spec anyway, because i dont think it
# SHOULD skip! # SHOULD skip!
# describe "should skip over broken modules" do describe "should skip over broken modules" do
# before do before do
# module TestHost module TestHost
# # hello # hello
# module M module M
# binding.eval("def a; end", "dummy.rb", 1) binding.eval("def a; end", "dummy.rb", 1)
# binding.eval("def b; end", "dummy.rb", 2) binding.eval("def b; end", "dummy.rb", 2)
# binding.eval("def c; end", "dummy.rb", 3) binding.eval("def c; end", "dummy.rb", 3)
# end end
# # goodbye # goodbye
# module M module M
# def d; end def d; end
# def e; end def e; end
# end end
# end end
# end end
# after do after do
# Object.remove_const(:TestHost) Object.remove_const(:TestHost)
# end end
# it 'should return doc for first valid module' do it 'should return doc for first valid module' do
# result = pry_eval("show-doc TestHost::M") result = pry_eval("show-doc TestHost::M")
# result.should =~ /goodbye/ result.should =~ /goodbye/
# result.should.not =~ /hello/ result.should.not =~ /hello/
# end end
# end end
end end
describe "on commands" do describe "on commands" do

View File

@ -491,7 +491,7 @@ if !PryTestHelpers.mri18_and_no_real_source_location?
proc { proc {
pry_eval(TestHost::C, 'show-source') pry_eval(TestHost::C, 'show-source')
}.should.raise(Pry::CommandError). }.should.raise(Pry::CommandError).
message.should =~ /Cannot find a definition for/ message.should =~ /Couldn't locate/
end end
it 'should display method code (rather than class) if Pry started inside method binding' do it 'should display method code (rather than class) if Pry started inside method binding' do
@ -535,14 +535,11 @@ if !PryTestHelpers.mri18_and_no_real_source_location?
Object.remove_const(:BabyDuck) Object.remove_const(:BabyDuck)
end end
# TODO: !!! This is a bad spec, should not be expected behaviour?!?! it 'should return source for first valid module' do
# out = pry_eval('show-source BabyDuck::Muesli')
# it 'should return source for first valid module' do out.should =~ /def d; end/
# out = pry_eval('show-source BabyDuck::Muesli') out.should.not =~ /def a; end/
# out.should =~ /def d; end/ end
# out.should.not =~ /def a; end/
# end
end end
end end
end end