Class: PaperTrailDiff::ActivityTimelineBuilder
- Inherits:
-
Object
- Object
- PaperTrailDiff::ActivityTimelineBuilder
- 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) ⇒ ActivityTimelineBuilder
constructor
: (untyped, range: TimelineRange, tree: AssociationTree, snapshotter: untyped, ?snapshots: bool) -> 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.
Constructor Details
#initialize(record, range:, tree:, snapshotter:, snapshots: false) ⇒ ActivityTimelineBuilder
: (untyped, range: TimelineRange, tree: AssociationTree, snapshotter: untyped, ?snapshots: bool) -> void
8 9 10 11 12 13 14 15 16 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 8 def initialize(record, range:, tree:, snapshotter:, snapshots: false) @snapshots = snapshots @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]
150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 150 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: @snapshots ) end steps.freeze end |
#analyze ⇒ Analysis
Builds all three version-bounded views from one activity snapshot pass. : () -> Analysis
30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 30 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
19 20 21 22 23 24 25 26 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 19 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
189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 189 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
66 67 68 69 70 71 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 66 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]
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 131 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
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 74 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]
92 93 94 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 92 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]
107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 107 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?
167 168 169 170 171 172 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 167 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
175 176 177 178 179 180 181 182 183 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 175 def event_history(root_versions, events, current: nil) ActivityHistoryBuilder.new( root_versions, events, @snapshotter, current: current, snapshots: @snapshots ).call end |
#no_steps ⇒ Array[ActivityStep]
: () -> Array
56 57 58 59 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 56 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
123 124 125 126 127 128 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 123 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
202 203 204 205 206 207 208 209 210 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 202 def time_builder TimeActivityTimelineBuilder.new( @record, range: @range, tree: @tree, snapshotter: @snapshotter, snapshots: @snapshots ) end |
#validate_current_range! ⇒ void
This method returns an undefined value.
: () -> void
97 98 99 100 101 102 103 104 |
# File 'lib/paper_trail_diff/activity_timeline_builder.rb', line 97 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 |