Class: Psych::Merge::SmartMerger

Inherits:
Ast::Merge::SmartMergerBase
  • Object
show all
Defined in:
lib/psych/merge/smart_merger.rb

Overview

Main entry point for intelligent YAML file merging.
SmartMerger orchestrates the merge process using FileAnalysis,
ConflictResolver, and MergeResult to merge two YAML files intelligently.

Examples:

Basic merge (destination customizations preserved)

merger = SmartMerger.new(template_yaml, dest_yaml)
result = merger.merge
File.write("output.yml", result)

Template updates win

merger = SmartMerger.new(
  template_yaml,
  dest_yaml,
  preference: :template,
  add_template_only_nodes: true
)
result = merger.merge

Recursive merge with template additions

merger = SmartMerger.new(
  template_yaml,
  dest_yaml,
  recursive: true,
  add_template_only_nodes: true
)
# Nested structures are merged recursively, template-only items added

With custom signature generator

sig_gen = ->(node) {
  if node.is_a?(MappingEntry) && node.key_name == "version"
    [:special_version, node.key_name]
  else
    node # Fall through to default
  end
}
merger = SmartMerger.new(template, dest, signature_generator: sig_gen)

With regions (embedded content)

merger = SmartMerger.new(template, dest,
  regions: [{ detector: SomeDetector.new, merger_class: SomeMerger }])

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(template_content, dest_content, signature_generator: nil, preference: :destination, add_template_only_nodes: false, remove_template_missing_nodes: false, recursive: true, freeze_token: FileAnalysis::DEFAULT_FREEZE_TOKEN, match_refiner: nil, regions: nil, region_placeholder: nil, node_typing: nil, **options) ⇒ SmartMerger

Creates a new SmartMerger for intelligent YAML file merging.

Parameters:

  • template_content (String)

    Template YAML source code

  • dest_content (String)

    Destination YAML source code

  • signature_generator (Proc, nil) (defaults to: nil)

    Custom signature generator

  • preference (Symbol) (defaults to: :destination)

    Which version to prefer when
    nodes have matching signatures:

    • :destination (default) - Keep destination version (customizations)
    • :template - Use template version (updates)
  • add_template_only_nodes (Boolean) (defaults to: false)

    Whether to add nodes only in template

  • remove_template_missing_nodes (Boolean) (defaults to: false)

    Whether to remove destination nodes not in template

  • recursive (Boolean, Integer) (defaults to: true)

    Whether to merge nested structures recursively

    • true: unlimited depth (default)
    • false: disabled
    • Integer > 0: max depth
  • freeze_token (String) (defaults to: FileAnalysis::DEFAULT_FREEZE_TOKEN)

    Token for freeze block markers

  • match_refiner (#call, nil) (defaults to: nil)

    Optional match refiner for fuzzy matching of
    unmatched nodes. Default: nil (fuzzy matching disabled).
    Set to MappingMatchRefiner.new to enable fuzzy key matching.

  • regions (Array<Hash>, nil) (defaults to: nil)

    Region configurations for nested merging

  • region_placeholder (String, nil) (defaults to: nil)

    Custom placeholder for regions

  • node_typing (Hash{Symbol,String => #call}, nil) (defaults to: nil)

    Node typing configuration
    for per-node-type merge preferences

  • options (Hash)

    Additional options for forward compatibility

Raises:



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
# File 'lib/psych/merge/smart_merger.rb', line 73

def initialize(
  template_content,
  dest_content,
  signature_generator: nil,
  preference: :destination,
  add_template_only_nodes: false,
  remove_template_missing_nodes: false,
  recursive: true,
  freeze_token: FileAnalysis::DEFAULT_FREEZE_TOKEN,
  match_refiner: nil,
  regions: nil,
  region_placeholder: nil,
  node_typing: nil,
  **options
)
  @remove_template_missing_nodes = remove_template_missing_nodes
  @recursive = recursive
  super(
    template_content,
    dest_content,
    signature_generator: 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,
    **options
  )
end

Instance Attribute Details

#recursiveBoolean, Integer (readonly)

Returns Whether to merge nested structures recursively.

Returns:

  • (Boolean, Integer)

    Whether to merge nested structures recursively



109
110
111
# File 'lib/psych/merge/smart_merger.rb', line 109

def recursive
  @recursive
end

#remove_template_missing_nodesBoolean (readonly)

Returns Whether to remove destination nodes not in template.

Returns:

  • (Boolean)

    Whether to remove destination nodes not in template



106
107
108
# File 'lib/psych/merge/smart_merger.rb', line 106

def remove_template_missing_nodes
  @remove_template_missing_nodes
end

Instance Method Details

#errorsArray

Get any parse errors from template or destination.

Returns:

  • (Array)

    Array of errors



151
152
153
154
155
156
# File 'lib/psych/merge/smart_merger.rb', line 151

def errors
  errors = []
  errors.concat(@template_analysis.errors.map { |e| {source: :template, error: e} })
  errors.concat(@dest_analysis.errors.map { |e| {source: :destination, error: e} })
  errors
end

#mergeString

Perform the merge and return the result as a YAML string.

Returns:

  • (String)

    Merged YAML content



114
115
116
# File 'lib/psych/merge/smart_merger.rb', line 114

def merge
  merge_result.to_yaml
end

#merge_with_debugHash

Perform the merge and return detailed results including debug info.

Returns:

  • (Hash)

    Hash containing :content, :statistics, :decisions



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/psych/merge/smart_merger.rb', line 121

def merge_with_debug
  content = merge

  {
    content: content,
    statistics: @result.statistics,
    decisions: @result.decision_summary,
    template_analysis: {
      valid: @template_analysis.valid?,
      statements: @template_analysis.statements.size,
      freeze_blocks: @template_analysis.freeze_blocks.size,
    },
    dest_analysis: {
      valid: @dest_analysis.valid?,
      statements: @dest_analysis.statements.size,
      freeze_blocks: @dest_analysis.freeze_blocks.size,
    },
  }
end

#valid?Boolean

Check if both files were parsed successfully.

Returns:

  • (Boolean)


144
145
146
# File 'lib/psych/merge/smart_merger.rb', line 144

def valid?
  @template_analysis.valid? && @dest_analysis.valid?
end