Class: Canon::Comparison::XmlComparatorHelpers::AttributeFilter

Inherits:
Object
  • Object
show all
Defined in:
lib/canon/comparison/xml_comparator/attribute_filter.rb

Overview

Attribute filtering logic Handles filtering of attributes based on options and match settings

Class Method Summary collapse

Class Method Details

.filter(attributes, opts) ⇒ Hash

Filter attributes based on options

Parameters:

  • attributes (Array, Hash)

    Raw attributes

  • opts (Hash)

    Comparison options

Returns:

  • (Hash)

    Filtered attributes



16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 16

def self.filter(attributes, opts)
  filtered = {}
  match_opts = opts[:match_opts]

  # Handle Canon::Xml::Node attribute format (array of AttributeNode)
  if attributes.is_a?(Array)
    filter_array_attributes(attributes, opts, match_opts, filtered)
  else
    # Handle Nokogiri and Moxml attribute formats (Hash-like)
    filter_hash_attributes(attributes, opts, match_opts, filtered)
  end

  filtered
end

.filter_array_attributes(attributes, opts, match_opts, filtered) ⇒ Object

Filter array-format attributes (Canon::Xml::Node)

Parameters:

  • attributes (Array)

    Array of AttributeNode objects

  • opts (Hash)

    Comparison options

  • match_opts (Hash)

    Resolved match options

  • filtered (Hash)

    Output hash to populate



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 37

def self.filter_array_attributes(attributes, opts, match_opts, filtered)
  attributes.each do |attr|
    name = attr.name
    value = attr.value

    # Skip namespace declarations - they're handled separately
    next if namespace_declaration?(name)

    # Skip if attribute name should be ignored
    next if ignore_by_name?(name, opts)

    # Skip if attribute content should be ignored
    next if ignore_by_content?(value, opts)

    # Apply match options for attribute values
    behavior = match_opts[:attribute_values] || :strict
    value = MatchOptions.process_attribute_value(value, behavior)

    filtered[name] = value
  end
end

.filter_hash_attributes(attributes, opts, match_opts, filtered) ⇒ Object

Filter hash-format attributes (Nokogiri/Moxml)

Parameters:

  • attributes (Hash)

    Hash-like attributes

  • opts (Hash)

    Comparison options

  • match_opts (Hash)

    Resolved match options

  • filtered (Hash)

    Output hash to populate



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 65

def self.filter_hash_attributes(attributes, opts, match_opts, filtered)
  attributes.each do |key, val|
    # Normalize key and value
    name, value = normalize_attribute_pair(key, val)

    # Skip namespace declarations - they're handled separately
    next if namespace_declaration?(name)

    # Skip if attribute name should be ignored
    next if ignore_by_name?(name, opts)

    # Skip if attribute content should be ignored
    next if ignore_by_content?(value, opts)

    # Apply match options for attribute values
    behavior = match_opts[:attribute_values] || :strict
    value = MatchOptions.process_attribute_value(value, behavior)

    filtered[name] = value
  end
end

.ignore_by_content?(value, opts) ⇒ Boolean

Check if attribute should be ignored by content

Parameters:

  • value (String)

    Attribute value

  • opts (Hash)

    Comparison options

Returns:

  • (Boolean)

    true if should ignore



120
121
122
123
124
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 120

def self.ignore_by_content?(value, opts)
  opts[:ignore_attr_content].any? do |pattern|
    value.to_s.include?(pattern)
  end
end

.ignore_by_name?(name, opts) ⇒ Boolean

Check if attribute should be ignored by name

Parameters:

  • name (String)

    Attribute name

  • opts (Hash)

    Comparison options

Returns:

  • (Boolean)

    true if should ignore



111
112
113
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 111

def self.ignore_by_name?(name, opts)
  opts[:ignore_attrs_by_name].any? { |pattern| name.include?(pattern) }
end

.namespace_declaration?(attr_name) ⇒ Boolean

Check if an attribute name is a namespace declaration

Parameters:

  • attr_name (String)

    Attribute name

Returns:

  • (Boolean)

    true if it’s a namespace declaration



130
131
132
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 130

def self.namespace_declaration?(attr_name)
  attr_name == "xmlns" || attr_name.start_with?("xmlns:")
end

.normalize_attribute_pair(key, val) ⇒ Array<String, String>

Normalize attribute key-value pair from different formats

Parameters:

  • key (Object)

    Attribute key (String or Attribute object)

  • val (Object)

    Attribute value

Returns:

  • (Array<String, String>)

    Normalized [name, value] pair



92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/canon/comparison/xml_comparator/attribute_filter.rb', line 92

def self.normalize_attribute_pair(key, val)
  if key.is_a?(String)
    # Nokogiri format: key=name (String), val=attr object
    name = key
    value = val.respond_to?(:value) ? val.value : val.to_s
  else
    # Moxml format: key=attr object, val=nil
    name = key.respond_to?(:name) ? key.name : key.to_s
    value = key.respond_to?(:value) ? key.value : key.to_s
  end

  [name, value]
end