Class: PaperTrailDiff::ActivityTimelineBuilder
- Inherits:
-
Object
- Object
- PaperTrailDiff::ActivityTimelineBuilder
- Includes:
- ActivityGrouping
- Defined in:
- lib/paper_trail_diff/activity_timeline_builder.rb,
sig/generated/paper_trail_diff/activity_timeline_builder.rbs
Overview
Compares adjacent root and selected-descendant activity boundaries.
Instance Method Summary collapse
-
#activity_steps(history, events, final_boundary, final_snapshot) ⇒ Array[ActivityStep]
Appends the transition into an explicit closing boundary, which is either a requested current record or the absence a final root destroy leaves.
-
#analyze ⇒ Analysis
Builds all three version-bounded views from one activity snapshot pass.
-
#build ⇒ Array[ActivityStep]
: () -> Array.
-
#build_analysis(plan, events, history) ⇒ Analysis
Only the activity view gains the closing removal.
-
#build_between_versions ⇒ Array[ActivityStep]
Every boundary in the span, filtered out or not.
- #build_event_steps(root_versions, events, current: nil, final_boundary: nil, final_snapshot: nil) ⇒ Array[ActivityStep]
-
#build_to_current ⇒ Array[ActivityStep]
: () -> Array.
-
#capture_current ⇒ [ RecordSnapshot?, untyped ]
: () -> [RecordSnapshot?, untyped].
- #collect_events(root_versions, range_start: root_versions.first, range_end: root_versions.last) ⇒ Array[ActivityEvent]
-
#destroyed_boundary(root_versions) ⇒ ActivityBoundary?
A destroyed root has no later version, but its own event states that nothing follows it, so the removal can still close the timeline.
- #event_history(root_versions, events, current: nil) ⇒ ActivityHistory
-
#initialize(record, range:, tree:, snapshotter:, snapshots: false, group: nil) ⇒ ActivityTimelineBuilder
constructor
: (untyped, range: TimelineRange, tree: AssociationTree, snapshotter: untyped, ?snapshots: bool, ?group: Symbol?) -> void.
-
#no_steps ⇒ Array[ActivityStep]
: () -> Array.
-
#prepare_history(root_versions, end_at: nil) ⇒ void
: (Array, ?end_at: untyped) -> void.
-
#time_builder ⇒ TimeActivityTimelineBuilder
: () -> TimeActivityTimelineBuilder.
-
#validate_current_range! ⇒ void
: () -> void.
Methods included from ActivityGrouping
Constructor Details
#initialize(record, range:, tree:, snapshotter:, snapshots: false, group: nil) ⇒ ActivityTimelineBuilder
: (untyped, range: TimelineRange, tree: AssociationTree, snapshotter: untyped, ?snapshots: bool, ?group: Symbol?) -> void
10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 10 def initialize(record, range:, tree:, snapshotter:, snapshots: false, group: nil) # rubocop:disable Metrics/ParameterLists @snapshots = snapshots @group = group # Merging a group compares its outer states, so the snapshots must survive # the build even when the caller did not ask to keep them. @retain = snapshots || grouping? @record = record @from = range.from @to = range.to @range = range @tree = tree @snapshotter = snapshotter end |
Instance Method Details
#activity_steps(history, events, final_boundary, final_snapshot) ⇒ Array[ActivityStep]
156 157 158 159 160 161 162 163 164 165 166 167 168 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 156 def activity_steps(history, events, final_boundary, final_snapshot) steps = history.steps.dup previous_event = events.last previous_boundary = ActivityBoundary.from_version(previous_event.version) if previous_event if final_boundary && previous_boundary steps << ActivityStep.between( from_boundary: previous_boundary, to_boundary: final_boundary, from_snapshot: history.last_snapshot, to_snapshot: final_snapshot, retain: @retain ) end group_steps(steps).freeze end |
#analyze ⇒ Analysis
Builds all three version-bounded views from one activity snapshot pass. : () -> Analysis
36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 36 def analyze return time_builder.analyze if @range.time? return Analysis.empty if @range.unresolved? unless Endpoint.version?(@to) raise InvalidTimelineRangeError, '`to` must be a root PaperTrail version' end plan = @range.select_plan root_versions = plan.reconstruction_versions prepare_history(root_versions) events = collect_events(root_versions) build_analysis(plan, events, event_history(root_versions, events)) end |
#build ⇒ Array[ActivityStep]
: () -> Array
25 26 27 28 29 30 31 32 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 25 def build return time_builder.build if @range.time? return no_steps if @range.unresolved? return build_to_current if Endpoint.record?(@to) Endpoint.validate!(@to) build_between_versions end |
#build_analysis(plan, events, history) ⇒ Analysis
Only the activity view gains the closing removal. The endpoint diff and
the root timeline keep their compare and timeline semantics, under
which the state at a destroy version is the state before the deletion.
: (RootVersionPlan, Array, ActivityHistory) -> Analysis
195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 195 def build_analysis(plan, events, history) Analysis.new( diff: Engine.compare(history.first_snapshot, history.last_snapshot), timeline: ActivityRootSteps.call(plan, history.root_snapshots), activity_timeline: activity_steps( history, events, destroyed_boundary(plan.reconstruction_versions), nil ), from_snapshot: history.first_snapshot, to_snapshot: history.last_snapshot ) end |
#build_between_versions ⇒ Array[ActivityStep]
Every boundary in the span, filtered out or not. A filter narrows where the span starts and ends, but the sequence inside it stays complete: dropping boundaries would fold the changes they carried into a neighbouring step and credit them to whoever made that one. : () -> Array
72 73 74 75 76 77 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 72 def build_between_versions root_versions = @range.select_plan.reconstruction_versions prepare_history(root_versions) events = collect_events(root_versions) build_event_steps(root_versions, events) end |
#build_event_steps(root_versions, events, current: nil, final_boundary: nil, final_snapshot: nil) ⇒ Array[ActivityStep]
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 137 def build_event_steps( root_versions, events, current: nil, final_boundary: nil, final_snapshot: nil ) history = event_history(root_versions, events, current: current) activity_steps( history, events, final_boundary || destroyed_boundary(root_versions), final_snapshot ) end |
#build_to_current ⇒ Array[ActivityStep]
: () -> Array
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 80 def build_to_current validate_current_range! current_snapshot, captured_at = capture_current root_versions = VersionRange.new(@record, from: @from, to: @from).select_through_latest # Descendants can move after the last root version, so the prepared range # ends at the captured instant rather than at that version. prepare_history(root_versions, end_at: captured_at) events = collect_events(root_versions, range_end: captured_at) build_event_steps( root_versions, events, current: @to, final_boundary: ActivityBoundary.current(@to, captured_at: captured_at), final_snapshot: current_snapshot ) end |
#capture_current ⇒ [ RecordSnapshot?, untyped ]
: () -> [RecordSnapshot?, untyped]
98 99 100 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 98 def capture_current [@snapshotter.call(@to, @to), Time.now.utc] end |
#collect_events(root_versions, range_start: root_versions.first, range_end: root_versions.last) ⇒ Array[ActivityEvent]
113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 113 def collect_events( root_versions, range_start: root_versions.first, range_end: root_versions.last ) ActivityVersionCollector.new( @record, root_versions: root_versions, tree: @tree, traversal: AssociationTraversal.new(@tree), range_start: range_start, range_end: range_end ).call end |
#destroyed_boundary(root_versions) ⇒ ActivityBoundary?
A destroyed root has no later version, but its own event states that nothing follows it, so the removal can still close the timeline. : (Array) -> ActivityBoundary?
173 174 175 176 177 178 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 173 def destroyed_boundary(root_versions) version = root_versions.last return unless version && version.event.to_s == 'destroy' ActivityBoundary.destroyed(version) end |
#event_history(root_versions, events, current: nil) ⇒ ActivityHistory
181 182 183 184 185 186 187 188 189 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 181 def event_history(root_versions, events, current: nil) ActivityHistoryBuilder.new( root_versions, events, @snapshotter, current: current, snapshots: @retain ).call end |
#no_steps ⇒ Array[ActivityStep]
: () -> Array
62 63 64 65 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 62 def no_steps steps = [] #: Array[ActivityStep] steps.freeze end |
#prepare_history(root_versions, end_at: nil) ⇒ void
This method returns an undefined value.
: (Array, ?end_at: untyped) -> void
129 130 131 132 133 134 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 129 def prepare_history(root_versions, end_at: nil) return unless @snapshotter.respond_to?(:prepare) return @snapshotter.prepare(@record, root_versions) unless end_at @snapshotter.prepare(@record, root_versions, end_at: end_at) end |
#time_builder ⇒ TimeActivityTimelineBuilder
: () -> TimeActivityTimelineBuilder
208 209 210 211 212 213 214 215 216 217 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 208 def time_builder TimeActivityTimelineBuilder.new( @record, range: @range, tree: @tree, snapshotter: @snapshotter, snapshots: @snapshots, group: @group ) end |
#validate_current_range! ⇒ void
This method returns an undefined value.
: () -> void
103 104 105 106 107 108 109 110 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 103 def validate_current_range! unless Endpoint.version?(@from) raise InvalidTimelineRangeError, '`from` must be a root PaperTrail version' end Endpoint.validate_pair!(@from, @to) Endpoint.validate_pair!(@record, @to) end |