Module: AbideDevUtils::XCCDF::Parser::Objects::DigestObject

Included in:
ElementBase
Defined in:
lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb

Overview

Methods for providing and comparing hash digests of objects

Instance Method Summary collapse

Instance Method Details

#digestObject

Returns a SHA256 digest of the object, including the digests of all children



40
41
42
43
44
45
46
47
# File 'lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb', line 40

def digest
  return @digest if defined?(@digest)

  parts = [labeled_self_digest]
  children.each { |child| parts << child.digest } unless children.empty?
  @digest = parts.join('|')
  @digest
end

#digest_equal?(other) ⇒ Boolean

Checks SHA256 digest equality

Returns:

  • (Boolean)


34
35
36
# File 'lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb', line 34

def digest_equal?(other)
  digest == other.digest
end

#digest_similarity(other, only_labels: [], label_weights: {}) ⇒ Object

Compares two objects by their SHA256 digests and returns the degree to which they are similar as a percentage.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb', line 71

def digest_similarity(other, only_labels: [], label_weights: {})
  digest_parts = sorted_digest_parts(digest)
  number_compared = 0
  cumulative_similarity = 0.0
  digest_parts.each do |digest_part|
    label, self_digest = split_labeled_digest(digest_part)
    next unless only_labels.empty? || only_labels.include?(label)

    label_weight = label_weights.key?(label) ? label_weights[label] : 1.0
    sorted_digest_parts(other.digest).each do |other_digest_part|
      other_label, other_digest = split_labeled_digest(other_digest_part)
      next unless (label == other_label) && (self_digest == other_digest)

      number_compared += 1
      cumulative_similarity += 1.0 * label_weight
      break # break when found
    end
  end
  cumulative_similarity / (number_compared.zero? ? 1.0 : number_compared)
end

#digestable_instance_variablesObject

Returns a string of all instance variable values that are not nil, empty, or excluded



57
58
59
60
61
62
63
64
65
66
# File 'lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb', line 57

def digestable_instance_variables
  instance_vars = instance_variables.reject { |iv| @exclude_from_digest.include?(iv) }.sort_by!(&:to_s)
  return 'empty' if instance_vars.empty?

  var_vals = instance_vars.map { |iv| instance_variable_get(iv) }
  var_vals.reject! { |v| v.nil? || v.empty? }
  return 'empty' if var_vals.empty?

  var_vals.join
end

#exclude_from_digest(exclude) ⇒ Object

Excludes instance variables that are not used in the digest



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb', line 10

def exclude_from_digest(exclude)
  unless exclude.is_a?(Array) || exclude.is_a?(Symbol)
    raise ArgumentError, 'exclude must be an Array or Symbol'
  end

  @exclude_from_digest ||= []
  if exclude.is_a?(Array)
    exclude.map! do |e|
      normalize_exclusion(e)
    end
    @exclude_from_digest += exclude
  else
    @exclude_from_digest << normalize_exclusion(exclude)
  end
  @exclude_from_digest.uniq!
end

#labeled_self_digestObject

Returns a labeled digest of the current object



50
51
52
53
54
# File 'lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb', line 50

def labeled_self_digest
  return "#{label}:#{Digest::SHA256.hexdigest(digestable_instance_variables)}" if respond_to?(:label)

  "none:#{Digest::SHA256.hexdigest(digestable_instance_variables)}"
end

#non_compatible?(digest_part, other_digest_part) ⇒ Boolean

If one of the digest parts is nil and the other is not, we can't compare

Returns:

  • (Boolean)


102
103
104
# File 'lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb', line 102

def non_compatible?(digest_part, other_digest_part)
  (digest_part.nil? || other_digest_part.nil?) && digest_part != other_digest_part
end

#normalize_exclusion(exclude) ⇒ Object

Exclusions are instance variable symbols and must be prefixed with “@”



28
29
30
31
# File 'lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb', line 28

def normalize_exclusion(exclude)
  exclude = "@#{exclude}" unless exclude.to_s.start_with?('@')
  exclude.to_sym
end

#sorted_digest_parts(dgst) ⇒ Object



92
93
94
95
96
97
98
99
# File 'lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb', line 92

def sorted_digest_parts(dgst)
  @sorted_digest_parts_cache = {} unless defined?(@sorted_digest_parts_cache)
  return @sorted_digest_parts_cache[dgst] if @sorted_digest_parts_cache.key?(dgst)

  @sorted_digest_parts_cache ||= {}
  @sorted_digest_parts_cache[dgst] = dgst.split('|').sort_by { |part| split_labeled_digest(part).first }
  @sorted_digest_parts_cache[dgst]
end

#split_labeled_digest(digest_part) ⇒ Object

Splits a digest into a label and digest



107
108
109
110
111
112
113
# File 'lib/abide_dev_utils/xccdf/parser/objects/digest_object.rb', line 107

def split_labeled_digest(digest_part)
  @labeled_digest_part_cache = {} unless defined?(@labeled_digest_part_cache)
  return @labeled_digest_part_cache[digest_part] if @labeled_digest_part_cache.key?(digest_part)

  @labeled_digest_part_cache[digest_part] = digest_part.split(':')
  @labeled_digest_part_cache[digest_part]
end