Class: PaperTrailDiff::TimelineRange
- Inherits:
-
Object
- Object
- PaperTrailDiff::TimelineRange
- Defined in:
- lib/paper_trail_diff/timeline_range.rb,
sig/generated/paper_trail_diff/timeline_range.rbs
Overview
Chooses explicit-version or wall-clock selection for one timeline request.
Constant Summary collapse
- BOUNDARY_SYMBOLS =
%i[first last].freeze
Instance Attribute Summary collapse
- #from ⇒ Object readonly
- #time_range ⇒ TimeRange? readonly
- #to ⇒ Object readonly
Instance Method Summary collapse
-
#begin_time ⇒ Time?
: () -> Time?.
-
#build_time_range(within) ⇒ TimeRange?
: (untyped) -> TimeRange?.
-
#empty_versions ⇒ Array[untyped]
: () -> Array.
-
#include?(version) ⇒ Boolean
: (untyped) -> bool.
-
#initialize(record, from:, to:, within:, versions: nil, version_scope: nil, plan: nil, live_endpoint: nil) ⇒ TimelineRange
constructor
: (untyped, from: untyped, to: untyped, within: untyped, ?versions: Array?, ?version_scope: untyped, ?plan: RootVersionPlan?, ?live_endpoint: untyped) -> void.
-
#ordered_versions ⇒ Object
: () -> untyped.
-
#resolve(boundary) ⇒ Object
Resolving
:firstand:lasthere keeps callers from depending on the order PaperTrail happens to give its versions association, which a caller is also free to reorder. -
#select(context_required: false) ⇒ Array[untyped]
: (?context_required: bool) -> Array.
-
#select_plan(context_required: false) ⇒ RootVersionPlan
A batch may have selected these versions already, in which case reselecting them per record would undo the batching.
-
#symbolic?(boundary) ⇒ Boolean
: (untyped) -> bool.
-
#time? ⇒ Boolean
: () -> bool.
-
#unresolved? ⇒ Boolean
A record with no versions has no first or last boundary to resolve, which is an empty history rather than a bad request.
-
#validate_mode! ⇒ void
: () -> void.
-
#versions_relation ⇒ Object
: () -> untyped.
Constructor Details
#initialize(record, from:, to:, within:, versions: nil, version_scope: nil, plan: nil, live_endpoint: nil) ⇒ TimelineRange
: (untyped, from: untyped, to: untyped, within: untyped, ?versions: Array?, ?version_scope: untyped, ?plan: RootVersionPlan?, ?live_endpoint: untyped) -> void
14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 14 def initialize(record, from:, to:, within:, versions: nil, version_scope: nil, plan: nil, live_endpoint: nil) # rubocop:disable Metrics/ParameterLists, Layout/LineLength @record = record @plan = plan @live_endpoint = live_endpoint @versions = (plan ? plan.versions : versions)&.freeze @version_scope = version_scope @requested_from = from @requested_to = to @time_range = build_time_range(within) validate_mode! @from = resolve(from) @to = resolve(to) freeze end |
Instance Attribute Details
#from ⇒ Object (readonly)
9 10 11 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 9 def from @from end |
#time_range ⇒ TimeRange? (readonly)
11 12 13 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 11 def time_range @time_range end |
#to ⇒ Object (readonly)
10 11 12 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 10 def to @to end |
Instance Method Details
#begin_time ⇒ Time?
: () -> Time?
81 82 83 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 81 def begin_time time_range&.begin_time end |
#build_time_range(within) ⇒ TimeRange?
: (untyped) -> TimeRange?
143 144 145 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 143 def build_time_range(within) TimeRange.new(within) unless within.nil? end |
#empty_versions ⇒ Array[untyped]
: () -> Array
104 105 106 107 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 104 def empty_versions versions = [] #: Array[untyped] versions.freeze end |
#include?(version) ⇒ Boolean
: (untyped) -> bool
86 87 88 89 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 86 def include?(version) range = time_range !range || range.include?(version.created_at) end |
#ordered_versions ⇒ Object
: () -> untyped
130 131 132 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 130 def ordered_versions versions_relation.reorder(created_at: :asc, id: :asc) end |
#resolve(boundary) ⇒ Object
Resolving :first and :last here keeps callers from depending on the
order PaperTrail happens to give its versions association, which a caller
is also free to reorder.
: (untyped) -> untyped
118 119 120 121 122 123 124 125 126 127 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 118 def resolve(boundary) return boundary unless symbolic?(boundary) unless BOUNDARY_SYMBOLS.include?(boundary) raise InvalidTimelineRangeError, "unsupported boundary: #{boundary.inspect}; use :first, :last, a version, or a record" end boundary == :first ? ordered_versions.first : ordered_versions.last end |
#select(context_required: false) ⇒ Array[untyped]
: (?context_required: bool) -> Array
60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 60 def select(context_required: false) preselected = @versions return preselected if preselected range = time_range if range return TimeVersionRange.new( @record, time_range: range, version_scope: @version_scope ).select(context_required: context_required) end return empty_versions if unresolved? VersionRange.new(@record, from: @from, to: @to, version_scope: @version_scope).select end |
#select_plan(context_required: false) ⇒ RootVersionPlan
A batch may have selected these versions already, in which case reselecting them per record would undo the batching. The plan says which pairs of versions become steps, which a filter can make different from adjacent pairs of the selected versions. : (?context_required: bool) -> RootVersionPlan
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 41 def select_plan(context_required: false) preselected = @plan return preselected if preselected range = time_range if range return TimeVersionRange.new( @record, time_range: range, version_scope: @version_scope, live_endpoint: @live_endpoint ).select_plan(context_required: context_required) end return RootVersionPlan.empty if unresolved? VersionRange.new( @record, from: @from, to: @to, version_scope: @version_scope ).select_plan_for_range end |
#symbolic?(boundary) ⇒ Boolean
: (untyped) -> bool
110 111 112 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 110 def symbolic?(boundary) boundary.is_a?(Symbol) end |
#time? ⇒ Boolean
: () -> bool
76 77 78 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 76 def time? !time_range.nil? end |
#unresolved? ⇒ Boolean
A record with no versions has no first or last boundary to resolve, which is an empty history rather than a bad request. : () -> bool
32 33 34 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 32 def unresolved? (symbolic?(@requested_from) && @from.nil?) || (symbolic?(@requested_to) && @to.nil?) end |
#validate_mode! ⇒ void
This method returns an undefined value.
: () -> void
148 149 150 151 152 153 154 155 156 157 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 148 def validate_mode! if time? return if @requested_from.nil? && @requested_to.nil? raise InvalidTimelineRangeError, '`within` cannot be combined with `from` or `to`' end return unless @requested_from.nil? || @requested_to.nil? raise InvalidTimelineRangeError, 'provide both `from` and `to`, or provide `within`' end |
#versions_relation ⇒ Object
: () -> untyped
135 136 137 138 139 140 |
# File 'lib/paper_trail_diff/timeline_range.rb', line 135 def versions_relation @record.public_send(@record.class.versions_association_name) rescue NoMethodError => e = 'record does not expose a PaperTrail version history' raise InvalidTimelineRangeError, , cause: e end |