Module: Ast::Merge::TrailingGroups::DestIterate

Includes:
Core
Included in:
Ast::Merge::Text::ConflictResolver
Defined in:
lib/ast/merge/trailing_groups/dest_iterate.rb

Overview

Pattern A — Destination-iterate trailing groups.

Convenience wrapper around Core for gems that iterate destination nodes and match them against template nodes by signature. This is the pattern used by prism-merge, psych-merge, json-merge, jsonc-merge, toml-merge, and bash-merge.

Typical usage

include Ast::Merge::TrailingGroups::DestIterate

# 1. Build groups
groups, matched = build_dest_iterate_trailing_groups(
template_nodes: t_nodes,
dest_sigs: dest_sig_set,
signature_for: ->(node) { analysis.generate_signature(node) },
)

# 2. Emit prefix
emit_prefix_trailing_group(groups, consumed) { |info| emit(info[:node]) }

# 3. Inside dest loop, after each match:
flush_ready_trailing_groups(
trailing_groups: groups,
matched_indices: matched,
consumed_indices: consumed,
) { |info| emit(info[:node]) }

# 4. After dest loop:
emit_remaining_trailing_groups(
trailing_groups: groups,
consumed_indices: consumed,
) { |info| emit(info[:node]) }

Hooks

Override #trailing_group_node_matched? to add format-specific match criteria (e.g. freeze-node detection, refined-match IDs).

Override the entry_builder: parameter on #build_dest_iterate_trailing_groups to add extra keys to each entry (e.g. :item for psych-merge sequences).

Instance Method Summary collapse

Methods included from Core

#build_trailing_groups, #emit_remaining_trailing_groups, #flush_ready_trailing_groups

Instance Method Details

#build_dest_iterate_trailing_groups(template_nodes:, dest_sigs:, signature_for:, refined_template_ids: ::Set.new, entry_builder: nil, add_template_only_nodes: true) ⇒ Array(Hash, Set)

Build trailing groups using destination signatures for match detection.

This is the standard Pattern A builder. A template node is considered "matched" when any of the following is true:

  1. Its signature exists in dest_sigs
  2. Its object_id is in refined_template_ids
  3. #trailing_group_node_matched? returns true (override hook)

Parameters:

  • template_nodes (Array)

    Ordered template nodes

  • dest_sigs (Set)

    Set of destination node signatures

  • signature_for (#call)

    Lambda receiving (node) returning signature

  • refined_template_ids (Set) (defaults to: ::Set.new)

    Object IDs of refined-match template nodes

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

    Custom entry builder (see Core#build_trailing_groups)

  • add_template_only_nodes (Boolean) (defaults to: true)

    Gate — returns empty results when false

Returns:

  • (Array(Hash, Set))

    Tuple of [trailing_groups, matched_indices]



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/ast/merge/trailing_groups/dest_iterate.rb', line 69

def build_dest_iterate_trailing_groups(
  template_nodes:,
  dest_sigs:,
  signature_for:,
  refined_template_ids: ::Set.new,
  entry_builder: nil,
  add_template_only_nodes: true
)
  return [{}, ::Set.new] unless add_template_only_nodes

  predicate = lambda { |node, _idx|
    sig = signature_for.call(node)
    (sig && dest_sigs.include?(sig)) ||
      refined_template_ids.include?(node.object_id) ||
      trailing_group_node_matched?(node, sig)
  }

  build_trailing_groups(
    template_nodes: template_nodes,
    matched_predicate: predicate,
    entry_builder: entry_builder
  )
end

#emit_prefix_trailing_group(trailing_groups, consumed_indices) {|info| ... } ⇒ void

This method returns an undefined value.

Emit the :prefix trailing group (template-only nodes before the first matched template node).

Parameters:

Yields:

  • (info)

    Called for each prefix entry

Yield Parameters:

  • info (Hash)

    Entry hash with at least :node and :index



101
102
103
104
105
106
107
108
109
110
111
# File 'lib/ast/merge/trailing_groups/dest_iterate.rb', line 101

def emit_prefix_trailing_group(trailing_groups, consumed_indices, &emit_block)
  group = trailing_groups[:prefix]
  return unless group

  group.each do |info|
    next if consumed_indices.include?(info[:index])

    emit_block.call(info)
    consumed_indices << info[:index]
  end
end

#trailing_group_node_matched?(_node, _signature) ⇒ Boolean

Hook: additional match criteria for a template node.

Override in including classes to recognize format-specific "always matched" nodes (e.g. freeze nodes in psych-merge, bash-merge).

The default implementation returns false.

Parameters:

  • _node (Object)

    Template node

  • _signature (Object, nil)

    The node's computed signature

Returns:

  • (Boolean)

    true if the node should be treated as matched



123
124
125
# File 'lib/ast/merge/trailing_groups/dest_iterate.rb', line 123

def trailing_group_node_matched?(_node, _signature)
  false
end