def find_source(signature, super_level = 0)
case signature
when /\A(::)?[A-Z]\w*(::[A-Z]\w*)*\z/
eval_receiver_or_owner(signature)
*parts, name = signature.split('::', -1)
base =
if parts.empty?
find_const_owner(name)
elsif parts == ['']
Object
else
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/
owner = eval_receiver_or_owner(Regexp.last_match[:owner])
method = Regexp.last_match[:method]
return unless owner.respond_to?(:instance_method)
method = method_target(owner, super_level, method, "owner")
file, line = method&.source_location
when /\A((?<receiver>.+)(\.|::))?(?<method>[^ :.]+)\z/
receiver = eval_receiver_or_owner(Regexp.last_match[:receiver] || 'self')
method = Regexp.last_match[:method]
return unless receiver.respond_to?(method, true)
method = method_target(receiver, super_level, method, "receiver")
file, line = method&.source_location
end
return unless file && line
if File.exist?(file)
Source.new(file, line)
elsif method
source = RubyVM::InstructionSequence.of(method)&.script_lines&.join rescue nil
Source.new(file, line, source)
end
rescue EvaluationError
nil
end