Class: Ast::Merge::NodeWrapperBase Abstract
- Inherits:
-
Object
- Object
- Ast::Merge::NodeWrapperBase
- Defined in:
- lib/ast/merge/node_wrapper_base.rb
Overview
Subclass and implement #compute_signature
Base class for format-specific node wrappers used in *-merge gems.
This provides common functionality for wrapping TreeHaver nodes with:
- Source context (lines, source string)
- Line information (start_line, end_line)
- Comment associations (leading_comments, inline_comment)
- Content extraction (text, content)
- Signature generation (abstract)
Relationship to NodeTyping::Wrapper
This class is DIFFERENT from Ast::Merge::NodeTyping::Wrapper:
-
NodeWrapperBase: Provides format-specific functionality (line info,
signatures, comments, type predicates). Used to wrap raw TreeHaver nodes
with rich context needed for merging. -
NodeTyping::Wrapper: Adds a custom
merge_typeattribute for merge
classification. Used by SmartMergerBase to apply custom typing rules.
A node CAN be wrapped by both:
NodeTyping::Wrapper(Toml::Merge::NodeWrapper(tree_sitter_node))
The NodeTyping.unwrap method handles unwrapping NodeTyping::Wrapper,
while NodeWrapperBase#node provides access to the underlying TreeHaver node.
Subclass Responsibilities
Subclasses MUST implement:
#compute_signature(node)- Generate a signature for node matching
Subclasses SHOULD implement format-specific type predicates:
- TOML:
#table?,#pair?,#array_of_tables?, etc. - JSON:
#object?,#array?,#pair?, etc. - Bash:
#function_definition?,#variable_assignment?, etc.
Instance Attribute Summary collapse
-
#end_line ⇒ Integer?
readonly
End line (1-based).
-
#inline_comment ⇒ Hash?
readonly
Inline/trailing comment on the same line.
-
#leading_comments ⇒ Array<Hash>
readonly
Leading comments associated with this node.
-
#lines ⇒ Array<String>
readonly
Source lines for content extraction.
-
#node ⇒ Object
readonly
The wrapped TreeHaver node.
-
#source ⇒ String
readonly
The original source string.
-
#start_line ⇒ Integer?
readonly
Start line (1-based).
Instance Method Summary collapse
-
#children ⇒ Array<NodeWrapperBase>
Get children wrapped as NodeWrappers.
-
#container? ⇒ Boolean
Check if this node is a container (has children for merging).
-
#content ⇒ String
Get the content for this node from source lines.
-
#freeze_node? ⇒ Boolean
Check if this is a freeze node.
-
#initialize(node, lines:, source: nil, leading_comments: [], inline_comment: nil, **options) ⇒ NodeWrapperBase
constructor
Initialize the node wrapper with source context.
-
#inspect ⇒ String
String representation for debugging.
-
#leaf? ⇒ Boolean
Check if this node is a leaf (no mergeable children).
-
#mergeable_children ⇒ Array<NodeWrapperBase>
Get mergeable children - the semantically meaningful children for tree merging.
-
#node_text(ts_node) ⇒ String
Extract text from a node using byte positions.
-
#node_wrapper? ⇒ Boolean
Returns true to indicate this is a node wrapper.
-
#process_additional_options(options) ⇒ Object
Process additional options.
-
#signature ⇒ Array?
Generate a signature for this node for matching purposes.
-
#text ⇒ String
Get the text content for this node by extracting from source using byte positions.
-
#type ⇒ Symbol
Get the node type as a symbol.
-
#type?(type_name) ⇒ Boolean
Check if this node has a specific type.
-
#underlying_node ⇒ Object
Get the underlying TreeHaver node.
Constructor Details
#initialize(node, lines:, source: nil, leading_comments: [], inline_comment: nil, **options) ⇒ NodeWrapperBase
Initialize the node wrapper with source context.
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 92 def initialize(node, lines:, source: nil, leading_comments: [], inline_comment: nil, **) @node = node @lines = lines @source = source || lines.join("\n") @leading_comments = leading_comments @inline_comment = inline_comment # Store additional options for subclasses to use () # Extract line information from the node (0-indexed to 1-indexed) extract_line_info(node) # Handle edge case where end_line might be before start_line @end_line = @start_line if @start_line && @end_line && @end_line < @start_line end |
Instance Attribute Details
#end_line ⇒ Integer? (readonly)
Returns End line (1-based).
82 83 84 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 82 def end_line @end_line end |
#inline_comment ⇒ Hash? (readonly)
Returns Inline/trailing comment on the same line.
76 77 78 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 76 def inline_comment @inline_comment end |
#leading_comments ⇒ Array<Hash> (readonly)
Returns Leading comments associated with this node.
73 74 75 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 73 def leading_comments @leading_comments end |
#lines ⇒ Array<String> (readonly)
Returns Source lines for content extraction.
67 68 69 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 67 def lines @lines end |
#node ⇒ Object (readonly)
Returns The wrapped TreeHaver node.
64 65 66 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 64 def node @node end |
#source ⇒ String (readonly)
Returns The original source string.
70 71 72 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 70 def source @source end |
#start_line ⇒ Integer? (readonly)
Returns Start line (1-based).
79 80 81 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 79 def start_line @start_line end |
Instance Method Details
#children ⇒ Array<NodeWrapperBase>
Get children wrapped as NodeWrappers.
Override in subclasses to return wrapped children.
182 183 184 185 186 187 188 189 190 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 182 def children return [] unless @node.respond_to?(:each) result = [] @node.each do |child| result << wrap_child(child) end result end |
#container? ⇒ Boolean
Check if this node is a container (has children for merging).
Override in subclasses to define container types.
169 170 171 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 169 def container? false end |
#content ⇒ String
Get the content for this node from source lines.
160 161 162 163 164 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 160 def content return "" unless @start_line && @end_line (@start_line..@end_line).map { |ln| @lines[ln - 1] }.compact.join("\n") end |
#freeze_node? ⇒ Boolean
Check if this is a freeze node.
Override in subclasses if freeze node detection differs.
139 140 141 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 139 def freeze_node? false end |
#inspect ⇒ String
String representation for debugging.
201 202 203 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 201 def inspect "#<#{self.class.name} type=#{@node.type} lines=#{@start_line}..#{@end_line}>" end |
#leaf? ⇒ Boolean
Check if this node is a leaf (no mergeable children).
175 176 177 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 175 def leaf? !container? end |
#mergeable_children ⇒ Array<NodeWrapperBase>
Get mergeable children - the semantically meaningful children for tree merging.
Override in subclasses to return format-specific mergeable children.
195 196 197 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 195 def mergeable_children children end |
#node_text(ts_node) ⇒ String
Extract text from a node using byte positions.
152 153 154 155 156 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 152 def node_text(ts_node) return "" unless ts_node.respond_to?(:start_byte) && ts_node.respond_to?(:end_byte) @source[ts_node.start_byte...ts_node.end_byte] || "" end |
#node_wrapper? ⇒ Boolean
Returns true to indicate this is a node wrapper.
Used to distinguish from NodeTyping::Wrapper.
208 209 210 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 208 def node_wrapper? true end |
#process_additional_options(options) ⇒ Object
Process additional options. Override in subclasses to handle format-specific options.
111 112 113 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 111 def () # Default: no-op. Subclasses can override to process options like :backend, :document_root end |
#signature ⇒ Array?
Generate a signature for this node for matching purposes.
Signatures are used to identify corresponding nodes between template and destination.
119 120 121 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 119 def signature compute_signature(@node) end |
#text ⇒ String
Get the text content for this node by extracting from source using byte positions.
145 146 147 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 145 def text node_text(@node) end |
#type ⇒ Symbol
Get the node type as a symbol.
125 126 127 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 125 def type @node.type.to_sym end |
#type?(type_name) ⇒ Boolean
Check if this node has a specific type.
132 133 134 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 132 def type?(type_name) @node.type.to_s == type_name.to_s end |
#underlying_node ⇒ Object
Get the underlying TreeHaver node.
Note: This is NOT the same as NodeTyping::Wrapper#unwrap which removes
the typing wrapper. This method provides access to the raw parser node.
216 217 218 |
# File 'lib/ast/merge/node_wrapper_base.rb', line 216 def @node end |