Class: Fingerprintable::Fingerprinter

Inherits:
Object
  • Object
show all
Defined in:
lib/fingerprintable/fingerprinter.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attributes: [], cache: {}, fallback_to_string: false, ignore: [], object:) ⇒ Fingerprinter

Returns a new instance of Fingerprinter.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/fingerprintable/fingerprinter.rb', line 10

def initialize(
  attributes: [],
  cache: {},
  fallback_to_string: false,
  ignore: [],
  object:
)
  @fallback_to_string = fallback_to_string
  @ignore = ignore | ignore.map { |e| "@#{e}".to_sym }
  @object = object
  @attributes = populate_attributes(attributes: attributes, ignore: ignore)
  @cache = cache || {}
  @cache[object] = next_cache_id
  @fingerprinted = false
end

Instance Attribute Details

#attributesObject (readonly)

Returns the value of attribute attributes.



5
6
7
# File 'lib/fingerprintable/fingerprinter.rb', line 5

def attributes
  @attributes
end

#fallback_to_stringObject (readonly)

Returns the value of attribute fallback_to_string.



5
6
7
# File 'lib/fingerprintable/fingerprinter.rb', line 5

def fallback_to_string
  @fallback_to_string
end

#ignoreObject (readonly)

Returns the value of attribute ignore.



5
6
7
# File 'lib/fingerprintable/fingerprinter.rb', line 5

def ignore
  @ignore
end

#objectObject (readonly)

Returns the value of attribute object.



5
6
7
# File 'lib/fingerprintable/fingerprinter.rb', line 5

def object
  @object
end

Class Method Details

.diff(obj1, obj2) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/fingerprintable/fingerprinter.rb', line 80

def self.diff(obj1, obj2)
  f1 =  if obj1.respond_to?(:fingerprinter)
          obj1.fingerprinter
        else
          Fingerprinter.new(object: obj1)
        end

  f2 =  if obj2.respond_to?(:fingerprinter)
          obj2.fingerprinter
        else
          Fingerprinter.new(object: obj2)
        end

  f1.diff(f2)
end

Instance Method Details

#cacheObject



26
27
28
29
# File 'lib/fingerprintable/fingerprinter.rb', line 26

def cache
  fingerprint unless @fingerprinted
  @cache
end

#deep_convert_and_sort(obj) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/fingerprintable/fingerprinter.rb', line 44

def deep_convert_and_sort(obj)
  case obj
  when nil
    ''
  when String
    obj.to_s
  when FalseClass, Float, Integer, Symbol, TrueClass
    obj.to_s
  when Array
    obj.map { |v| deep_convert_and_sort(v) }.sort.to_s
  when Hash
    Hash[obj.map { |k, v| [deep_convert_and_sort(k), deep_convert_and_sort(v)] }].sort.to_s
  when Module
    obj.name
  else
    fingerprint_object(obj)
  end
end

#diff(other_fingerprinter) ⇒ Object



31
32
33
34
35
36
37
38
# File 'lib/fingerprintable/fingerprinter.rb', line 31

def diff(other_fingerprinter)
  raise "Passed object (#{other_fingerprinter.class.name}) does not match the fingerprinter object class: #{object.class.name}" if object.class != other_fingerprinter.object.class

  values = object_values_hash
  other_values = other_fingerprinter.object_values_hash

  (attributes | other_fingerprinter.attributes).reject { |e| values[e] == other_values[e] }
end

#diff?(other_fingerprinter) ⇒ Boolean

Returns:

  • (Boolean)


40
41
42
# File 'lib/fingerprintable/fingerprinter.rb', line 40

def diff?(other_fingerprinter)
  diff(other_fingerprinter).any?
end

#fingerprintObject



63
64
65
66
67
68
# File 'lib/fingerprintable/fingerprinter.rb', line 63

def fingerprint
  @fingerprint ||= begin
    @fingerprinted = true
    Digest::MD5.hexdigest(to_s)
  end
end

#object_values_hashObject



70
71
72
73
74
# File 'lib/fingerprintable/fingerprinter.rb', line 70

def object_values_hash
  @object_values_hash ||= Hash[attributes.map do |attr|
    [attr, object.send(attr)]
  end]
end

#to_sObject



76
77
78
# File 'lib/fingerprintable/fingerprinter.rb', line 76

def to_s
  @to_s ||= deep_convert_and_sort(object_values_hash).to_s
end