Class: Prism::Merge::MergeResult
- Inherits:
-
Ast::Merge::MergeResultBase
- Object
- Ast::Merge::MergeResultBase
- Prism::Merge::MergeResult
- Includes:
- SourceLineLookup
- Defined in:
- lib/prism/merge/merge_result.rb
Overview
Represents the merged output with bidirectional links to source lines. Tracks merge decisions and provenance for validation and debugging.
Inherits decision constants and base functionality from Ast::Merge::MergeResultBase.
Constant Summary collapse
- DECISION_KEPT_TEMPLATE =
Inherit decision constants from base class
Ast::Merge::MergeResultBase::DECISION_KEPT_TEMPLATE
- DECISION_KEPT_DEST =
Ast::Merge::MergeResultBase::DECISION_KEPT_DEST
- DECISION_APPENDED =
Ast::Merge::MergeResultBase::DECISION_APPENDED
- DECISION_REPLACED =
Ast::Merge::MergeResultBase::DECISION_REPLACED
- DECISION_FREEZE_BLOCK =
Ast::Merge::MergeResultBase::DECISION_FREEZE_BLOCK
Instance Attribute Summary collapse
-
#line_metadata ⇒ Object
readonly
Returns the value of attribute line_metadata.
Instance Method Summary collapse
-
#add_line(content, decision:, template_line: nil, dest_line: nil, comment: nil) ⇒ Object
Add a line to the result.
-
#add_lines_from(source_lines, decision:, source:, start_line:, comment: nil) ⇒ Object
Add multiple lines from a source with same decision.
-
#add_node(node_info, decision:, source:, source_analysis: nil) ⇒ Object
Add a node's content with its comments.
-
#debug_output ⇒ String
Debug output showing merge provenance.
- #decision_summary ⇒ Object
-
#initialize(**options) ⇒ MergeResult
constructor
A new instance of MergeResult.
-
#lines_by_decision(decision) ⇒ Array<Hash>
Get lines by decision type.
-
#statistics ⇒ Hash<Symbol, Integer>
Get statistics about merge decisions.
-
#to_s ⇒ String
Convert to final merged content string.
Constructor Details
#initialize(**options) ⇒ MergeResult
Returns a new instance of MergeResult.
22 23 24 25 |
# File 'lib/prism/merge/merge_result.rb', line 22 def initialize(**) super(**) @line_metadata = [] end |
Instance Attribute Details
#line_metadata ⇒ Object (readonly)
Returns the value of attribute line_metadata.
19 20 21 |
# File 'lib/prism/merge/merge_result.rb', line 19 def @line_metadata end |
Instance Method Details
#add_line(content, decision:, template_line: nil, dest_line: nil, comment: nil) ⇒ Object
Add a line to the result
33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/prism/merge/merge_result.rb', line 33 def add_line(content, decision:, template_line: nil, dest_line: nil, comment: nil) @lines << content @line_metadata << { decision: decision, template_line: template_line, dest_line: dest_line, comment: comment, result_line: @lines.length } track_decision(decision, template_line ? :template : :destination, line: template_line || dest_line) end |
#add_lines_from(source_lines, decision:, source:, start_line:, comment: nil) ⇒ Object
Add multiple lines from a source with same decision
51 52 53 54 55 56 57 58 59 60 |
# File 'lib/prism/merge/merge_result.rb', line 51 def add_lines_from(source_lines, decision:, source:, start_line:, comment: nil) source_lines.each_with_index do |line, idx| line_num = start_line + idx if source == :template add_line(line, decision: decision, template_line: line_num, comment: comment) else add_line(line, decision: decision, dest_line: line_num, comment: comment) end end end |
#add_node(node_info, decision:, source:, source_analysis: nil) ⇒ Object
Add a node's content with its comments
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/prism/merge/merge_result.rb', line 67 def add_node(node_info, decision:, source:, source_analysis: nil) node = node_info[:node] start_line = node.location.start_line end_line = node.location.end_line # Add leading comments with blank lines between them preserved prev_comment_line = nil node_info[:leading_comments].each do |comment| comment_line = comment.location.start_line # Add blank lines between this comment and the previous one if prev_comment_line && comment_line > prev_comment_line + 1 ((prev_comment_line + 1)...comment_line).each do |blank_line_num| line = if source_analysis required_source_line( source_analysis, blank_line_num, context: 'emitting preserved blank line between leading comments' ) else '' end if source == :template add_line(line, decision: decision, template_line: blank_line_num) else add_line(line, decision: decision, dest_line: blank_line_num) end end end # Use source_analysis to get full line with indentation if available line = if source_analysis required_comment_line( source_analysis, comment, context: 'emitting leading comment from analyzed source' ) else comment.slice.chomp end if source == :template add_line(line, decision: decision, template_line: comment_line) else add_line(line, decision: decision, dest_line: comment_line) end prev_comment_line = comment_line end # Add blank lines between last comment and node if needed if node_info[:leading_comments].any? last_comment_line = node_info[:leading_comments].last.location.start_line if start_line > last_comment_line + 1 ((last_comment_line + 1)...start_line).each do |blank_line_num| line = if source_analysis required_source_line( source_analysis, blank_line_num, context: 'emitting preserved blank line before node body' ) else '' end if source == :template add_line(line, decision: decision, template_line: blank_line_num) else add_line(line, decision: decision, dest_line: blank_line_num) end end end end # Add node source lines # Use source_analysis.line_at to preserve original indentation if source_analysis # Get full lines from source to preserve indentation # Note: inline comments are already part of the source line from line_at(), # so we don't need to append them separately. The inline_comments in node_info # are just metadata about comments that were attached to the node by Prism. (start_line..end_line).each do |line_num| line = required_source_line( source_analysis, line_num, context: 'emitting analyzed node source line' ) if source == :template add_line(line, decision: decision, template_line: line_num) else add_line(line, decision: decision, dest_line: line_num) end end else # Analysis-free emission path: use node.slice when no source analysis # object is available. This is an alternate input mode, not cleanup. node_source = node.slice node_lines = node_source.lines(chomp: true) # Handle inline comments inline_comments = node_info[:inline_comments] if inline_comments.any? # Inline comments are on the last line last_idx = node_lines.length - 1 if last_idx >= 0 # Analysis-free mode only has node.slice, which excludes the original # pre-comment separator. Reattach inline comments with a canonical # single space instead of pretending to preserve unavailable spacing. inline_text = inline_comments.map { |c| c.slice.strip }.join(' ') node_lines[last_idx] = "#{node_lines[last_idx]} #{inline_text}" end end node_lines.each_with_index do |line, idx| line_num = start_line + idx if source == :template add_line(line, decision: decision, template_line: line_num) else add_line(line, decision: decision, dest_line: line_num) end end end end |
#debug_output ⇒ String
Debug output showing merge provenance
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/prism/merge/merge_result.rb', line 219 def debug_output output = ['=== Merge Result Debug ==='] output << "Total lines: #{@lines.length}" output << "Statistics: #{statistics.inspect}" output << '' output << 'Line-by-line provenance:' @lines.each_with_index do |line, idx| = @line_metadata[idx] parts = [ "#{idx + 1}:".rjust(4), [:decision].to_s.ljust(20) ] parts << if [:template_line] "T:#{[:template_line]}".ljust(8) else ' ' * 8 end parts << if [:dest_line] "D:#{[:dest_line]}".ljust(8) else ' ' * 8 end parts << "| #{line[0..60]}" output << parts.join(' ') end output.join("\n") end |
#decision_summary ⇒ Object
206 207 208 |
# File 'lib/prism/merge/merge_result.rb', line 206 def decision_summary statistics end |
#lines_by_decision(decision) ⇒ Array<Hash>
Get lines by decision type
213 214 215 |
# File 'lib/prism/merge/merge_result.rb', line 213 def lines_by_decision(decision) @line_metadata.select { || [:decision] == decision } end |
#statistics ⇒ Hash<Symbol, Integer>
Get statistics about merge decisions
198 199 200 201 202 203 204 |
# File 'lib/prism/merge/merge_result.rb', line 198 def statistics stats = Hash.new(0) @line_metadata.each do || stats[[:decision]] += 1 end stats end |
#to_s ⇒ String
Convert to final merged content string
192 193 194 |
# File 'lib/prism/merge/merge_result.rb', line 192 def to_s "#{@lines.join("\n")}\n" end |