Class: Ast::Merge::SmartMergerBase Abstract
- Inherits:
-
Object
- Object
- Ast::Merge::SmartMergerBase
- Includes:
- Detector::Mergeable
- Defined in:
- lib/ast/merge/smart_merger_base.rb
Overview
Subclass and implement #analysis_class and #perform_merge
Abstract base class for SmartMerger implementations across all *-merge gems.
SmartMergerBase provides the standard interface and common functionality
for intelligent file merging. Subclasses implement format-specific parsing,
analysis, and merge logic while inheriting the common API.
Standard Options
All SmartMerger implementations support these common options:
preference-:destination(default) or:template, or Hash for per-typeadd_template_only_nodes-false(default) ortruesignature_generator- Custom signature proc ornilfreeze_token- Token for freeze block markersmatch_refiner- Fuzzy match refiner ornilregions- Region configurations for nested mergingregion_placeholder- Custom placeholder for regionsnode_typing- Hash mapping node types to callables for per-type preferences
Implementing a SmartMerger
Subclasses must implement:
analysis_class- Returns the FileAnalysis class for this formatperform_merge- Performs the format-specific merge logic
Subclasses may override:
default_freeze_token- Format-specific default freeze tokenresolver_class- Returns the ConflictResolver class (if different)result_class- Returns the MergeResult class (if different)aligner_class- Returns the FileAligner class (if used)parse_content- Custom parsing logicbuild_analysis_options- Additional analysis optionsbuild_resolver_options- Additional resolver options
FileAnalysis Error Handling Pattern
All FileAnalysis classes must follow this consistent error handling pattern:
-
Catch backend errors internally - Handle
TreeHaver::NotAvailableand
similar backend errors inside the FileAnalysis class, storing them in@errors
and setting@ast = nil. Do NOT re-raise these errors. -
Collect parse errors without raising - When the parser detects syntax errors
(e.g.,has_error?returns true), collect them in@errorsbut do NOT raise. - Implement
valid?- Returnfalsewhen there are errors or no AST:def valid? @errors.empty? && !@ast.nil? end - SmartMergerBase handles the rest - After FileAnalysis creation,
parse_and_analyzechecksvalid?and raises the appropriate parse error
(TemplateParseError or DestinationParseError) if the analysis is invalid.
This pattern ensures:
- Consistent error handling across all *-merge gems
- TreeHaver::NotAvailable (which inherits from Exception) is handled safely
- Parse errors are properly wrapped in format-specific error classes
- No need to rescue Exception in SmartMergerBase
Direct Known Subclasses
Constant Summary
Constants included from Detector::Mergeable
Detector::Mergeable::DEFAULT_PLACEHOLDER_PREFIX, Detector::Mergeable::DEFAULT_PLACEHOLDER_SUFFIX
Instance Attribute Summary collapse
-
#add_template_only_nodes ⇒ Boolean
readonly
Whether to add template-only nodes.
-
#aligner ⇒ Object?
readonly
Aligner for finding matches (if applicable).
-
#dest_analysis ⇒ Object
readonly
Analysis of the destination file.
-
#dest_content ⇒ String
readonly
Destination source content.
-
#freeze_token ⇒ String
readonly
Token for freeze block markers.
-
#match_refiner ⇒ Object?
readonly
Match refiner for fuzzy matching.
-
#node_typing ⇒ Hash{Symbol,String => #call}?
readonly
Node typing configuration.
-
#preference ⇒ Symbol, Hash
readonly
Preference for signature matches.
-
#resolver ⇒ Object
readonly
Resolver for handling conflicts.
-
#result ⇒ Object
readonly
Result object tracking merged content.
-
#signature_generator ⇒ Proc?
readonly
Custom signature generator.
-
#template_analysis ⇒ Object
readonly
Analysis of the template file.
-
#template_content ⇒ String
readonly
Template source content.
Instance Method Summary collapse
-
#initialize(template_content, dest_content, signature_generator: nil, preference: :destination, add_template_only_nodes: false, freeze_token: nil, match_refiner: nil, regions: nil, region_placeholder: nil, node_typing: nil, **format_options) ⇒ SmartMergerBase
constructor
Creates a new SmartMerger for intelligent file merging.
-
#merge ⇒ String
Perform the merge operation and return the merged content as a string.
-
#merge_result ⇒ Object
Perform the merge operation and return the full result object.
-
#merge_with_debug ⇒ Hash
Perform the merge and return detailed debug information.
-
#stats ⇒ Hash
Get merge statistics.
Methods included from Detector::Mergeable
#extract_dest_regions, #extract_template_regions, #regions_configured?, #setup_regions, #substitute_merged_regions
Constructor Details
#initialize(template_content, dest_content, signature_generator: nil, preference: :destination, add_template_only_nodes: false, freeze_token: nil, match_refiner: nil, regions: nil, region_placeholder: nil, node_typing: nil, **format_options) ⇒ SmartMergerBase
Creates a new SmartMerger for intelligent file merging.
206 207 208 209 210 211 212 213 214 215 216 217 218 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 251 |
# File 'lib/ast/merge/smart_merger_base.rb', line 206 def initialize( template_content, dest_content, signature_generator: nil, preference: :destination, add_template_only_nodes: false, freeze_token: nil, match_refiner: nil, regions: nil, region_placeholder: nil, node_typing: nil, ** ) @template_content = template_content @dest_content = dest_content @signature_generator = signature_generator @preference = preference @add_template_only_nodes = add_template_only_nodes @freeze_token = freeze_token || default_freeze_token @match_refiner = match_refiner @node_typing = node_typing @format_options = # Validate node_typing if provided NodeTyping.validate!(node_typing) if node_typing # Set up region support setup_regions(regions: regions || [], region_placeholder: region_placeholder) # Extract regions before parsing (if configured) template_for_parsing = extract_template_regions(@template_content) dest_for_parsing = extract_dest_regions(@dest_content) # Parse and analyze both files @template_analysis = parse_and_analyze(template_for_parsing, :template) @dest_analysis = parse_and_analyze(dest_for_parsing, :destination) # Set up aligner (if applicable) @aligner = build_aligner if respond_to?(:aligner_class, true) && aligner_class # Set up resolver @resolver = build_resolver # Set up result @result = build_result end |
Instance Attribute Details
#add_template_only_nodes ⇒ Boolean (readonly)
Returns Whether to add template-only nodes.
135 136 137 |
# File 'lib/ast/merge/smart_merger_base.rb', line 135 def add_template_only_nodes @add_template_only_nodes end |
#aligner ⇒ Object? (readonly)
Returns Aligner for finding matches (if applicable).
123 124 125 |
# File 'lib/ast/merge/smart_merger_base.rb', line 123 def aligner @aligner end |
#dest_analysis ⇒ Object (readonly)
Returns Analysis of the destination file.
120 121 122 |
# File 'lib/ast/merge/smart_merger_base.rb', line 120 def dest_analysis @dest_analysis end |
#dest_content ⇒ String (readonly)
Returns Destination source content.
114 115 116 |
# File 'lib/ast/merge/smart_merger_base.rb', line 114 def dest_content @dest_content end |
#freeze_token ⇒ String (readonly)
Returns Token for freeze block markers.
138 139 140 |
# File 'lib/ast/merge/smart_merger_base.rb', line 138 def freeze_token @freeze_token end |
#match_refiner ⇒ Object? (readonly)
Returns Match refiner for fuzzy matching.
144 145 146 |
# File 'lib/ast/merge/smart_merger_base.rb', line 144 def match_refiner @match_refiner end |
#node_typing ⇒ Hash{Symbol,String => #call}? (readonly)
Returns Node typing configuration.
147 148 149 |
# File 'lib/ast/merge/smart_merger_base.rb', line 147 def node_typing @node_typing end |
#preference ⇒ Symbol, Hash (readonly)
Returns Preference for signature matches.
132 133 134 |
# File 'lib/ast/merge/smart_merger_base.rb', line 132 def preference @preference end |
#resolver ⇒ Object (readonly)
Returns Resolver for handling conflicts.
126 127 128 |
# File 'lib/ast/merge/smart_merger_base.rb', line 126 def resolver @resolver end |
#result ⇒ Object (readonly)
Returns Result object tracking merged content.
129 130 131 |
# File 'lib/ast/merge/smart_merger_base.rb', line 129 def result @result end |
#signature_generator ⇒ Proc? (readonly)
Returns Custom signature generator.
141 142 143 |
# File 'lib/ast/merge/smart_merger_base.rb', line 141 def signature_generator @signature_generator end |
#template_analysis ⇒ Object (readonly)
Returns Analysis of the template file.
117 118 119 |
# File 'lib/ast/merge/smart_merger_base.rb', line 117 def template_analysis @template_analysis end |
#template_content ⇒ String (readonly)
Returns Template source content.
111 112 113 |
# File 'lib/ast/merge/smart_merger_base.rb', line 111 def template_content @template_content end |
Instance Method Details
#merge ⇒ String
Perform the merge operation and return the merged content as a string.
256 257 258 |
# File 'lib/ast/merge/smart_merger_base.rb', line 256 def merge merge_result.to_s end |
#merge_result ⇒ Object
Perform the merge operation and return the full result object.
This method is memoized - subsequent calls return the cached result.
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/ast/merge/smart_merger_base.rb', line 265 def merge_result return @merge_result if @merge_result @merge_result = DebugLogger.time("#{self.class.name}#merge") do result = perform_merge # Substitute merged regions back into the result if configured if regions_configured? && (merged_content = result.to_s) final_content = substitute_merged_regions(merged_content) update_result_content(result, final_content) end result end end |
#merge_with_debug ⇒ Hash
Perform the merge and return detailed debug information.
286 287 288 289 290 291 292 293 |
# File 'lib/ast/merge/smart_merger_base.rb', line 286 def merge_with_debug content = merge { content: content, statistics: @result.decision_summary, } end |
#stats ⇒ Hash
Get merge statistics.
298 299 300 301 |
# File 'lib/ast/merge/smart_merger_base.rb', line 298 def stats merge_result # Ensure merge has run @result.decision_summary end |