Module: Rigor::ModuleGraph::ConstantName

Defined in:
lib/rigor/module_graph/constant_name.rb

Overview

Resolves a fully-qualified constant name from Prism AST nodes and lexical ancestor chains.

Three things this module handles that the bare Prism API does not give you in one place:

  • Owner from lexical nesting. ‘node.constant_path.full_name` on a `class Billing::Invoice` only returns `“Invoice”`; the outer `module Billing` does not enter unless we walk ancestors ourselves.

  • Absolute paths (‘::Foo::Bar`). Prism encodes the leading `::` as an empty-symbol `:“”` in `full_name_parts`; we render it as `“::Foo::Bar”`.

  • Mixed AST shapes. ‘ClassNode#constant_path` is either a `ConstantReadNode` (single name) or a `ConstantPathNode` (dotted path); same for `superclass` and `include` args.

Class Method Summary collapse

Class Method Details

.full_name_for_path(node) ⇒ Object



74
75
76
77
78
79
80
81
82
83
# File 'lib/rigor/module_graph/constant_name.rb', line 74

def full_name_for_path(node)
  parts = node.full_name_parts
  # Prism encodes a leading `::` as an empty-symbol first
  # part. Render it as a literal `"::"` prefix.
  if parts.first == :""
    "::" + parts.drop(1).join("::")
  else
    parts.join("::")
  end
end

.lexical_owner(context) ⇒ Object

Build the lexical-nesting owner string for a node, by walking ‘context.ancestors` from outer to inner and joining every enclosing `ClassNode`/`ModuleNode` constant path with `::`. Returns nil when no class/module encloses the node.



43
44
45
46
47
48
# File 'lib/rigor/module_graph/constant_name.rb', line 43

def lexical_owner(context)
  parts = lexical_parts(context.ancestors)
  return nil if parts.empty?

  parts.join("::")
end

.lexical_owner_with(context, extra) ⇒ Object

Same as ‘#lexical_owner`, but with `extra` appended as the innermost element. Used to build the owner of a class or module decl itself: pass `context.ancestors` (which does NOT include the node itself) plus the node’s own constant path.



54
55
56
57
58
59
60
# File 'lib/rigor/module_graph/constant_name.rb', line 54

def lexical_owner_with(context, extra)
  parts = lexical_parts(context.ancestors)
  parts << extra unless extra.nil? || extra.empty?
  return nil if parts.empty?

  parts.join("::")
end

.lexical_parts(ancestors) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
# File 'lib/rigor/module_graph/constant_name.rb', line 62

def lexical_parts(ancestors)
  ancestors.flat_map do |ancestor|
    case ancestor
    when Prism::ClassNode, Prism::ModuleNode
      name = render(ancestor.constant_path)
      name ? [name] : []
    else
      []
    end
  end
end

.render(node) ⇒ Object

Render a single Prism constant node into a string like ‘“Foo”`, `“Foo::Bar”`, or `“::Foo::Bar”`. Returns nil when the node is not a constant carrier (e.g. `include SOME_VAR` where the arg is a `CallNode`).



30
31
32
33
34
35
36
37
# File 'lib/rigor/module_graph/constant_name.rb', line 30

def render(node)
  case node
  when Prism::ConstantReadNode
    node.name.to_s
  when Prism::ConstantPathNode
    full_name_for_path(node)
  end
end