Class: Prism::Merge::SmartMerger
- Inherits:
-
Ast::Merge::SmartMergerBase
- Object
- Ast::Merge::SmartMergerBase
- Prism::Merge::SmartMerger
- Defined in:
- lib/prism/merge/smart_merger.rb
Overview
A merger that uses section-based semantics with recursive body merging for cleaner merging.
SmartMerger:
- Converts each top-level node into a “section” identified by its signature
- Uses SectionTyping-style merge logic to decide which sections to include
- Recursively merges matching class/module/block bodies
- Outputs each selected node exactly once (with its comments)
This approach avoids the complexity of tracking line ranges for anchors
and boundaries, which can lead to duplicate content when comments are
attached to multiple overlapping ranges.
Merge Algorithm
- Parse both template and destination files
- Generate signatures for all top-level nodes in both files
- Build a signature -> node map for destination
- Walk template nodes in order:
- If signature matches a dest node:
- If class/module/block with mergeable body: recursively merge bodies
- Otherwise: output based on preference
- If template-only: output if add_template_only_nodes is true
- If signature matches a dest node:
- Output any remaining dest-only nodes
Recursive Body Merging
When matching class/module definitions or CallNodes with blocks are found,
the merger recursively merges their body contents. This allows template
updates to nested methods/constants to be merged with destination customizations.
Instance Attribute Summary collapse
-
#max_recursion_depth ⇒ Integer, Float
readonly
Maximum recursion depth for body merging.
-
#text_merger_options ⇒ Hash?
readonly
Options to pass to Text::SmartMerger for comment-only files.
Instance Method Summary collapse
-
#comment_only_file?(analysis) ⇒ Boolean
Determine whether the given analysis represents a comment-only file.
-
#initialize(template_content, dest_content, signature_generator: nil, preference: :destination, add_template_only_nodes: false, freeze_token: nil, node_typing: nil, max_recursion_depth: Float::INFINITY, current_depth: 0, match_refiner: nil, regions: nil, region_placeholder: nil, text_merger_options: nil, **options) ⇒ SmartMerger
constructor
Creates a new SmartMerger.
-
#merge_with_debug ⇒ Hash
Perform the merge and return a hash with content, debug info, and statistics.
Constructor Details
#initialize(template_content, dest_content, signature_generator: nil, preference: :destination, add_template_only_nodes: false, freeze_token: nil, node_typing: nil, max_recursion_depth: Float::INFINITY, current_depth: 0, match_refiner: nil, regions: nil, region_placeholder: nil, text_merger_options: nil, **options) ⇒ SmartMerger
Creates a new SmartMerger.
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 |
# File 'lib/prism/merge/smart_merger.rb', line 77 def initialize( template_content, dest_content, signature_generator: nil, preference: :destination, add_template_only_nodes: false, freeze_token: nil, node_typing: nil, max_recursion_depth: Float::INFINITY, current_depth: 0, match_refiner: nil, regions: nil, region_placeholder: nil, text_merger_options: nil, ** ) @max_recursion_depth = max_recursion_depth @current_depth = current_depth @text_merger_options = @dest_prefix_comment_lines = nil # Store the raw (unwrapped) signature_generator so that # merge_node_body_recursively can pass it to inner SmartMergers # without double-wrapping. @raw_signature_generator = signature_generator # Wrap signature_generator to include node_typing processing effective_signature_generator = build_effective_signature_generator(signature_generator, node_typing) super( template_content, dest_content, signature_generator: effective_signature_generator, preference: preference, add_template_only_nodes: add_template_only_nodes, freeze_token: freeze_token, match_refiner: match_refiner, regions: regions, region_placeholder: region_placeholder, node_typing: node_typing, ** ) end |
Instance Attribute Details
#max_recursion_depth ⇒ Integer, Float (readonly)
Returns Maximum recursion depth for body merging.
50 51 52 |
# File 'lib/prism/merge/smart_merger.rb', line 50 def max_recursion_depth @max_recursion_depth end |
#text_merger_options ⇒ Hash? (readonly)
Returns Options to pass to Text::SmartMerger for comment-only files.
53 54 55 |
# File 'lib/prism/merge/smart_merger.rb', line 53 def @text_merger_options end |
Instance Method Details
#comment_only_file?(analysis) ⇒ Boolean
Determine whether the given analysis represents a comment-only file.
Returns true when every top-level statement is a comment/block/empty
node produced by the comment parsers. This is used to decide whether to
delegate to the comment-only merger logic.
129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/prism/merge/smart_merger.rb', line 129 def comment_only_file?(analysis) stmts = analysis.statements return false if stmts.nil? || stmts.empty? stmts.all? do |s| # AST comment nodes (Prism-specific ones inherit from these) s.is_a?(Ast::Merge::Comment::Empty) || s.is_a?(Ast::Merge::Comment::Block) || s.is_a?(Ast::Merge::Comment::Line) end end |
#merge_with_debug ⇒ Hash
Perform the merge and return a hash with content, debug info, and statistics.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/prism/merge/smart_merger.rb', line 144 def merge_with_debug result_obj = merge_result { content: result_obj.to_s, debug: { template_statements: @template_analysis&.statements&.size || 0, dest_statements: @dest_analysis&.statements&.size || 0, preference: @preference, add_template_only_nodes: @add_template_only_nodes, freeze_token: @freeze_token, }, statistics: result_obj.respond_to?(:statistics) ? result_obj.statistics : result_obj.decision_summary, } end |