Module: PaperTrailDiff::Support
- Defined in:
- lib/paper_trail_diff/support.rb,
sig/generated/paper_trail_diff/support.rbs
Overview
Internal helpers for isolating and serializing values held by result objects.
Class Method Summary collapse
- .ambiguous_message(pair) ⇒ Object
- .ambiguous_pair(sorted) ⇒ Object
- .association_path(parent, name) ⇒ Object
-
.chronological_sort(versions) ⇒ Object
Ordering falls back to the id whenever timestamps tie, which recovers the real order only while ids increase with insertion.
- .chronological_version_key(version) ⇒ Object
- .compare_versions(left, right) ⇒ Object
- .immutable_copy(value) ⇒ Object
- .merge_record_groups(existing, incoming) ⇒ Object
- .sequential_id?(id) ⇒ Boolean
- .serialize(value) ⇒ Object
Instance Method Summary collapse
-
#self?.ambiguous_message ⇒ String
: (Array) -> String.
- #self?.ambiguous_pair ⇒ Array[untyped]?
-
#self?.association_path ⇒ String
: (String, String) -> String.
-
#self?.chronological_sort ⇒ Array[untyped]
Ordering falls back to the id whenever timestamps tie, which recovers the real order only while ids increase with insertion.
-
#self?.chronological_version_key ⇒ Array[untyped]
: (untyped) -> Array.
-
#self?.compare_versions ⇒ Integer
: (untyped, untyped) -> Integer.
-
#self?.duplicate_and_freeze ⇒ Object
: (untyped) -> untyped.
-
#self?.immutable_copy ⇒ Object
: (untyped) -> untyped.
-
#self?.immutable_hash ⇒ Hash[untyped, untyped]
: (Hash[untyped, untyped]) -> Hash[untyped, untyped].
-
#self?.merge_record_groups ⇒ Hash[String, Hash[Symbol, untyped]]
: (Hash[String, Hash[Symbol, untyped]], Hash[String, Hash[Symbol, untyped]]) -> Hash[String, Hash[Symbol, untyped]].
-
#self?.merge_record_owners ⇒ Hash[String, Array[untyped]]?
: (Hash[String, Array[untyped]]?, Hash[String, Array[untyped]]?) -> Hash[String, Array[untyped]]?.
-
#self?.paper_trail_diff_value? ⇒ Boolean
: (untyped) -> bool.
-
#self?.sequential_id? ⇒ Boolean
: (untyped) -> bool.
-
#self?.serialize ⇒ Object
: (untyped) -> untyped.
Class Method Details
.ambiguous_message(pair) ⇒ Object
81 82 83 84 85 86 87 |
# File 'lib/paper_trail_diff/support.rb', line 81 def (pair) left, right = pair "versions #{left.id.inspect} and #{right.id.inspect} share the timestamp " \ "#{left.created_at.inspect} and have ids that do not order them, so their " \ 'sequence cannot be recovered; record versions at sub-second precision or ' \ 'with sequential ids' end |
.ambiguous_pair(sorted) ⇒ Object
68 69 70 71 72 73 |
# File 'lib/paper_trail_diff/support.rb', line 68 def ambiguous_pair(sorted) sorted.each_cons(2).find do |left, right| left.created_at == right.created_at && !(sequential_id?(left.id) && sequential_id?(right.id)) end end |
.association_path(parent, name) ⇒ Object
96 97 98 |
# File 'lib/paper_trail_diff/support.rb', line 96 def association_path(parent, name) parent.empty? ? name : "#{parent}.#{name}" end |
.chronological_sort(versions) ⇒ Object
Ordering falls back to the id whenever timestamps tie, which recovers the real order only while ids increase with insertion. An autoincrement id does; a UUID does not, so a tie between UUID-keyed versions is genuinely unorderable and any timeline built from it would be fiction.
59 60 61 62 63 64 65 |
# File 'lib/paper_trail_diff/support.rb', line 59 def chronological_sort(versions) sorted = versions.sort_by { |version| chronological_version_key(version) } ambiguous = ambiguous_pair(sorted) return sorted unless ambiguous raise AmbiguousVersionOrderError, (ambiguous) end |
.chronological_version_key(version) ⇒ Object
50 51 52 |
# File 'lib/paper_trail_diff/support.rb', line 50 def chronological_version_key(version) [version.created_at, version.id.to_s.rjust(32, '0')] end |
.compare_versions(left, right) ⇒ Object
90 91 92 93 |
# File 'lib/paper_trail_diff/support.rb', line 90 def compare_versions(left, right) chronological_version_key(left) <=> chronological_version_key(right) || raise(ConfigurationError, 'versions have incomparable timestamps') end |
.immutable_copy(value) ⇒ Object
10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/paper_trail_diff/support.rb', line 10 def immutable_copy(value) return value if value.frozen? case value when Hash immutable_hash(value) when Array value.map { |item| immutable_copy(item) }.freeze else duplicate_and_freeze(value) end end |
.merge_record_groups(existing, incoming) ⇒ Object
101 102 103 104 105 106 107 |
# File 'lib/paper_trail_diff/support.rb', line 101 def merge_record_groups(existing, incoming) existing.merge(incoming) do |_name, left, right| merged = left.merge(right, ids: (left.fetch(:ids) | right.fetch(:ids))) owners = merge_record_owners(left[:owners], right[:owners]) owners ? merged.merge(owners: owners) : merged end end |
.sequential_id?(id) ⇒ Boolean
76 77 78 |
# File 'lib/paper_trail_diff/support.rb', line 76 def sequential_id?(id) id.is_a?(Integer) || id.to_s.match?(/\A\d+\z/) end |
.serialize(value) ⇒ Object
34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/paper_trail_diff/support.rb', line 34 def serialize(value) case value when Hash serialized = {} #: Hash[untyped, untyped] value.each do |key, item| serialized[key] = serialize(item) end serialized when Array value.map { |item| serialize(item) } else paper_trail_diff_value?(value) ? value.to_h : value end end |
Instance Method Details
#self?.ambiguous_message ⇒ String
: (Array) -> String
32 |
# File 'sig/generated/paper_trail_diff/support.rbs', line 32
def self?.ambiguous_message: (Array[untyped]) -> String
|
#self?.ambiguous_pair ⇒ Array[untyped]?
26 |
# File 'sig/generated/paper_trail_diff/support.rbs', line 26
def self?.ambiguous_pair: (Array[untyped]) -> Array[untyped]?
|
#self?.association_path ⇒ String
: (String, String) -> String
38 |
# File 'sig/generated/paper_trail_diff/support.rbs', line 38
def self?.association_path: (String, String) -> String
|
#self?.chronological_sort ⇒ Array[untyped]
23 |
# File 'sig/generated/paper_trail_diff/support.rbs', line 23
def self?.chronological_sort: (Array[untyped]) -> Array[untyped]
|
#self?.chronological_version_key ⇒ Array[untyped]
: (untyped) -> Array
16 |
# File 'sig/generated/paper_trail_diff/support.rbs', line 16
def self?.chronological_version_key: (untyped) -> Array[untyped]
|
#self?.compare_versions ⇒ Integer
: (untyped, untyped) -> Integer
35 |
# File 'sig/generated/paper_trail_diff/support.rbs', line 35
def self?.compare_versions: (untyped, untyped) -> Integer
|
#self?.duplicate_and_freeze ⇒ Object
: (untyped) -> untyped
44 |
# File 'sig/generated/paper_trail_diff/support.rbs', line 44
def self?.duplicate_and_freeze: (untyped) -> untyped
|
#self?.immutable_copy ⇒ Object
: (untyped) -> untyped
7 |
# File 'sig/generated/paper_trail_diff/support.rbs', line 7
def self?.immutable_copy: (untyped) -> untyped
|
#self?.immutable_hash ⇒ Hash[untyped, untyped]
: (Hash[untyped, untyped]) -> Hash[untyped, untyped]
10 |
# File 'sig/generated/paper_trail_diff/support.rbs', line 10
def self?.immutable_hash: (Hash[untyped, untyped]) -> Hash[untyped, untyped]
|
#self?.merge_record_groups ⇒ Hash[String, Hash[Symbol, untyped]]
: (Hash[String, Hash[Symbol, untyped]], Hash[String, Hash[Symbol, untyped]]) -> Hash[String, Hash[Symbol, untyped]]
41 |
# File 'sig/generated/paper_trail_diff/support.rbs', line 41
def self?.merge_record_groups: (Hash[String, Hash[Symbol, untyped]], Hash[String, Hash[Symbol, untyped]]) -> Hash[String, Hash[Symbol, untyped]]
|
#self?.merge_record_owners ⇒ Hash[String, Array[untyped]]?
: (Hash[String, Array[untyped]]?, Hash[String, Array[untyped]]?) -> Hash[String, Array[untyped]]?
47 |
# File 'sig/generated/paper_trail_diff/support.rbs', line 47
def self?.merge_record_owners: (Hash[String, Array[untyped]]?, Hash[String, Array[untyped]]?) -> Hash[String, Array[untyped]]?
|
#self?.paper_trail_diff_value? ⇒ Boolean
: (untyped) -> bool
50 |
# File 'sig/generated/paper_trail_diff/support.rbs', line 50
def self?.paper_trail_diff_value?: (untyped) -> bool
|
#self?.sequential_id? ⇒ Boolean
: (untyped) -> bool
29 |
# File 'sig/generated/paper_trail_diff/support.rbs', line 29
def self?.sequential_id?: (untyped) -> bool
|
#self?.serialize ⇒ Object
: (untyped) -> untyped
13 |
# File 'sig/generated/paper_trail_diff/support.rbs', line 13
def self?.serialize: (untyped) -> untyped
|