class IRB::SourceFinder
Public Class Methods
new(irb_context)
click to toggle source
# File lib/irb/source_finder.rb, line 66 def initialize(irb_context) @irb_context = irb_context end
Public Instance Methods
find_source(signature, super_level = 0)
click to toggle source
# File lib/irb/source_finder.rb, line 70 def find_source(signature, super_level = 0) case signature when /\A(::)?[A-Z]\w*(::[A-Z]\w*)*\z/ # ConstName, ::ConstName, ConstPath::ConstName eval_receiver_or_owner(signature) # trigger autoload *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] 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/ # method, receiver.method, receiver::method 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 # Method defined with eval, probably in IRB session source = RubyVM::AbstractSyntaxTree.of(method)&.source rescue nil Source.new(file, line, source) end rescue EvaluationError nil end
Private Instance Methods
eval_receiver_or_owner(code)
click to toggle source
# File lib/irb/source_finder.rb, line 127 def eval_receiver_or_owner(code) context_binding = @irb_context.workspace.binding eval(code, context_binding) rescue NameError raise EvaluationError end
find_const_owner(name)
click to toggle source
# File lib/irb/source_finder.rb, line 134 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
method_target(owner_receiver, super_level, method, type)
click to toggle source
# File lib/irb/source_finder.rb, line 112 def method_target(owner_receiver, super_level, method, type) case type when "owner" target_method = owner_receiver.instance_method(method) when "receiver" target_method = owner_receiver.method(method) end super_level.times do |s| target_method = target_method.super_method if target_method end target_method rescue NameError nil end