diff --git a/lib/pry/default_commands/introspection.rb b/lib/pry/default_commands/introspection.rb index c6c03221..918cfa4f 100644 --- a/lib/pry/default_commands/introspection.rb +++ b/lib/pry/default_commands/introspection.rb @@ -20,13 +20,26 @@ class Pry def process(name) if module?(name) code_or_doc = process_module - else method? + elsif method? code_or_doc = process_method + else + code_or_doc = process_alternatives 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) + + process_module + else + process_method + end + end + def module_start_line(mod, candidate_rank=0) if opts.present?(:'base-one') 1 diff --git a/lib/pry/helpers/command_helpers.rb b/lib/pry/helpers/command_helpers.rb index 0f5582bf..26ae96fd 100644 --- a/lib/pry/helpers/command_helpers.rb +++ b/lib/pry/helpers/command_helpers.rb @@ -39,13 +39,16 @@ class Pry [file, line_num] end + def internal_binding?(target) + m = target.eval("__method__").to_s + ["__binding__", "__binding_impl__"].include?(m) + end + 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) - elsif !meth - command_error("No method name given, and context is not a method.", omit_help, NonMethodContextError) end (opts[:super] || 0).times do @@ -56,6 +59,10 @@ class Pry end end + if !meth || (!name && internal_binding?(target)) + command_error("No method name given, and context is not a method.", omit_help, NonMethodContextError) + end + set_file_and_dir_locals(meth.source_file) meth end diff --git a/test/test_default_commands/test_show_source.rb b/test/test_default_commands/test_show_source.rb index a3c93522..45c5efcd 100644 --- a/test/test_default_commands/test_show_source.rb +++ b/test/test_default_commands/test_show_source.rb @@ -321,6 +321,69 @@ if !mri18_and_no_real_source_location? result.should =~ /def instance_eval_method/ end end + + describe "when show-source is invoked without a method or class argument" do + before do + module Host + module M + def alpha; end + def beta; end + end + + module C + end + + module D + def self.invoked_in_method + redirect_pry_io(InputTester.new("show-source", "exit-all"), out = StringIO.new) do + Pry.start(binding) + end + out.string + end + end + end + end + + after do + Object.remove_const(:Host) + end + + describe "inside a module" do + it 'should display module source by default' do + redirect_pry_io(InputTester.new("show-source", "exit-all"), out = StringIO.new) do + Pry.start(Host::M) + end + + out.string.should =~ /module M/ + out.string.should =~ /def alpha/ + out.string.should =~ /def beta/ + end + + it 'should be unable to find module source if no methods defined' do + redirect_pry_io(InputTester.new("show-source", "exit-all"), out = StringIO.new) do + Pry.start(Host::C) + end + + out.string.should.should =~ /Cannot find a definition for/ + end + + it 'should display method code (rather than class) if Pry started inside method binding' do + string = Host::D.invoked_in_method + string.should =~ /invoked_in_method/ + string.should.not =~ /module D/ + end + + it 'should allow options to be passed' do + redirect_pry_io(InputTester.new("show-source -b", "exit-all"), out = StringIO.new) do + Pry.start(Host::M) + end + + out.string.should =~ /\d:\s*module M/ + out.string.should =~ /\d:\s*def alpha/ + out.string.should =~ /\d:\s*def beta/ + end + end + end end end end