Class: Rbs::Merge::SmartMerger

Inherits:
Object
  • Object
show all
Defined in:
lib/rbs/merge/smart_merger.rb

Overview

Orchestrates the smart merge process for RBS type signature files. Uses FileAnalysis, FileAligner, ConflictResolver, and MergeResult to merge two RBS files intelligently.

SmartMerger provides flexible configuration for different merge scenarios. When matching class or module definitions are found in both files, the merger can perform recursive merging of their members.

Examples:

Basic merge (destination customizations preserved)

merger = SmartMerger.new(template_content, dest_content)
result = merger.merge

Template updates win

merger = SmartMerger.new(
  template_content,
  dest_content,
  preference: :template,
  add_template_only_nodes: true
)
result = merger.merge

Custom signature matching

sig_gen = ->(node) { [:decl, node.name.to_s] }
merger = SmartMerger.new(
  template_content,
  dest_content,
  signature_generator: sig_gen
)

See Also:

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, freeze_token: FileAnalysis::DEFAULT_FREEZE_TOKEN, max_recursion_depth: Float::INFINITY) ⇒ SmartMerger

Creates a new SmartMerger for intelligent RBS file merging.

Parameters:

  • template_content (String)

    Template RBS source code

  • dest_content (String)

    Destination RBS source code

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

    Optional proc to generate custom node signatures. The proc receives an RBS declaration and should return one of:

    • An array representing the node’s signature

    • ‘nil` to indicate the node should have no signature

    • The original node to fall through to default signature computation

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

    Controls which version to use when nodes have matching signatures but different content:

    • ‘:destination` (default) - Use destination version (preserves customizations)

    • ‘:template` - Use template version (applies updates)

  • add_template_only_nodes (Boolean) (defaults to: false)

    Controls whether to add nodes that only exist in template:

    • ‘false` (default) - Skip template-only nodes

    • ‘true` - Add template-only nodes to result

  • freeze_token (String) (defaults to: FileAnalysis::DEFAULT_FREEZE_TOKEN)

    Token to use for freeze block markers. Default: “rbs-merge” (looks for # rbs-merge:freeze / # rbs-merge:unfreeze)

  • max_recursion_depth (Integer, Float) (defaults to: Float::INFINITY)

    Maximum depth for recursive body merging. Default: Float::INFINITY (no limit)

Raises:



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

def initialize(
  template_content,
  dest_content,
  signature_generator: nil,
  preference: :destination,
  add_template_only_nodes: false,
  freeze_token: FileAnalysis::DEFAULT_FREEZE_TOKEN,
  max_recursion_depth: Float::INFINITY
)
  @preference = preference
  @add_template_only_nodes = add_template_only_nodes
  @max_recursion_depth = max_recursion_depth

  # Parse template
  begin
    @template_analysis = FileAnalysis.new(
      template_content,
      freeze_token: freeze_token,
      signature_generator: signature_generator,
    )
  rescue RBS::ParsingError => e
    raise TemplateParseError.new([e])
  end

  # Parse destination
  begin
    @dest_analysis = FileAnalysis.new(
      dest_content,
      freeze_token: freeze_token,
      signature_generator: signature_generator,
    )
  rescue RBS::ParsingError => e
    raise DestinationParseError.new([e])
  end

  @aligner = FileAligner.new(@template_analysis, @dest_analysis)
  @resolver = ConflictResolver.new(
    preference: @preference,
    template_analysis: @template_analysis,
    dest_analysis: @dest_analysis,
  )
  @result = MergeResult.new(@template_analysis, @dest_analysis)
end

Instance Attribute Details

#alignerFileAligner (readonly)

Returns Aligner for finding matches and differences.

Returns:

  • (FileAligner)

    Aligner for finding matches and differences



46
47
48
# File 'lib/rbs/merge/smart_merger.rb', line 46

def aligner
  @aligner
end

#dest_analysisFileAnalysis (readonly)

Returns Analysis of the destination file.

Returns:



43
44
45
# File 'lib/rbs/merge/smart_merger.rb', line 43

def dest_analysis
  @dest_analysis
end

#resolverConflictResolver (readonly)

Returns Resolver for handling conflicting content.

Returns:



49
50
51
# File 'lib/rbs/merge/smart_merger.rb', line 49

def resolver
  @resolver
end

#resultMergeResult (readonly)

Returns Result object tracking merged content.

Returns:

  • (MergeResult)

    Result object tracking merged content



52
53
54
# File 'lib/rbs/merge/smart_merger.rb', line 52

def result
  @result
end

#template_analysisFileAnalysis (readonly)

Returns Analysis of the template file.

Returns:



40
41
42
# File 'lib/rbs/merge/smart_merger.rb', line 40

def template_analysis
  @template_analysis
end

Instance Method Details

#mergeString

Perform the merge operation

Returns:

  • (String)

    The merged content as a string



130
131
132
# File 'lib/rbs/merge/smart_merger.rb', line 130

def merge
  merge_result.to_s
end

#merge_resultMergeResult

Perform the merge operation and return the full result object

Returns:

  • (MergeResult)

    The merge result containing merged content



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/rbs/merge/smart_merger.rb', line 137

def merge_result
  return @merge_result if @merge_result

  @merge_result = DebugLogger.time("SmartMerger#merge") do
    alignment = @aligner.align

    DebugLogger.debug("Alignment complete", {
      total_entries: alignment.size,
      matches: alignment.count { |e| e[:type] == :match },
      template_only: alignment.count { |e| e[:type] == :template_only },
      dest_only: alignment.count { |e| e[:type] == :dest_only },
    })

    process_alignment(alignment)
    @result
  end
end