lib/ruby-lint/constant_path.rb
module RubyLint
##
# The ConstantPath class can be used for various operations on a constant AST
# node such as generating the full constant name.
#
# @!attribute [r] node
# @return [RubyLint::AST::Node]
#
class ConstantPath
attr_reader :node
##
# Hash containing node types to remap when resolving them.
#
# @return [Hash]
#
REMAP_TYPES = {
:casgn => :const
}
##
# @param [RubyLint::AST::Node] node
#
def initialize(node)
@node = node
end
##
# Retrieves the definition associated with the constant path and returns
# it, or `nil` if no definition was found.
#
# @param [RubyLint::Definition::RubyObject] scope The scope to use for the
# lookups.
# @return [RubyLint::Definition::RubyObject|NilClass]
#
def resolve(scope)
current = scope
constant_segments.each_with_index do |(type, name), index|
type = REMAP_TYPES.fetch(type, type)
found = current.lookup(type, name, index == 0)
if found and (found.const? or found.type == :root)
current = found
# Local variables and the likes.
elsif found and found.value
current = found.value
else
return
end
end
return current
end
##
# Returns a String containing the full constant path, e.g.
# "RubyLint::Runner".
#
# @return [String]
#
def to_s
return constant_segments.map { |seg| seg[1] }.join('::')
end
##
# Returns an Array containing the segments of a constant path.
#
# @param [RubyLint::AST::Node] node
# @return [Array<Array(Symbol,String)>]
#
def constant_segments(node = self.node)
segments = []
if has_child_node?(node)
segments.concat(constant_segments(node.children[0]))
end
segments << [node.type, name_for_node(node)]
return segments
end
private
##
# @param [RubyLint::AST::Node] node
# @return [TrueClass|FalseClass]
#
def has_child_node?(node)
return node.children[0] && node.children[0].is_a?(AST::Node)
end
##
# @param [RubyLint::AST::Node] node
# @return [String]
#
def name_for_node(node)
if node.type == :casgn
return node.children[1].to_s
else
return node.name
end
end
end # ConstantPath
end # RubyLint