Module: Canon::TreeDiff::OperationConverterHelpers::ReasonBuilder

Defined in:
lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb

Overview

Reason string builders for operations Handles creation of human-readable reason messages for DiffNodes

Class Method Summary collapse

Class Method Details

.build_attribute_diff_details(old_attrs, new_attrs) ⇒ String

Build detailed reason for attribute differences

Parameters:

  • old_attrs (Hash)

    Old attributes

  • new_attrs (Hash)

    New attributes

Returns:

  • (String)

    Detailed reason



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb', line 72

def self.build_attribute_diff_details(old_attrs, new_attrs)
  old_keys = Set.new(old_attrs.keys)
  new_keys = Set.new(new_attrs.keys)

  missing = old_keys - new_keys
  extra = new_keys - old_keys
  changed = (old_keys & new_keys).reject do |k|
    old_attrs[k] == new_attrs[k]
  end

  parts = []
  parts << "Missing: #{missing.to_a.join(', ')}" if missing.any?
  parts << "Extra: #{extra.to_a.join(', ')}" if extra.any?
  if changed.any?
    parts << "Changed: #{changed.map do |k|
      "#{k}=\"#{truncate(old_attrs[k],
                         20)}\" → \"#{truncate(new_attrs[k], 20)}\""
    end.join(', ')}"
  end

  parts.any? ? "Attributes differ (#{parts.join('; ')})" : "Attribute values differ"
end

.build_attribute_order_reason(changes) ⇒ String

Build reason for attribute order changes

Parameters:

  • changes (Hash)

    Changes hash

Returns:

  • (String)

    Reason description



112
113
114
115
116
117
118
119
120
# File 'lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb', line 112

def self.build_attribute_order_reason(changes)
  if changes.is_a?(Hash) && changes.key?(:old)
    old_order = changes[:old]
    new_order = changes[:new]
    "Attribute order changed: [#{old_order.join(', ')}] → [#{new_order.join(', ')}]"
  else
    "attribute order differs"
  end
end

.build_attribute_value_reason(changes) ⇒ String

Build reason for attribute value changes

Parameters:

  • changes (Hash)

    Changes hash

Returns:

  • (String)

    Reason description



99
100
101
102
103
104
105
106
# File 'lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb', line 99

def self.build_attribute_value_reason(changes)
  # Changes can be either true (flag) or { old: ..., new: ... } (detailed)
  if changes.is_a?(Hash) && changes.key?(:old)
    build_attribute_diff_details(changes[:old], changes[:new])
  else
    "attribute values differ"
  end
end

.build_delete_reason(operation) ⇒ String

Build reason string for DELETE operation

Parameters:

  • operation (Operation)

    Operation

Returns:

  • (String)

    Reason description



31
32
33
34
35
36
37
38
39
40
41
# File 'lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb', line 31

def self.build_delete_reason(operation)
  node = operation[:node]
  content = operation[:content]

  if node.respond_to?(:label)
    # Include content preview for clarity
    "Element deleted: #{content || "<#{node.label}>"}"
  else
    "Element deleted"
  end
end

.build_element_name_reason(changes) ⇒ String

Build reason for element name changes

Parameters:

  • changes (Hash)

    Changes hash

Returns:

  • (String)

    Reason description



142
143
144
145
146
147
148
149
150
# File 'lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb', line 142

def self.build_element_name_reason(changes)
  if changes.is_a?(Hash) && changes.key?(:old)
    old_label = changes[:old]
    new_label = changes[:new]
    "Element name changed: <#{old_label}> → <#{new_label}>"
  else
    "element name differs"
  end
end

.build_insert_reason(operation) ⇒ String

Build reason string for INSERT operation

Parameters:

  • operation (Operation)

    Operation

Returns:

  • (String)

    Reason description



15
16
17
18
19
20
21
22
23
24
25
# File 'lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb', line 15

def self.build_insert_reason(operation)
  node = operation[:node]
  content = operation[:content]

  if node.respond_to?(:label)
    # Include content preview for clarity
    "Element inserted: #{content || "<#{node.label}>"}"
  else
    "Element inserted"
  end
end

.build_move_reason(operation) ⇒ String

Build reason string for MOVE operation

Parameters:

  • operation (Operation)

    Operation

Returns:

  • (String)

    Reason description



56
57
58
59
60
61
62
63
64
65
# File 'lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb', line 56

def self.build_move_reason(operation)
  from_pos = operation[:from_position]
  to_pos = operation[:to_position]

  if from_pos && to_pos
    "moved from position #{from_pos} to #{to_pos}"
  else
    "moved to different position"
  end
end

.build_text_content_reason(changes) ⇒ String

Build reason for text content changes

Parameters:

  • changes (Hash)

    Changes hash

Returns:

  • (String)

    Reason description



126
127
128
129
130
131
132
133
134
135
136
# File 'lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb', line 126

def self.build_text_content_reason(changes)
  if changes.is_a?(Hash) && changes.key?(:old)
    old_val = changes[:old] || ""
    new_val = changes[:new] || ""
    preview_old = truncate(old_val.to_s, 40)
    preview_new = truncate(new_val.to_s, 40)
    "Text content changed: \"#{preview_old}\" → \"#{preview_new}\""
  else
    "text content differs"
  end
end

.build_update_reason(operation) ⇒ String

Build reason string for UPDATE operation

Parameters:

  • operation (Operation)

    Operation

Returns:

  • (String)

    Reason description



47
48
49
50
# File 'lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb', line 47

def self.build_update_reason(operation)
  change_type = operation[:change_type] || "content"
  "updated #{change_type}"
end

.truncate(text, max_length) ⇒ String

Truncate text for reason messages

Parameters:

  • text (String)

    Text to truncate

  • max_length (Integer)

    Maximum length

Returns:

  • (String)

    Truncated text



157
158
159
160
161
162
163
164
# File 'lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb', line 157

def self.truncate(text, max_length)
  return "" if text.nil?

  text = text.to_s
  return text if text.length <= max_length

  "#{text[0...(max_length - 3)]}..."
end