require_relative '../helper' require "fixtures/show_source_doc_examples" describe "show-source" do before do @o = Object.new def @o.sample_method :sample end Object.remove_const :Test if Object.const_defined? :Test Object.const_set(:Test, Module.new) end after do Pad.clear end it "should output a method's source" do expect(pry_eval(binding, 'show-source @o.sample_method')).to match(/def @o.sample/) end it "should output help" do expect(pry_eval('show-source -h')).to match(/Usage:\s+show-source/) end it "should output a method's source with line numbers" do expect(pry_eval(binding, 'show-source -l @o.sample_method')).to match(/\d+: def @o.sample/) end it "should output a method's source with line numbers starting at 1" do expect(pry_eval(binding, 'show-source -b @o.sample_method')).to match(/1: def @o.sample/) end it "should output a method's source if inside method and no name given" do def @o.sample pry_eval(binding, 'show-source').should =~ /def @o.sample/ end @o.sample end it "should output a method's source inside method using the -l switch" do def @o.sample pry_eval(binding, 'show-source -l').should =~ /def @o.sample/ end @o.sample end it "should find methods even if there are spaces in the arguments" do def @o.foo(*_bars) @foo = "Mr flibble" self end out = pry_eval(binding, "show-source @o.foo('bar', 'baz bam').foo") expect(out).to match(/Mr flibble/) end it "should find methods even if the object overrides method method" do _c = Class.new{ def method; 98 end } expect(pry_eval(binding, "show-source _c.new.method")).to match(/98/) end it "should not show the source when a non-extant method is requested" do _c = Class.new{ def method; 98; end } expect(mock_pry(binding, "show-source _c#wrongmethod")).to match(/Couldn't locate/) end it "should not show the source and deliver an error message without exclamation point" do _c = Class.new error_message = "Error: Couldn't locate a definition for _c#wrongmethod\n" expect(mock_pry(binding, "show-source _c#wrongmethod")).to eq(error_message) end it "should find instance_methods if the class overrides instance_method" do _c = Class.new{ def method; 98 end def self.instance_method; 789; end } expect(pry_eval(binding, "show-source _c#method")).to match(/98/) end it "should find instance methods with self#moo" do _c = Class.new{ def moo; "ve over!"; end } expect(pry_eval(binding, "cd _c", "show-source self#moo")).to match(/ve over/) end it "should not find instance methods with self.moo" do _c = Class.new{ def moo; "ve over!"; end } expect { pry_eval(binding, 'cd _c', 'show-source self.moo') }.to raise_error(Pry::CommandError, /Couldn't locate/) end it "should find normal methods with self.moo" do _c = Class.new{ def self.moo; "ve over!"; end } expect(pry_eval(binding, 'cd _c', 'show-source self.moo')).to match(/ve over/) end it "should not find normal methods with self#moo" do _c = Class.new{ def self.moo; "ve over!"; end } expect { pry_eval(binding, 'cd _c', 'show-source self#moo') }.to raise_error(Pry::CommandError, /Couldn't locate/) end it "should find normal methods (i.e non-instance methods) by default" do _c = Class.new{ def self.moo; "ve over!"; end } expect(pry_eval(binding, "cd _c", "show-source moo")).to match(/ve over/) end it "should find instance methods if no normal methods available" do _c = Class.new{ def moo; "ve over!"; end } expect(pry_eval(binding, "cd _c", "show-source moo")).to match(/ve over/) end describe "with -e option" do before do class FooBar def bar :bar end end end after do Object.remove_const(:FooBar) end it "evaluates the argument as ruby and shows the source code for the returned value" do ReplTester.start target: binding do input 'show-source -e FooBar.new' output(/class FooBar/) end end end it "should raise a CommandError when super method doesn't exist" do def @o.foo(*bars); end expect { pry_eval(binding, "show-source --super @o.foo") }.to raise_error(Pry::CommandError, /No superclass found/) end it "should output the source of a method defined inside Pry" do out = pry_eval("def dyn_method\n:test\nend", 'show-source dyn_method') expect(out).to match(/def dyn_method/) Object.remove_method :dyn_method end it 'should output source for an instance method defined inside pry' do pry_tester.tap do |t| t.eval "class Test::A\n def yo\n end\nend" expect(t.eval('show-source Test::A#yo')).to match(/def yo/) end end it 'should output source for a repl method defined using define_method' do pry_tester.tap do |t| t.eval "class Test::A\n define_method(:yup) {}\nend" expect(t.eval('show-source Test::A#yup')).to match(/define_method\(:yup\)/) end end it "should output the source of a command defined inside Pry" do command_definition = %{ Pry.config.commands.command "hubba-hubba" do puts "that's what she said!" end } out = pry_eval(command_definition, 'show-source hubba-hubba') expect(out).to match(/what she said/) Pry.config.commands.delete "hubba-hubba" end context "when there's no source code but the comment exists" do before do class Foo # Bingo. def bar; end end allow_any_instance_of(Pry::Method).to receive(:source).and_return(nil) end after do Object.remove_const(:Foo) end it "outputs zero line numbers" do out = pry_eval('show-source Foo#bar') expect(out).to match(/ Owner:\sFoo .+ Number\sof\slines:\s0 .+ \*\*\sWarning:\sCannot\sfind\scode\sfor\s'bar'\s\(source_location\sis\snil\) /mx) end end describe "finding super methods with help of `--super` switch" do before do class Foo def foo(*_bars) :super_wibble end end end after do Object.remove_const(:Foo) end it "finds super methods with explicit method argument" do o = Foo.new def o.foo(*_bars) :wibble end expect(pry_eval(binding, "show-source --super o.foo")).to match(/:super_wibble/) end it "finds super methods without explicit method argument" do o = Foo.new def o.foo(*bars) @foo = :wibble pry_eval(binding, 'show-source --super') end expect(o.foo).to match(/:super_wibble/) end it "finds super methods with multiple --super " do o = Foo.new o.extend( Module.new do def foo :nibble end end ) def o.foo(*bars) @foo = :wibble pry_eval(binding, 'show-source --super --super') end expect(o.foo).to match(/:super_wibble/) end end describe "on sourcable objects" do it "should output source defined inside pry" do pry_tester.tap do |t| t.eval "hello = proc { puts 'hello world!' }" expect(t.eval("show-source hello")).to match(/proc \{ puts/) end end it "should output source for procs/lambdas stored in variables" do _hello = proc { puts 'hello world!' } expect(pry_eval(binding, 'show-source _hello')).to match(/proc \{ puts/) end it "should output source for procs/lambdas stored in constants" do HELLO = proc { puts 'hello world!' } expect(pry_eval(binding, "show-source HELLO")).to match(/proc \{ puts/) Object.remove_const(:HELLO) end it "should output source for method objects" do def @o.hi; puts 'hi world'; end _meth = @o.method(:hi) expect(pry_eval(binding, "show-source _meth")).to match(/puts 'hi world'/) end describe "on variables that shadow methods" do before do @t = pry_tester.eval unindent(<<-EOS) class ::TestHost def hello hello = proc { ' smile ' } _foo = hello pry_tester(binding) end end ::TestHost.new.hello EOS end after do Object.remove_const(:TestHost) end it "source of variable should take precedence over method that is being shadowed" do source = @t.eval('show-source hello') expect(source).not_to match(/def hello/) expect(source).to match(/proc \{ ' smile ' \}/) end it "source of method being shadowed should take precedence over variable if given self.meth_name syntax" do expect(@t.eval('show-source self.hello')).to match(/def hello/) end end end describe "on variable or constant" do before do class TestHost def hello "hi there" end end end after do Object.remove_const(:TestHost) end it "should output source of its class if variable doesn't respond to source_location" do _test_host = TestHost.new expect(pry_eval(binding, 'show-source _test_host')). to match(/class TestHost\n.*def hello/) end it "should output source of its class if constant doesn't respond to source_location" do TEST_HOST = TestHost.new expect(pry_eval(binding, 'show-source TEST_HOST')). to match(/class TestHost\n.*def hello/) Object.remove_const(:TEST_HOST) end end describe "on modules" do before do class ShowSourceTestSuperClass def alpha end end class ShowSourceTestClass