[ruby/irb] Improve constant lookup in SourceFinder

(https://github.com/ruby/irb/pull/871)

https://github.com/ruby/irb/commit/87c279ccf2
This commit is contained in:
tomoya ishida 2024-02-14 22:46:45 +09:00 коммит произвёл git
Родитель eea7ce55de
Коммит d0412599e0
2 изменённых файлов: 47 добавлений и 3 удалений

Просмотреть файл

@ -69,10 +69,18 @@ module IRB
def find_source(signature, super_level = 0)
case signature
when /\A(::)?[A-Z]\w*(::[A-Z]\w*)*\z/ # Const::Name
when /\A(::)?[A-Z]\w*(::[A-Z]\w*)*\z/ # ConstName, ::ConstName, ConstPath::ConstName
eval_receiver_or_owner(signature) # trigger autoload
base = @irb_context.workspace.binding.receiver.yield_self { |r| r.is_a?(Module) ? r : Object }
file, line = base.const_source_location(signature)
*parts, name = signature.split('::', -1)
base =
if parts.empty? # ConstName
find_const_owner(name)
elsif parts == [''] # ::ConstName
Object
else # ConstPath::ConstName
eval_receiver_or_owner(parts.join('::'))
end
file, line = base.const_source_location(name)
when /\A(?<owner>[A-Z]\w*(::[A-Z]\w*)*)#(?<method>[^ :.]+)\z/ # Class#method
owner = eval_receiver_or_owner(Regexp.last_match[:owner])
method = Regexp.last_match[:method]
@ -122,5 +130,10 @@ module IRB
rescue NameError
raise EvaluationError
end
def find_const_owner(name)
module_nesting = @irb_context.workspace.binding.eval('::Module.nesting')
module_nesting.find { |mod| mod.const_defined?(name, false) } || module_nesting.find { |mod| mod.const_defined?(name) } || Object
end
end
end

Просмотреть файл

@ -362,5 +362,36 @@ module TestIRB
refute_match(/NameError/, out)
assert_match(%r[Defined in binary file:.+io/console], out)
end
def test_show_source_with_constant_lookup
write_ruby <<~RUBY
X = 1
module M
Y = 1
Z = 2
end
class A
Z = 1
Array = 1
class B
include M
Object.new.instance_eval { binding.irb }
end
end
RUBY
out = run_ruby_file do
type "show_source X"
type "show_source Y"
type "show_source Z"
type "show_source Array"
type "exit"
end
assert_match(%r[#{@ruby_file.to_path}:1\s+X = 1], out)
assert_match(%r[#{@ruby_file.to_path}:3\s+Y = 1], out)
assert_match(%r[#{@ruby_file.to_path}:7\s+Z = 1], out)
assert_match(%r[#{@ruby_file.to_path}:8\s+Array = 1], out)
end
end
end