Skip to content

Commit 87c279c

Browse files
authored
Improve constant lookup in SourceFinder (#871)
1 parent 8c16e02 commit 87c279c

File tree

2 files changed

+47
-3
lines changed

2 files changed

+47
-3
lines changed

lib/irb/source_finder.rb

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,18 @@ def initialize(irb_context)
6969

7070
def find_source(signature, super_level = 0)
7171
case signature
72-
when /\A(::)?[A-Z]\w*(::[A-Z]\w*)*\z/ # Const::Name
72+
when /\A(::)?[A-Z]\w*(::[A-Z]\w*)*\z/ # ConstName, ::ConstName, ConstPath::ConstName
7373
eval_receiver_or_owner(signature) # trigger autoload
74-
base = @irb_context.workspace.binding.receiver.yield_self { |r| r.is_a?(Module) ? r : Object }
75-
file, line = base.const_source_location(signature)
74+
*parts, name = signature.split('::', -1)
75+
base =
76+
if parts.empty? # ConstName
77+
find_const_owner(name)
78+
elsif parts == [''] # ::ConstName
79+
Object
80+
else # ConstPath::ConstName
81+
eval_receiver_or_owner(parts.join('::'))
82+
end
83+
file, line = base.const_source_location(name)
7684
when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
7785
owner = eval_receiver_or_owner(Regexp.last_match[:owner])
7886
method = Regexp.last_match[:method]
@@ -122,5 +130,10 @@ def eval_receiver_or_owner(code)
122130
rescue NameError
123131
raise EvaluationError
124132
end
133+
134+
def find_const_owner(name)
135+
module_nesting = @irb_context.workspace.binding.eval('::Module.nesting')
136+
module_nesting.find { |mod| mod.const_defined?(name, false) } || module_nesting.find { |mod| mod.const_defined?(name) } || Object
137+
end
125138
end
126139
end

test/irb/cmd/test_show_source.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,5 +362,36 @@ def test_show_source_shows_binary_source
362362
refute_match(/NameError/, out)
363363
assert_match(%r[Defined in binary file:.+io/console], out)
364364
end
365+
366+
def test_show_source_with_constant_lookup
367+
write_ruby <<~RUBY
368+
X = 1
369+
module M
370+
Y = 1
371+
Z = 2
372+
end
373+
class A
374+
Z = 1
375+
Array = 1
376+
class B
377+
include M
378+
Object.new.instance_eval { binding.irb }
379+
end
380+
end
381+
RUBY
382+
383+
out = run_ruby_file do
384+
type "show_source X"
385+
type "show_source Y"
386+
type "show_source Z"
387+
type "show_source Array"
388+
type "exit"
389+
end
390+
391+
assert_match(%r[#{@ruby_file.to_path}:1\s+X = 1], out)
392+
assert_match(%r[#{@ruby_file.to_path}:3\s+Y = 1], out)
393+
assert_match(%r[#{@ruby_file.to_path}:7\s+Z = 1], out)
394+
assert_match(%r[#{@ruby_file.to_path}:8\s+Array = 1], out)
395+
end
365396
end
366397
end

0 commit comments

Comments
 (0)