paper_trail_diff 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -0
- data/QUICKSTART.md +260 -0
- data/README.md +79 -5
- data/lib/paper_trail_diff/activity_boundary.rb +34 -3
- data/lib/paper_trail_diff/association_diff_traversal.rb +184 -0
- data/lib/paper_trail_diff/snapshot_traversal.rb +97 -0
- data/lib/paper_trail_diff/step.rb +9 -0
- data/lib/paper_trail_diff/traversal.rb +80 -0
- data/lib/paper_trail_diff/traversal_emitter.rb +42 -0
- data/lib/paper_trail_diff/traversal_entry.rb +94 -0
- data/lib/paper_trail_diff/version.rb +1 -1
- data/lib/paper_trail_diff.rb +10 -1
- data/sig/generated/paper_trail_diff/activity_boundary.rbs +17 -2
- data/sig/generated/paper_trail_diff/association_diff_traversal.rbs +58 -0
- data/sig/generated/paper_trail_diff/snapshot_traversal.rbs +29 -0
- data/sig/generated/paper_trail_diff/step.rbs +7 -0
- data/sig/generated/paper_trail_diff/traversal.rbs +41 -0
- data/sig/generated/paper_trail_diff/traversal_emitter.rbs +16 -0
- data/sig/generated/paper_trail_diff/traversal_entry.rbs +52 -0
- data/sig/generated/paper_trail_diff.rbs +8 -0
- metadata +15 -4
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
module PaperTrailDiff
|
|
5
|
+
# Walks nested state included in an added, removed, or replaced record snapshot.
|
|
6
|
+
class SnapshotTraversal < TraversalEmitter
|
|
7
|
+
#: (RecordSnapshot, association_path: traversal_association_path, record_path: traversal_record_path, state: traversal_state, ?association_kind: Symbol?, ?include_record: bool) -> void
|
|
8
|
+
def call( # rubocop:disable Metrics/ParameterLists
|
|
9
|
+
snapshot,
|
|
10
|
+
association_path:,
|
|
11
|
+
record_path:,
|
|
12
|
+
state:,
|
|
13
|
+
association_kind: nil,
|
|
14
|
+
include_record: true
|
|
15
|
+
)
|
|
16
|
+
if include_record
|
|
17
|
+
emit_record(snapshot, association_path, record_path, state, association_kind)
|
|
18
|
+
end
|
|
19
|
+
emit_attributes(snapshot, association_path, record_path, state, association_kind)
|
|
20
|
+
emit_associations(snapshot, association_path, record_path, state)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
#: (RecordSnapshot, traversal_association_path, traversal_record_path, traversal_state, Symbol?) -> void
|
|
26
|
+
def emit_record(snapshot, association_path, record_path, state, association_kind)
|
|
27
|
+
emit(
|
|
28
|
+
kind: :record_included,
|
|
29
|
+
context: :included_state,
|
|
30
|
+
association_path: association_path,
|
|
31
|
+
record_path: record_path,
|
|
32
|
+
association_kind: association_kind,
|
|
33
|
+
state: state,
|
|
34
|
+
value: snapshot.reference
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
#: (RecordSnapshot, traversal_association_path, traversal_record_path, traversal_state, Symbol?) -> void
|
|
39
|
+
def emit_attributes(snapshot, association_path, record_path, state, association_kind)
|
|
40
|
+
snapshot.attributes.each do |name, value|
|
|
41
|
+
emit_attribute(name, value, association_path, record_path, state, association_kind)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
#: (String, untyped, traversal_association_path, traversal_record_path, traversal_state, Symbol?) -> void
|
|
46
|
+
def emit_attribute( # rubocop:disable Metrics/ParameterLists
|
|
47
|
+
name, value, association_path, record_path, state, association_kind
|
|
48
|
+
)
|
|
49
|
+
emit(
|
|
50
|
+
kind: :attribute_included,
|
|
51
|
+
context: :included_state,
|
|
52
|
+
association_path: association_path,
|
|
53
|
+
record_path: record_path,
|
|
54
|
+
association_kind: association_kind,
|
|
55
|
+
state: state,
|
|
56
|
+
attribute: name,
|
|
57
|
+
value: value
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
#: (RecordSnapshot, traversal_association_path, traversal_record_path, traversal_state) -> void
|
|
62
|
+
def emit_associations(snapshot, association_path, record_path, state)
|
|
63
|
+
snapshot.associations.each do |name, association|
|
|
64
|
+
child_path = association_path + [name]
|
|
65
|
+
emit_association(association, child_path, record_path, state)
|
|
66
|
+
emit_association_records(association, child_path, record_path, state)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
#: (AssociationSnapshot, traversal_association_path, traversal_record_path, traversal_state) -> void
|
|
71
|
+
def emit_association(association, association_path, record_path, state)
|
|
72
|
+
emit(
|
|
73
|
+
kind: :association_included,
|
|
74
|
+
context: :included_state,
|
|
75
|
+
association_path: association_path,
|
|
76
|
+
record_path: record_path,
|
|
77
|
+
association_kind: association.kind,
|
|
78
|
+
state: state,
|
|
79
|
+
value: association
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
#: (AssociationSnapshot, traversal_association_path, traversal_record_path, traversal_state) -> void
|
|
84
|
+
def emit_association_records(association, association_path, record_path, state)
|
|
85
|
+
association.records.each do |snapshot|
|
|
86
|
+
call(
|
|
87
|
+
snapshot,
|
|
88
|
+
association_path: association_path,
|
|
89
|
+
record_path: record_path + [snapshot.reference],
|
|
90
|
+
state: state,
|
|
91
|
+
association_kind: association.kind
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
private_constant :SnapshotTraversal
|
|
97
|
+
end
|
|
@@ -6,16 +6,25 @@ module PaperTrailDiff
|
|
|
6
6
|
class Step
|
|
7
7
|
attr_reader :from_version #: untyped
|
|
8
8
|
attr_reader :to_version #: untyped
|
|
9
|
+
attr_reader :from_boundary #: ActivityBoundary
|
|
10
|
+
attr_reader :to_boundary #: ActivityBoundary
|
|
9
11
|
attr_reader :diff #: Diff
|
|
10
12
|
|
|
11
13
|
#: (from_version: untyped, to_version: untyped, diff: Diff) -> void
|
|
12
14
|
def initialize(from_version:, to_version:, diff:)
|
|
13
15
|
@from_version = from_version
|
|
14
16
|
@to_version = to_version
|
|
17
|
+
@from_boundary = ActivityBoundary.from_version(from_version)
|
|
18
|
+
@to_boundary = ActivityBoundary.from_version(to_version)
|
|
15
19
|
@diff = diff
|
|
16
20
|
freeze
|
|
17
21
|
end
|
|
18
22
|
|
|
23
|
+
#: () -> bool
|
|
24
|
+
def empty?
|
|
25
|
+
diff.empty?
|
|
26
|
+
end
|
|
27
|
+
|
|
19
28
|
#: () -> Hash[Symbol, untyped]
|
|
20
29
|
def to_h
|
|
21
30
|
{
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
module PaperTrailDiff
|
|
5
|
+
# Coordinates root lifecycle, scalar, and association traversal.
|
|
6
|
+
class DiffTraversal < TraversalEmitter
|
|
7
|
+
#: (Diff, ^(TraversalEntry) -> void) -> void
|
|
8
|
+
def initialize(diff, receiver)
|
|
9
|
+
super(receiver)
|
|
10
|
+
@diff = diff
|
|
11
|
+
@associations = AssociationDiffTraversal.new(receiver)
|
|
12
|
+
@snapshots = SnapshotTraversal.new(receiver)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
#: () -> void
|
|
16
|
+
def call
|
|
17
|
+
walk_presence_change
|
|
18
|
+
@associations.attributes(
|
|
19
|
+
@diff.attributes,
|
|
20
|
+
association_path: [],
|
|
21
|
+
record_path: [],
|
|
22
|
+
association_kind: nil
|
|
23
|
+
)
|
|
24
|
+
@associations.call(@diff.associations, association_path: [], record_path: [])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
# @rbs @diff: Diff
|
|
30
|
+
# @rbs @associations: AssociationDiffTraversal
|
|
31
|
+
# @rbs @snapshots: SnapshotTraversal
|
|
32
|
+
|
|
33
|
+
#: () -> void
|
|
34
|
+
def walk_presence_change
|
|
35
|
+
change = @diff.record_presence_change
|
|
36
|
+
return unless change
|
|
37
|
+
|
|
38
|
+
emit(
|
|
39
|
+
kind: :record_presence_changed,
|
|
40
|
+
context: :change,
|
|
41
|
+
association_path: [],
|
|
42
|
+
record_path: [],
|
|
43
|
+
value: change
|
|
44
|
+
)
|
|
45
|
+
walk_presence_snapshot(change.from, :before)
|
|
46
|
+
walk_presence_snapshot(change.to, :after)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
#: (RecordSnapshot?, traversal_state) -> void
|
|
50
|
+
def walk_presence_snapshot(snapshot, state)
|
|
51
|
+
return unless snapshot
|
|
52
|
+
|
|
53
|
+
@snapshots.call(snapshot, association_path: [], record_path: [], state: state)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
private_constant :DiffTraversal
|
|
57
|
+
|
|
58
|
+
# The complete structured difference between two normalized endpoints.
|
|
59
|
+
class Diff
|
|
60
|
+
# Walks semantic changes and the nested state carried by added or removed records.
|
|
61
|
+
# @rbs () { (TraversalEntry) -> void } -> Diff
|
|
62
|
+
# | () -> Enumerator[TraversalEntry, Diff]
|
|
63
|
+
def each_entry(&receiver)
|
|
64
|
+
return enum_for(:each_entry) unless receiver
|
|
65
|
+
|
|
66
|
+
DiffTraversal.new(self, receiver).call
|
|
67
|
+
self
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Walks only semantic changes, excluding snapshot state included for context.
|
|
71
|
+
# @rbs () { (TraversalEntry) -> void } -> Diff
|
|
72
|
+
# | () -> Enumerator[TraversalEntry, Diff]
|
|
73
|
+
def each_change(&receiver)
|
|
74
|
+
return enum_for(:each_change) unless receiver
|
|
75
|
+
|
|
76
|
+
each_entry { |entry| receiver.call(entry) if entry.change? }
|
|
77
|
+
self
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
module PaperTrailDiff
|
|
5
|
+
# Shared entry construction for internal traversal collaborators.
|
|
6
|
+
class TraversalEmitter
|
|
7
|
+
#: (^(TraversalEntry) -> void) -> void
|
|
8
|
+
def initialize(receiver)
|
|
9
|
+
@receiver = receiver
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
# @rbs @receiver: ^(TraversalEntry) -> void
|
|
15
|
+
|
|
16
|
+
#: (kind: Symbol, context: traversal_context, association_path: traversal_association_path, record_path: traversal_record_path, value: untyped, ?association_kind: Symbol?, ?state: traversal_state?, ?attribute: String?) -> void
|
|
17
|
+
def emit( # rubocop:disable Metrics/ParameterLists
|
|
18
|
+
kind:,
|
|
19
|
+
context:,
|
|
20
|
+
association_path:,
|
|
21
|
+
record_path:,
|
|
22
|
+
value:,
|
|
23
|
+
association_kind: nil,
|
|
24
|
+
state: nil,
|
|
25
|
+
attribute: nil
|
|
26
|
+
)
|
|
27
|
+
@receiver.call(
|
|
28
|
+
TraversalEntry.new(
|
|
29
|
+
kind: kind,
|
|
30
|
+
context: context,
|
|
31
|
+
association_path: association_path,
|
|
32
|
+
record_path: record_path,
|
|
33
|
+
association_kind: association_kind,
|
|
34
|
+
state: state,
|
|
35
|
+
attribute: attribute,
|
|
36
|
+
value: value
|
|
37
|
+
)
|
|
38
|
+
)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
private_constant :TraversalEmitter
|
|
42
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
module PaperTrailDiff
|
|
5
|
+
# One immutable location and value emitted while walking a Diff tree.
|
|
6
|
+
class TraversalEntry
|
|
7
|
+
CONTEXTS = %i[change included_state].freeze
|
|
8
|
+
STATES = %i[before after].freeze
|
|
9
|
+
private_constant :CONTEXTS, :STATES
|
|
10
|
+
|
|
11
|
+
attr_reader :kind #: Symbol
|
|
12
|
+
attr_reader :context #: traversal_context
|
|
13
|
+
attr_reader :association_path #: traversal_association_path
|
|
14
|
+
attr_reader :record_path #: traversal_record_path
|
|
15
|
+
attr_reader :association_kind #: Symbol?
|
|
16
|
+
attr_reader :state #: traversal_state?
|
|
17
|
+
attr_reader :attribute #: String?
|
|
18
|
+
attr_reader :value #: untyped
|
|
19
|
+
|
|
20
|
+
#: (kind: Symbol, context: traversal_context, ?association_path: traversal_association_path, ?record_path: traversal_record_path, ?association_kind: Symbol?, ?state: traversal_state?, ?attribute: String?, ?value: untyped) -> void
|
|
21
|
+
def initialize( # rubocop:disable Metrics/ParameterLists
|
|
22
|
+
kind:,
|
|
23
|
+
context:,
|
|
24
|
+
association_path: [],
|
|
25
|
+
record_path: [],
|
|
26
|
+
association_kind: nil,
|
|
27
|
+
state: nil,
|
|
28
|
+
attribute: nil,
|
|
29
|
+
value: nil
|
|
30
|
+
)
|
|
31
|
+
validate!(context, state)
|
|
32
|
+
@kind = kind
|
|
33
|
+
@context = context
|
|
34
|
+
@association_path = immutable_names(association_path)
|
|
35
|
+
@record_path = Support.immutable_copy(record_path)
|
|
36
|
+
@association_kind = association_kind
|
|
37
|
+
@state = state
|
|
38
|
+
@attribute = Support.immutable_copy(attribute&.to_s)
|
|
39
|
+
@value = Support.immutable_copy(value)
|
|
40
|
+
freeze
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
#: () -> bool
|
|
44
|
+
def change?
|
|
45
|
+
context == :change
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
#: () -> bool
|
|
49
|
+
def included_state?
|
|
50
|
+
context == :included_state
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
#: () -> String?
|
|
54
|
+
def association
|
|
55
|
+
association_path.last
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
#: () -> RecordReference?
|
|
59
|
+
def record
|
|
60
|
+
record_path.last
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
#: () -> Hash[Symbol, untyped]
|
|
64
|
+
def to_h
|
|
65
|
+
{
|
|
66
|
+
kind: kind,
|
|
67
|
+
context: context,
|
|
68
|
+
association_path: Support.serialize(association_path),
|
|
69
|
+
record_path: Support.serialize(record_path),
|
|
70
|
+
association_kind: association_kind,
|
|
71
|
+
state: state,
|
|
72
|
+
attribute: attribute,
|
|
73
|
+
value: Support.serialize(value)
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
#: (Symbol, Symbol?) -> void
|
|
80
|
+
def validate!(candidate_context, candidate_state)
|
|
81
|
+
unless CONTEXTS.include?(candidate_context)
|
|
82
|
+
raise ArgumentError, "unsupported traversal context: #{candidate_context.inspect}"
|
|
83
|
+
end
|
|
84
|
+
return if candidate_state.nil? || STATES.include?(candidate_state)
|
|
85
|
+
|
|
86
|
+
raise ArgumentError, "unsupported traversal state: #{candidate_state.inspect}"
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
#: (traversal_association_path) -> traversal_association_path
|
|
90
|
+
def immutable_names(names)
|
|
91
|
+
names.map { |name| Support.immutable_copy(name.to_s) }.freeze
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
data/lib/paper_trail_diff.rb
CHANGED
|
@@ -13,6 +13,11 @@ require_relative 'paper_trail_diff/association_discovery'
|
|
|
13
13
|
require_relative 'paper_trail_diff/diagnostics'
|
|
14
14
|
require_relative 'paper_trail_diff/snapshot'
|
|
15
15
|
require_relative 'paper_trail_diff/value_objects'
|
|
16
|
+
require_relative 'paper_trail_diff/traversal_entry'
|
|
17
|
+
require_relative 'paper_trail_diff/traversal_emitter'
|
|
18
|
+
require_relative 'paper_trail_diff/snapshot_traversal'
|
|
19
|
+
require_relative 'paper_trail_diff/association_diff_traversal'
|
|
20
|
+
require_relative 'paper_trail_diff/traversal'
|
|
16
21
|
require_relative 'paper_trail_diff/engine'
|
|
17
22
|
require_relative 'paper_trail_diff/historical_association_reifier'
|
|
18
23
|
require_relative 'paper_trail_diff/prepared_record_index'
|
|
@@ -27,8 +32,8 @@ require_relative 'paper_trail_diff/timeline_snapshot_provider'
|
|
|
27
32
|
require_relative 'paper_trail_diff/activity_event_snapshot_refresher'
|
|
28
33
|
require_relative 'paper_trail_diff/activity_root_snapshot_refresher'
|
|
29
34
|
require_relative 'paper_trail_diff/branch_snapshot_refresher'
|
|
30
|
-
require_relative 'paper_trail_diff/step'
|
|
31
35
|
require_relative 'paper_trail_diff/activity_boundary'
|
|
36
|
+
require_relative 'paper_trail_diff/step'
|
|
32
37
|
require_relative 'paper_trail_diff/analysis'
|
|
33
38
|
require_relative 'paper_trail_diff/version_range'
|
|
34
39
|
require_relative 'paper_trail_diff/timeline_builder'
|
|
@@ -50,6 +55,10 @@ require_relative 'paper_trail_diff/paper_trail_adapter'
|
|
|
50
55
|
# type identity = Array[untyped]
|
|
51
56
|
# type ignore_option = Array[String | Symbol] | Hash[String | Symbol, untyped]
|
|
52
57
|
# type reference_key = :type | :id | "type" | "id"
|
|
58
|
+
# type traversal_context = :change | :included_state
|
|
59
|
+
# type traversal_state = :before | :after
|
|
60
|
+
# type traversal_association_path = Array[String]
|
|
61
|
+
# type traversal_record_path = Array[RecordReference]
|
|
53
62
|
# end
|
|
54
63
|
|
|
55
64
|
# Structured version comparison for PaperTrail.
|
|
@@ -13,14 +13,26 @@ module PaperTrailDiff
|
|
|
13
13
|
|
|
14
14
|
attr_reader recorded_at: untyped
|
|
15
15
|
|
|
16
|
+
attr_reader event: String?
|
|
17
|
+
|
|
18
|
+
attr_reader whodunnit: untyped
|
|
19
|
+
|
|
20
|
+
attr_reader record: RecordReference
|
|
21
|
+
|
|
16
22
|
# : (untyped) -> ActivityBoundary
|
|
17
23
|
def self.from_version: (untyped) -> ActivityBoundary
|
|
18
24
|
|
|
19
25
|
# : (untyped, captured_at: untyped) -> ActivityBoundary
|
|
20
26
|
def self.current: (untyped, captured_at: untyped) -> ActivityBoundary
|
|
21
27
|
|
|
22
|
-
# : (kind: Symbol, version_id: untyped, item_type: untyped, item_id: untyped, recorded_at: untyped) -> void
|
|
23
|
-
def initialize: (kind: Symbol, version_id: untyped, item_type: untyped, item_id: untyped, recorded_at: untyped) -> void
|
|
28
|
+
# : (kind: Symbol, version_id: untyped, item_type: untyped, item_id: untyped, recorded_at: untyped, ?event: untyped, ?whodunnit: untyped) -> void
|
|
29
|
+
def initialize: (kind: Symbol, version_id: untyped, item_type: untyped, item_id: untyped, recorded_at: untyped, ?event: untyped, ?whodunnit: untyped) -> void
|
|
30
|
+
|
|
31
|
+
# : () -> bool
|
|
32
|
+
def version?: () -> bool
|
|
33
|
+
|
|
34
|
+
# : () -> bool
|
|
35
|
+
def current?: () -> bool
|
|
24
36
|
|
|
25
37
|
# : () -> Hash[Symbol, untyped]
|
|
26
38
|
def to_h: () -> Hash[Symbol, untyped]
|
|
@@ -37,6 +49,9 @@ module PaperTrailDiff
|
|
|
37
49
|
# : (from_boundary: ActivityBoundary, to_boundary: ActivityBoundary, diff: Diff) -> void
|
|
38
50
|
def initialize: (from_boundary: ActivityBoundary, to_boundary: ActivityBoundary, diff: Diff) -> void
|
|
39
51
|
|
|
52
|
+
# : () -> bool
|
|
53
|
+
def empty?: () -> bool
|
|
54
|
+
|
|
40
55
|
# : () -> Hash[Symbol, untyped]
|
|
41
56
|
def to_h: () -> Hash[Symbol, untyped]
|
|
42
57
|
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Generated from lib/paper_trail_diff/association_diff_traversal.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module PaperTrailDiff
|
|
4
|
+
# Walks nested singular and collection association differences.
|
|
5
|
+
class AssociationDiffTraversal < TraversalEmitter
|
|
6
|
+
# : (^(TraversalEntry) -> void) -> void
|
|
7
|
+
def initialize: (^(TraversalEntry) -> void) -> void
|
|
8
|
+
|
|
9
|
+
# : (association_diffs, association_path: traversal_association_path, record_path: traversal_record_path) -> void
|
|
10
|
+
def call: (association_diffs, association_path: traversal_association_path, record_path: traversal_record_path) -> void
|
|
11
|
+
|
|
12
|
+
# : (Hash[String, ValueChange], association_path: traversal_association_path, record_path: traversal_record_path, association_kind: Symbol?) -> void
|
|
13
|
+
def attributes: (Hash[String, ValueChange], association_path: traversal_association_path, record_path: traversal_record_path, association_kind: Symbol?) -> void
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
@snapshots: SnapshotTraversal
|
|
18
|
+
|
|
19
|
+
# : (association_diff, traversal_association_path, traversal_record_path) -> void
|
|
20
|
+
def walk_association: (association_diff, traversal_association_path, traversal_record_path) -> void
|
|
21
|
+
|
|
22
|
+
# : (String, ValueChange, traversal_association_path, traversal_record_path, Symbol?) -> void
|
|
23
|
+
def emit_attribute: (String, ValueChange, traversal_association_path, traversal_record_path, Symbol?) -> void
|
|
24
|
+
|
|
25
|
+
# : (CollectionAssociationDiff, traversal_association_path, traversal_record_path) -> void
|
|
26
|
+
def walk_collection: (CollectionAssociationDiff, traversal_association_path, traversal_record_path) -> void
|
|
27
|
+
|
|
28
|
+
# : (Array[RecordSnapshot], Symbol, traversal_state, CollectionAssociationDiff, traversal_association_path, traversal_record_path) -> void
|
|
29
|
+
def walk_memberships: (Array[RecordSnapshot], Symbol, traversal_state, CollectionAssociationDiff, traversal_association_path, traversal_record_path) -> void
|
|
30
|
+
|
|
31
|
+
# : (RecordSnapshot, Symbol, traversal_state, CollectionAssociationDiff, traversal_association_path, traversal_record_path) -> void
|
|
32
|
+
def walk_membership: (RecordSnapshot, Symbol, traversal_state, CollectionAssociationDiff, traversal_association_path, traversal_record_path) -> void
|
|
33
|
+
|
|
34
|
+
# : (RecordSnapshot, Symbol, traversal_state, CollectionAssociationDiff, traversal_association_path, traversal_record_path) -> void
|
|
35
|
+
def emit_membership: (RecordSnapshot, Symbol, traversal_state, CollectionAssociationDiff, traversal_association_path, traversal_record_path) -> void
|
|
36
|
+
|
|
37
|
+
# : (ToOneAssociationDiff, traversal_association_path, traversal_record_path) -> void
|
|
38
|
+
def walk_to_one: (ToOneAssociationDiff, traversal_association_path, traversal_record_path) -> void
|
|
39
|
+
|
|
40
|
+
# : (ValueChange, Symbol, traversal_association_path, traversal_record_path) -> void
|
|
41
|
+
def walk_relationship: (ValueChange, Symbol, traversal_association_path, traversal_record_path) -> void
|
|
42
|
+
|
|
43
|
+
# : (ValueChange, Symbol, traversal_association_path, traversal_record_path) -> void
|
|
44
|
+
def emit_relationship: (ValueChange, Symbol, traversal_association_path, traversal_record_path) -> void
|
|
45
|
+
|
|
46
|
+
# : (RecordSnapshot?, traversal_state, Symbol, traversal_association_path, traversal_record_path) -> void
|
|
47
|
+
def walk_related: (RecordSnapshot?, traversal_state, Symbol, traversal_association_path, traversal_record_path) -> void
|
|
48
|
+
|
|
49
|
+
# : (ValueChange) -> Symbol
|
|
50
|
+
def relationship_kind: (ValueChange) -> Symbol
|
|
51
|
+
|
|
52
|
+
# : (RecordChange, Symbol, traversal_association_path, traversal_record_path) -> void
|
|
53
|
+
def walk_record_change: (RecordChange, Symbol, traversal_association_path, traversal_record_path) -> void
|
|
54
|
+
|
|
55
|
+
# : (RecordChange, Symbol, traversal_association_path, traversal_record_path) -> void
|
|
56
|
+
def emit_record_change: (RecordChange, Symbol, traversal_association_path, traversal_record_path) -> void
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Generated from lib/paper_trail_diff/snapshot_traversal.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module PaperTrailDiff
|
|
4
|
+
# Walks nested state included in an added, removed, or replaced record snapshot.
|
|
5
|
+
class SnapshotTraversal < TraversalEmitter
|
|
6
|
+
# : (RecordSnapshot, association_path: traversal_association_path, record_path: traversal_record_path, state: traversal_state, ?association_kind: Symbol?, ?include_record: bool) -> void
|
|
7
|
+
def call: (RecordSnapshot, association_path: traversal_association_path, record_path: traversal_record_path, state: traversal_state, ?association_kind: Symbol?, ?include_record: bool) -> void
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# : (RecordSnapshot, traversal_association_path, traversal_record_path, traversal_state, Symbol?) -> void
|
|
12
|
+
def emit_record: (RecordSnapshot, traversal_association_path, traversal_record_path, traversal_state, Symbol?) -> void
|
|
13
|
+
|
|
14
|
+
# : (RecordSnapshot, traversal_association_path, traversal_record_path, traversal_state, Symbol?) -> void
|
|
15
|
+
def emit_attributes: (RecordSnapshot, traversal_association_path, traversal_record_path, traversal_state, Symbol?) -> void
|
|
16
|
+
|
|
17
|
+
# : (String, untyped, traversal_association_path, traversal_record_path, traversal_state, Symbol?) -> void
|
|
18
|
+
def emit_attribute: (String, untyped, traversal_association_path, traversal_record_path, traversal_state, Symbol?) -> void
|
|
19
|
+
|
|
20
|
+
# : (RecordSnapshot, traversal_association_path, traversal_record_path, traversal_state) -> void
|
|
21
|
+
def emit_associations: (RecordSnapshot, traversal_association_path, traversal_record_path, traversal_state) -> void
|
|
22
|
+
|
|
23
|
+
# : (AssociationSnapshot, traversal_association_path, traversal_record_path, traversal_state) -> void
|
|
24
|
+
def emit_association: (AssociationSnapshot, traversal_association_path, traversal_record_path, traversal_state) -> void
|
|
25
|
+
|
|
26
|
+
# : (AssociationSnapshot, traversal_association_path, traversal_record_path, traversal_state) -> void
|
|
27
|
+
def emit_association_records: (AssociationSnapshot, traversal_association_path, traversal_record_path, traversal_state) -> void
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -7,11 +7,18 @@ module PaperTrailDiff
|
|
|
7
7
|
|
|
8
8
|
attr_reader to_version: untyped
|
|
9
9
|
|
|
10
|
+
attr_reader from_boundary: ActivityBoundary
|
|
11
|
+
|
|
12
|
+
attr_reader to_boundary: ActivityBoundary
|
|
13
|
+
|
|
10
14
|
attr_reader diff: Diff
|
|
11
15
|
|
|
12
16
|
# : (from_version: untyped, to_version: untyped, diff: Diff) -> void
|
|
13
17
|
def initialize: (from_version: untyped, to_version: untyped, diff: Diff) -> void
|
|
14
18
|
|
|
19
|
+
# : () -> bool
|
|
20
|
+
def empty?: () -> bool
|
|
21
|
+
|
|
15
22
|
# : () -> Hash[Symbol, untyped]
|
|
16
23
|
def to_h: () -> Hash[Symbol, untyped]
|
|
17
24
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Generated from lib/paper_trail_diff/traversal.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module PaperTrailDiff
|
|
4
|
+
# Coordinates root lifecycle, scalar, and association traversal.
|
|
5
|
+
class DiffTraversal < TraversalEmitter
|
|
6
|
+
# : (Diff, ^(TraversalEntry) -> void) -> void
|
|
7
|
+
def initialize: (Diff, ^(TraversalEntry) -> void) -> void
|
|
8
|
+
|
|
9
|
+
# : () -> void
|
|
10
|
+
def call: () -> void
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
@associations: AssociationDiffTraversal
|
|
15
|
+
|
|
16
|
+
@diff: Diff
|
|
17
|
+
|
|
18
|
+
@snapshots: SnapshotTraversal
|
|
19
|
+
|
|
20
|
+
# : () -> void
|
|
21
|
+
def walk_presence_change: () -> void
|
|
22
|
+
|
|
23
|
+
# : (RecordSnapshot?, traversal_state) -> void
|
|
24
|
+
def walk_presence_snapshot: (RecordSnapshot?, traversal_state) -> void
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# The complete structured difference between two normalized endpoints.
|
|
28
|
+
class Diff
|
|
29
|
+
# Walks semantic changes and the nested state carried by added or removed records.
|
|
30
|
+
# @rbs () { (TraversalEntry) -> void } -> Diff
|
|
31
|
+
# | () -> Enumerator[TraversalEntry, Diff]
|
|
32
|
+
def each_entry: () { (TraversalEntry) -> void } -> Diff
|
|
33
|
+
| () -> Enumerator[TraversalEntry, Diff]
|
|
34
|
+
|
|
35
|
+
# Walks only semantic changes, excluding snapshot state included for context.
|
|
36
|
+
# @rbs () { (TraversalEntry) -> void } -> Diff
|
|
37
|
+
# | () -> Enumerator[TraversalEntry, Diff]
|
|
38
|
+
def each_change: () { (TraversalEntry) -> void } -> Diff
|
|
39
|
+
| () -> Enumerator[TraversalEntry, Diff]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Generated from lib/paper_trail_diff/traversal_emitter.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module PaperTrailDiff
|
|
4
|
+
# Shared entry construction for internal traversal collaborators.
|
|
5
|
+
class TraversalEmitter
|
|
6
|
+
# : (^(TraversalEntry) -> void) -> void
|
|
7
|
+
def initialize: (^(TraversalEntry) -> void) -> void
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
@receiver: ^(TraversalEntry) -> void
|
|
12
|
+
|
|
13
|
+
# : (kind: Symbol, context: traversal_context, association_path: traversal_association_path, record_path: traversal_record_path, value: untyped, ?association_kind: Symbol?, ?state: traversal_state?, ?attribute: String?) -> void
|
|
14
|
+
def emit: (kind: Symbol, context: traversal_context, association_path: traversal_association_path, record_path: traversal_record_path, value: untyped, ?association_kind: Symbol?, ?state: traversal_state?, ?attribute: String?) -> void
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Generated from lib/paper_trail_diff/traversal_entry.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module PaperTrailDiff
|
|
4
|
+
# One immutable location and value emitted while walking a Diff tree.
|
|
5
|
+
class TraversalEntry
|
|
6
|
+
CONTEXTS: untyped
|
|
7
|
+
|
|
8
|
+
STATES: untyped
|
|
9
|
+
|
|
10
|
+
attr_reader kind: Symbol
|
|
11
|
+
|
|
12
|
+
attr_reader context: traversal_context
|
|
13
|
+
|
|
14
|
+
attr_reader association_path: traversal_association_path
|
|
15
|
+
|
|
16
|
+
attr_reader record_path: traversal_record_path
|
|
17
|
+
|
|
18
|
+
attr_reader association_kind: Symbol?
|
|
19
|
+
|
|
20
|
+
attr_reader state: traversal_state?
|
|
21
|
+
|
|
22
|
+
attr_reader attribute: String?
|
|
23
|
+
|
|
24
|
+
attr_reader value: untyped
|
|
25
|
+
|
|
26
|
+
# : (kind: Symbol, context: traversal_context, ?association_path: traversal_association_path, ?record_path: traversal_record_path, ?association_kind: Symbol?, ?state: traversal_state?, ?attribute: String?, ?value: untyped) -> void
|
|
27
|
+
def initialize: (kind: Symbol, context: traversal_context, ?association_path: traversal_association_path, ?record_path: traversal_record_path, ?association_kind: Symbol?, ?state: traversal_state?, ?attribute: String?, ?value: untyped) -> void
|
|
28
|
+
|
|
29
|
+
# : () -> bool
|
|
30
|
+
def change?: () -> bool
|
|
31
|
+
|
|
32
|
+
# : () -> bool
|
|
33
|
+
def included_state?: () -> bool
|
|
34
|
+
|
|
35
|
+
# : () -> String?
|
|
36
|
+
def association: () -> String?
|
|
37
|
+
|
|
38
|
+
# : () -> RecordReference?
|
|
39
|
+
def record: () -> RecordReference?
|
|
40
|
+
|
|
41
|
+
# : () -> Hash[Symbol, untyped]
|
|
42
|
+
def to_h: () -> Hash[Symbol, untyped]
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
# : (Symbol, Symbol?) -> void
|
|
47
|
+
def validate!: (Symbol, Symbol?) -> void
|
|
48
|
+
|
|
49
|
+
# : (traversal_association_path) -> traversal_association_path
|
|
50
|
+
def immutable_names: (traversal_association_path) -> traversal_association_path
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -53,4 +53,12 @@ module PaperTrailDiff
|
|
|
53
53
|
type ignore_option = Array[String | Symbol] | Hash[String | Symbol, untyped]
|
|
54
54
|
|
|
55
55
|
type reference_key = :type | :id | "type" | "id"
|
|
56
|
+
|
|
57
|
+
type traversal_context = :change | :included_state
|
|
58
|
+
|
|
59
|
+
type traversal_state = :before | :after
|
|
60
|
+
|
|
61
|
+
type traversal_association_path = Array[String]
|
|
62
|
+
|
|
63
|
+
type traversal_record_path = Array[RecordReference]
|
|
56
64
|
end
|