Class: Ast::Merge::Navigable::InjectionPoint

Inherits:
Object
  • Object
show all
Defined in:
lib/ast/merge/navigable/injection_point.rb

Overview

Represents a location in a document where content can be injected.

InjectionPoint is language-agnostic - it works with any AST structure.
It defines WHERE to inject content and HOW (as child, sibling, or replacement).

Examples:

Inject as first child of a class

point = InjectionPoint.new(
  anchor: class_node,
  position: :first_child
)

Inject after a specific method

point = InjectionPoint.new(
  anchor: method_node,
  position: :after
)

Replace a range of nodes

point = InjectionPoint.new(
  anchor: start_node,
  position: :replace,
  boundary: end_node
)

Constant Summary collapse

POSITIONS =

Valid positions for injection

%i[
  before
  after
  first_child
  last_child
  replace
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(anchor:, position:, boundary: nil, **metadata) ⇒ InjectionPoint

Initialize an InjectionPoint.

Parameters:

  • anchor (Statement)

    The reference node

  • position (Symbol)

    Where to inject relative to anchor

  • boundary (Statement, nil) (defaults to: nil)

    End boundary for replacements

  • metadata (Hash)

    Additional info (e.g., match details)



58
59
60
61
62
63
64
65
66
# File 'lib/ast/merge/navigable/injection_point.rb', line 58

def initialize(anchor:, position:, boundary: nil, **)
  validate_position!(position)
  validate_boundary!(position, boundary)

  @anchor = anchor
  @position = position
  @boundary = boundary
  @metadata = 
end

Instance Attribute Details

#anchorStatement (readonly)

Returns The anchor node for injection.

Returns:

  • (Statement)

    The anchor node for injection



41
42
43
# File 'lib/ast/merge/navigable/injection_point.rb', line 41

def anchor
  @anchor
end

#boundaryStatement? (readonly)

Returns End boundary for :replace position.

Returns:

  • (Statement, nil)

    End boundary for :replace position



47
48
49
# File 'lib/ast/merge/navigable/injection_point.rb', line 47

def boundary
  @boundary
end

#metadataHash (readonly)

Returns Additional metadata about this injection point.

Returns:

  • (Hash)

    Additional metadata about this injection point



50
51
52
# File 'lib/ast/merge/navigable/injection_point.rb', line 50

def 
  @metadata
end

#positionSymbol (readonly)

Returns Position relative to anchor (:before, :after, :first_child, :last_child, :replace).

Returns:

  • (Symbol)

    Position relative to anchor (:before, :after, :first_child, :last_child, :replace)



44
45
46
# File 'lib/ast/merge/navigable/injection_point.rb', line 44

def position
  @position
end

Instance Method Details

#child_injection?Boolean

Returns true if this injects as a child.

Returns:

  • (Boolean)

    true if this injects as a child



74
75
76
# File 'lib/ast/merge/navigable/injection_point.rb', line 74

def child_injection?
  %i[first_child last_child].include?(position)
end

#end_lineInteger?

Returns End line of injection point.

Returns:

  • (Integer, nil)

    End line of injection point



106
107
108
# File 'lib/ast/merge/navigable/injection_point.rb', line 106

def end_line
  (boundary || anchor).end_line
end

#inspectString

Returns Human-readable representation.

Returns:

  • (String)

    Human-readable representation



111
112
113
114
# File 'lib/ast/merge/navigable/injection_point.rb', line 111

def inspect
  boundary_info = boundary ? " to #{boundary.index}" : ""
  "#<Navigable::InjectionPoint position=#{position} anchor=#{anchor.index}#{boundary_info}>"
end

#replaced_statementsArray<Statement>

Get all statements that would be replaced.

Returns:

  • (Array<Statement>)

    Statements to replace (empty if not replacement)



86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/ast/merge/navigable/injection_point.rb', line 86

def replaced_statements
  return [] unless replacement?
  return [anchor] unless boundary

  result = [anchor]
  current = anchor.next
  while current && current != boundary
    result << current
    current = current.next
  end
  result << boundary if boundary
  result
end

#replacement?Boolean

Returns true if this is a replacement (not insertion).

Returns:

  • (Boolean)

    true if this is a replacement (not insertion)



69
70
71
# File 'lib/ast/merge/navigable/injection_point.rb', line 69

def replacement?
  position == :replace
end

#sibling_injection?Boolean

Returns true if this injects as a sibling.

Returns:

  • (Boolean)

    true if this injects as a sibling



79
80
81
# File 'lib/ast/merge/navigable/injection_point.rb', line 79

def sibling_injection?
  %i[before after].include?(position)
end

#start_lineInteger?

Returns Start line of injection point.

Returns:

  • (Integer, nil)

    Start line of injection point



101
102
103
# File 'lib/ast/merge/navigable/injection_point.rb', line 101

def start_line
  anchor.start_line
end