Module: PaperTrailDiff

Defined in:
lib/paper_trail_diff.rb,
lib/paper_trail_diff/step.rb,
lib/paper_trail_diff/engine.rb,
lib/paper_trail_diff/errors.rb,
lib/paper_trail_diff/support.rb,
lib/paper_trail_diff/version.rb,
lib/paper_trail_diff/analysis.rb,
lib/paper_trail_diff/endpoint.rb,
lib/paper_trail_diff/snapshot.rb,
lib/paper_trail_diff/traversal.rb,
lib/paper_trail_diff/time_range.rb,
lib/paper_trail_diff/diagnostics.rb,
lib/paper_trail_diff/configuration.rb,
lib/paper_trail_diff/value_objects.rb,
lib/paper_trail_diff/version_range.rb,
lib/paper_trail_diff/activity_event.rb,
lib/paper_trail_diff/activity_range.rb,
lib/paper_trail_diff/analysis_batch.rb,
lib/paper_trail_diff/timeline_range.rb,
lib/paper_trail_diff/instrumentation.rb,
lib/paper_trail_diff/scoped_analysis.rb,
lib/paper_trail_diff/traversal_entry.rb,
lib/paper_trail_diff/activity_history.rb,
lib/paper_trail_diff/comparison_batch.rb,
lib/paper_trail_diff/prepared_history.rb,
lib/paper_trail_diff/timeline_builder.rb,
lib/paper_trail_diff/activity_boundary.rb,
lib/paper_trail_diff/activity_grouping.rb,
lib/paper_trail_diff/nested_comparator.rb,
lib/paper_trail_diff/root_version_plan.rb,
lib/paper_trail_diff/traversal_emitter.rb,
lib/paper_trail_diff/snapshot_traversal.rb,
lib/paper_trail_diff/time_version_range.rb,
lib/paper_trail_diff/traversal_preparer.rb,
lib/paper_trail_diff/activity_root_steps.rb,
lib/paper_trail_diff/paper_trail_adapter.rb,
lib/paper_trail_diff/snapshot_normalizer.rb,
lib/paper_trail_diff/live_graph_collector.rb,
lib/paper_trail_diff/prepared_edge_loader.rb,
lib/paper_trail_diff/version_scope_filter.rb,
lib/paper_trail_diff/activity_relationship.rb,
lib/paper_trail_diff/association_discovery.rb,
lib/paper_trail_diff/association_traversal.rb,
lib/paper_trail_diff/batched_root_analyzer.rb,
lib/paper_trail_diff/batched_root_versions.rb,
lib/paper_trail_diff/collection_comparator.rb,
lib/paper_trail_diff/collection_transition.rb,
lib/paper_trail_diff/prepared_record_index.rb,
lib/paper_trail_diff/scoped_root_selection.rb,
lib/paper_trail_diff/live_endpoint_provider.rb,
lib/paper_trail_diff/root_version_selection.rb,
lib/paper_trail_diff/activity_snapshot_delta.rb,
lib/paper_trail_diff/batch_boundary_resolver.rb,
lib/paper_trail_diff/live_association_reader.rb,
lib/paper_trail_diff/prepared_history_loader.rb,
lib/paper_trail_diff/activity_timeline_builder.rb,
lib/paper_trail_diff/branch_snapshot_refresher.rb,
lib/paper_trail_diff/collection_identity_index.rb,
lib/paper_trail_diff/historical_snapshot_store.rb,
lib/paper_trail_diff/activity_snapshot_sequence.rb,
lib/paper_trail_diff/activity_version_collector.rb,
lib/paper_trail_diff/association_diff_traversal.rb,
lib/paper_trail_diff/live_endpoint_batch_loader.rb,
lib/paper_trail_diff/timeline_snapshot_provider.rb,
lib/paper_trail_diff/activity_event_route_finder.rb,
lib/paper_trail_diff/activity_transaction_grouper.rb,
lib/paper_trail_diff/prepared_association_reifier.rb,
lib/paper_trail_diff/version_sequence_diagnostics.rb,
lib/paper_trail_diff/activity_event_record_resolver.rb,
lib/paper_trail_diff/historical_association_reifier.rb,
lib/paper_trail_diff/time_activity_timeline_builder.rb,
lib/paper_trail_diff/activity_child_candidate_loader.rb,
lib/paper_trail_diff/preloaded_endpoint_batch_loader.rb,
lib/paper_trail_diff/activity_collection_route_change.rb,
lib/paper_trail_diff/activity_event_record_normalizer.rb,
lib/paper_trail_diff/activity_root_snapshot_refresher.rb,
lib/paper_trail_diff/activity_belongs_to_event_applier.rb,
lib/paper_trail_diff/activity_collection_event_applier.rb,
lib/paper_trail_diff/activity_collection_route_updater.rb,
lib/paper_trail_diff/activity_event_snapshot_refresher.rb,
lib/paper_trail_diff/activity_collection_record_updater.rb,
lib/paper_trail_diff/version_association_candidate_scope.rb,
sig/generated/paper_trail_diff.rbs,
sig/generated/paper_trail_diff.rbs,
sig/generated/paper_trail_diff/step.rbs,
sig/generated/paper_trail_diff/engine.rbs,
sig/generated/paper_trail_diff/errors.rbs,
sig/generated/paper_trail_diff/support.rbs,
sig/generated/paper_trail_diff/version.rbs,
sig/generated/paper_trail_diff/analysis.rbs,
sig/generated/paper_trail_diff/endpoint.rbs,
sig/generated/paper_trail_diff/snapshot.rbs,
sig/generated/paper_trail_diff/traversal.rbs,
sig/generated/paper_trail_diff/time_range.rbs,
sig/generated/paper_trail_diff/diagnostics.rbs,
sig/generated/paper_trail_diff/configuration.rbs,
sig/generated/paper_trail_diff/value_objects.rbs,
sig/generated/paper_trail_diff/version_range.rbs,
sig/generated/paper_trail_diff/activity_event.rbs,
sig/generated/paper_trail_diff/activity_range.rbs,
sig/generated/paper_trail_diff/analysis_batch.rbs,
sig/generated/paper_trail_diff/timeline_range.rbs,
sig/generated/paper_trail_diff/instrumentation.rbs,
sig/generated/paper_trail_diff/scoped_analysis.rbs,
sig/generated/paper_trail_diff/traversal_entry.rbs,
sig/generated/paper_trail_diff/activity_history.rbs,
sig/generated/paper_trail_diff/comparison_batch.rbs,
sig/generated/paper_trail_diff/prepared_history.rbs,
sig/generated/paper_trail_diff/timeline_builder.rbs,
sig/generated/paper_trail_diff/activity_boundary.rbs,
sig/generated/paper_trail_diff/activity_grouping.rbs,
sig/generated/paper_trail_diff/nested_comparator.rbs,
sig/generated/paper_trail_diff/root_version_plan.rbs,
sig/generated/paper_trail_diff/traversal_emitter.rbs,
sig/generated/paper_trail_diff/snapshot_traversal.rbs,
sig/generated/paper_trail_diff/time_version_range.rbs,
sig/generated/paper_trail_diff/traversal_preparer.rbs,
sig/generated/paper_trail_diff/activity_root_steps.rbs,
sig/generated/paper_trail_diff/paper_trail_adapter.rbs,
sig/generated/paper_trail_diff/snapshot_normalizer.rbs,
sig/generated/paper_trail_diff/live_graph_collector.rbs,
sig/generated/paper_trail_diff/prepared_edge_loader.rbs,
sig/generated/paper_trail_diff/version_scope_filter.rbs,
sig/generated/paper_trail_diff/activity_relationship.rbs,
sig/generated/paper_trail_diff/association_discovery.rbs,
sig/generated/paper_trail_diff/association_traversal.rbs,
sig/generated/paper_trail_diff/batched_root_analyzer.rbs,
sig/generated/paper_trail_diff/batched_root_versions.rbs,
sig/generated/paper_trail_diff/collection_comparator.rbs,
sig/generated/paper_trail_diff/collection_transition.rbs,
sig/generated/paper_trail_diff/prepared_record_index.rbs,
sig/generated/paper_trail_diff/scoped_root_selection.rbs,
sig/generated/paper_trail_diff/live_endpoint_provider.rbs,
sig/generated/paper_trail_diff/root_version_selection.rbs,
sig/generated/paper_trail_diff/activity_snapshot_delta.rbs,
sig/generated/paper_trail_diff/batch_boundary_resolver.rbs,
sig/generated/paper_trail_diff/live_association_reader.rbs,
sig/generated/paper_trail_diff/prepared_history_loader.rbs,
sig/generated/paper_trail_diff/activity_timeline_builder.rbs,
sig/generated/paper_trail_diff/branch_snapshot_refresher.rbs,
sig/generated/paper_trail_diff/collection_identity_index.rbs,
sig/generated/paper_trail_diff/historical_snapshot_store.rbs,
sig/generated/paper_trail_diff/activity_snapshot_sequence.rbs,
sig/generated/paper_trail_diff/activity_version_collector.rbs,
sig/generated/paper_trail_diff/association_diff_traversal.rbs,
sig/generated/paper_trail_diff/live_endpoint_batch_loader.rbs,
sig/generated/paper_trail_diff/timeline_snapshot_provider.rbs,
sig/generated/paper_trail_diff/activity_event_route_finder.rbs,
sig/generated/paper_trail_diff/activity_transaction_grouper.rbs,
sig/generated/paper_trail_diff/prepared_association_reifier.rbs,
sig/generated/paper_trail_diff/version_sequence_diagnostics.rbs,
sig/generated/paper_trail_diff/activity_event_record_resolver.rbs,
sig/generated/paper_trail_diff/historical_association_reifier.rbs,
sig/generated/paper_trail_diff/time_activity_timeline_builder.rbs,
sig/generated/paper_trail_diff/activity_child_candidate_loader.rbs,
sig/generated/paper_trail_diff/preloaded_endpoint_batch_loader.rbs,
sig/generated/paper_trail_diff/activity_collection_route_change.rbs,
sig/generated/paper_trail_diff/activity_event_record_normalizer.rbs,
sig/generated/paper_trail_diff/activity_root_snapshot_refresher.rbs,
sig/generated/paper_trail_diff/activity_belongs_to_event_applier.rbs,
sig/generated/paper_trail_diff/activity_collection_event_applier.rbs,
sig/generated/paper_trail_diff/activity_collection_route_updater.rbs,
sig/generated/paper_trail_diff/activity_event_snapshot_refresher.rbs,
sig/generated/paper_trail_diff/activity_collection_record_updater.rbs,
sig/generated/paper_trail_diff/version_association_candidate_scope.rbs

Overview

Structured version comparison for PaperTrail. Each method is a thin, documented entry point, so this reads as an API listing rather than logic.

Defined Under Namespace

Modules: ActivityGrouping, ActivityRootSteps, Endpoint, Instrumentation, Support Classes: ActivityBelongsToEventApplier, ActivityBoundary, ActivityChildCandidateLoader, ActivityCollectionEventApplier, ActivityCollectionRecordUpdater, ActivityCollectionRouteChange, ActivityCollectionRouteUpdater, ActivityEvent, ActivityEventRecordNormalizer, ActivityEventRecordResolver, ActivityEventRegistry, ActivityEventRouteFinder, ActivityEventSnapshotRefresher, ActivityHistory, ActivityHistoryBuilder, ActivityRange, ActivityRelationship, ActivityRootSnapshotRefresher, ActivitySnapshotDelta, ActivitySnapshotProvider, ActivitySnapshotSequence, ActivityStep, ActivityTimelineBuilder, ActivityTransactionGrouper, ActivityTransactionGroups, ActivityVersionCollector, AmbiguousVersionOrderError, Analysis, AnalysisBatch, AssociationDescriptor, AssociationDiscovery, AssociationSnapshot, AssociationTrackingUnavailableError, AssociationTraversal, AssociationTree, BatchBoundaryResolver, BatchLimitExceededError, BatchedRootAnalyzer, BatchedRootVersions, BranchSnapshotRefresher, CollectionAssociationDiff, CollectionComparator, CollectionIdentityIndex, CollectionTransition, ComparisonBatch, ConfigurationError, DiagnosticIssue, DiagnosticReport, Diff, Engine, Error, HistoricalAssociationReifier, HistoricalSnapshotStore, HistoryDiagnostics, IgnorePolicy, IncompleteAssociationHistoryError, IncompleteTimeRangeError, InvalidEndpointError, InvalidTimeRangeError, InvalidTimelineRangeError, LiveAssociationReader, LiveEndpointBatchLoader, LiveEndpointProvider, LiveGraphCollector, NestedComparator, PaperTrailAdapter, PreloadedEndpointBatchLoader, PreparedAssociationReifier, PreparedEdgeLoader, PreparedHistory, PreparedHistoryLoader, PreparedRecordIndex, PreparedRecordSeries, PreparedRecordState, PreparedVersionStateLoader, RecordChange, RecordReference, RecordSnapshot, ReversedEndpointsError, RootVersionPlan, RootVersionSelection, ScopedAnalysis, ScopedRootSelection, SnapshotNormalizer, SnapshotPool, Step, TimeActivityTimelineBuilder, TimeRange, TimeVersionRange, TimelineBuilder, TimelineRange, TimelineSnapshotProvider, ToOneAssociationDiff, TraversalEntry, TraversalPreparer, UnknownAssociationError, UnloadedAssociationError, UnsupportedAssociationError, UnsupportedLiveActivityError, UnversionedAssociationError, ValueChange, VersionAssociationCandidateScope, VersionMismatchError, VersionRange, VersionScopeFilter, VersionSequenceDiagnostics

Constant Summary collapse

DEFAULT_IGNORED_ATTRIBUTES =

rubocop:disable Metrics/ModuleLength

Returns:

  • (Object)
['updated_at'].freeze
SUPPORTED_ASSOCIATION_MACROS =

Returns:

  • (Object)
%i[
  belongs_to
  has_one
  has_many
  has_and_belongs_to_many
].freeze
VERSION =

Returns:

  • (::String)
'0.11.0'

Class Method Summary collapse

Class Method Details

.activity_timeline(record, from: nil, to: nil, within: nil, associations: [], ignore: DEFAULT_IGNORED_ATTRIBUTES, reload_live_endpoints: true, version_scope: nil, close_on: nil, snapshots: false, group: nil) ⇒ Array[ActivityStep]

Compares adjacent root and selected-descendant activity boundaries. reload_live_endpoints: applies only when to: is a current record; the other range forms never read live state. : (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?reload_live_endpoints: bool, ?version_scope: untyped, ?close_on: Symbol?, ?snapshots: bool) -> Array

Parameters:

  • (Object)
  • from: (Object) (defaults to: nil)
  • to: (Object) (defaults to: nil)
  • within: (Object) (defaults to: nil)
  • associations: (Array[String | Symbol]) (defaults to: [])
  • ignore: (ignore_option) (defaults to: DEFAULT_IGNORED_ATTRIBUTES)
  • reload_live_endpoints: (Boolean) (defaults to: true)
  • version_scope: (Object) (defaults to: nil)
  • close_on: (Symbol, nil) (defaults to: nil)
  • snapshots: (Boolean) (defaults to: false)

Returns:



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/paper_trail_diff.rb', line 179

def activity_timeline( # rubocop:disable Metrics/ParameterLists
  record,
  from: nil,
  to: nil,
  within: nil,
  associations: [],
  ignore: DEFAULT_IGNORED_ATTRIBUTES,
  reload_live_endpoints: true,
  version_scope: nil,
  close_on: nil,
  snapshots: false,
  group: nil
)
  PaperTrailAdapter.new(
    associations: associations,
    ignore: ignore,
    reload_live_endpoints: reload_live_endpoints
  ).activity_timeline(
    record,
    from: from,
    to: to,
    within: within,
    version_scope: version_scope,
    close_on: close_on,
    group: group,
    snapshots: snapshots
  )
end

.analyze(record, from: nil, to: nil, within: nil, associations: [], ignore: DEFAULT_IGNORED_ATTRIBUTES, activity: false, version_scope: nil, close_on: nil, snapshots: false, group: nil) ⇒ Analysis

Builds an endpoint diff and root-checkpoint timeline while normalizing each version once. : (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?, ?snapshots: bool, ?group: Symbol?) -> Analysis

Parameters:

  • (Object)
  • from: (Object) (defaults to: nil)
  • to: (Object) (defaults to: nil)
  • within: (Object) (defaults to: nil)
  • associations: (Array[String | Symbol]) (defaults to: [])
  • ignore: (ignore_option) (defaults to: DEFAULT_IGNORED_ATTRIBUTES)
  • activity: (Boolean) (defaults to: false)
  • version_scope: (Object) (defaults to: nil)
  • close_on: (Symbol, nil) (defaults to: nil)
  • snapshots: (Boolean) (defaults to: false)
  • group: (Symbol, nil) (defaults to: nil)

Returns:



210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/paper_trail_diff.rb', line 210

def analyze( # rubocop:disable Metrics/ParameterLists
  record,
  from: nil,
  to: nil,
  within: nil,
  associations: [],
  ignore: DEFAULT_IGNORED_ATTRIBUTES,
  activity: false,
  version_scope: nil,
  close_on: nil,
  snapshots: false,
  group: nil
)
  PaperTrailAdapter.new(associations: associations, ignore: ignore).analyze(
    record,
    from: from,
    to: to,
    within: within,
    activity: activity,
    version_scope: version_scope,
    close_on: close_on,
    snapshots: snapshots,
    group: group
  )
end

.analyze_many(records = nil, scope: nil, limit: nil, within: nil, associations: [], ignore: DEFAULT_IGNORED_ATTRIBUTES, activity: false, version_scope: nil, close_on: nil) ⇒ Hash[identity, Analysis], ScopedAnalysis

Analyzes many roots over one shared time window, preparing their selected history once for the batch instead of once per record. Roots with no versions in the window return an empty Analysis.

Pass records to analyze a list you assembled, which returns a Hash keyed by identity. Pass scope: with a limit: to have the roots selected for you from a relation, which returns a ScopedAnalysis -- the same Hash, plus the roots the relation could not reach. See analyze_scope for why that second collection exists. : (?Array?, ?scope: untyped, ?limit: Integer?, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?) -> (Hash[identity, Analysis] | ScopedAnalysis)

Parameters:

  • (Array[untyped], nil)
  • scope: (Object) (defaults to: nil)
  • limit: (Integer, nil) (defaults to: nil)
  • within: (Object) (defaults to: nil)
  • associations: (Array[String | Symbol]) (defaults to: [])
  • ignore: (ignore_option) (defaults to: DEFAULT_IGNORED_ATTRIBUTES)
  • activity: (Boolean) (defaults to: false)
  • version_scope: (Object) (defaults to: nil)
  • close_on: (Symbol, nil) (defaults to: nil)

Returns:



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/paper_trail_diff.rb', line 246

def analyze_many( # rubocop:disable Metrics/ParameterLists
  records = nil,
  scope: nil,
  limit: nil,
  within: nil,
  associations: [],
  ignore: DEFAULT_IGNORED_ATTRIBUTES,
  activity: false,
  version_scope: nil,
  close_on: nil
)
  adapter = PaperTrailAdapter.new(associations: associations, ignore: ignore)
  if scope
    raise ConfigurationError, 'pass either records or scope:, not both' unless records.nil?

    return adapter.analyze_scope(scope, limit: limit, within: within, activity: activity,
                                        version_scope: version_scope, close_on: close_on)
  end
  raise ConfigurationError, 'pass records or scope:' if records.nil?

  adapter.analyze_many(records, within: within, activity: activity,
                                version_scope: version_scope, close_on: close_on)
end

.analyze_scope(scope, limit:, within: nil, associations: [], ignore: DEFAULT_IGNORED_ATTRIBUTES, activity: false, version_scope: nil, close_on: nil) ⇒ ScopedAnalysis

Analyzes every root the relation reaches whose history moved inside the window, selecting them in a fixed number of queries rather than making the caller rediscover them.

limit: is required and exceeding it raises. Selection moves into the gem here, so the bound on how much work a page can ask for has to move with it, and a truncated audit report is worse than a refused one.

Returns a ScopedAnalysis, which destructures:

analyses, unreachable = PaperTrailDiff.analyze_scope(
Article.where(status: 'published'), within: july, limit: 500
)

unreachable names roots that changed in the window but have no live row left. A relation's conditions are evaluated against the live table, so a destroyed root cannot be tested against them at all -- its history is intact and the state it held at destruction may well have matched. Those roots are reported rather than dropped so that a page auditing deletions is told where to look instead of quietly coming up short.

Note also that a relation selects on current state, not on state during the window: where(status: 'published') means published now, which is a different set from what was published while the window was open. : (untyped, limit: Integer?, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?activity: bool, ?version_scope: untyped, ?close_on: Symbol?) -> ScopedAnalysis

Parameters:

  • (Object)
  • limit: (Integer, nil)
  • within: (Object) (defaults to: nil)
  • associations: (Array[String | Symbol]) (defaults to: [])
  • ignore: (ignore_option) (defaults to: DEFAULT_IGNORED_ATTRIBUTES)
  • activity: (Boolean) (defaults to: false)
  • version_scope: (Object) (defaults to: nil)
  • close_on: (Symbol, nil) (defaults to: nil)

Returns:



295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
# File 'lib/paper_trail_diff.rb', line 295

def analyze_scope( # rubocop:disable Metrics/ParameterLists
  scope,
  limit:,
  within: nil,
  associations: [],
  ignore: DEFAULT_IGNORED_ATTRIBUTES,
  activity: false,
  version_scope: nil,
  close_on: nil
)
  PaperTrailAdapter.new(associations: associations, ignore: ignore).analyze_scope(
    scope, limit: limit, within: within, activity: activity,
           version_scope: version_scope, close_on: close_on
  )
end

.association_paths(model_or_record, max_depth: 1) ⇒ Array[AssociationDescriptor]

Discovers supported, finite association paths for a model or record. : (untyped, ?max_depth: Integer) -> Array

Parameters:

  • (Object)
  • max_depth: (Integer) (defaults to: 1)

Returns:



319
320
321
# File 'lib/paper_trail_diff.rb', line 319

def association_paths(model_or_record, max_depth: 1)
  AssociationDiscovery.new(model_or_record, max_depth: max_depth).call
end

.compare(from_version, to_version, associations: [], ignore: DEFAULT_IGNORED_ATTRIBUTES, reload_live_endpoints: true) ⇒ Diff

Compares net state between explicit PaperTrail-version or current-record endpoints. : (untyped, untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?reload_live_endpoints: bool) -> Diff

Parameters:

  • (Object)
  • (Object)
  • associations: (Array[String | Symbol]) (defaults to: [])
  • ignore: (ignore_option) (defaults to: DEFAULT_IGNORED_ATTRIBUTES)
  • reload_live_endpoints: (Boolean) (defaults to: true)

Returns:



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/paper_trail_diff.rb', line 121

def compare(
  from_version,
  to_version,
  associations: [],
  ignore: DEFAULT_IGNORED_ATTRIBUTES,
  reload_live_endpoints: true
)
  PaperTrailAdapter.new(
    associations: associations,
    ignore: ignore,
    reload_live_endpoints: reload_live_endpoints
  ).compare(
    from_version,
    to_version
  )
end

.compare_many(comparisons, associations: [], ignore: DEFAULT_IGNORED_ATTRIBUTES, reload_live_endpoints: true) ⇒ comparison_results

Compares many independent endpoint pairs while batching current-record loading. : (Array, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?reload_live_endpoints: bool) -> comparison_results

Parameters:

  • (Array[comparison_input])
  • associations: (Array[String | Symbol]) (defaults to: [])
  • ignore: (ignore_option) (defaults to: DEFAULT_IGNORED_ATTRIBUTES)
  • reload_live_endpoints: (Boolean) (defaults to: true)

Returns:

  • (comparison_results)


140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/paper_trail_diff.rb', line 140

def compare_many(
  comparisons,
  associations: [],
  ignore: DEFAULT_IGNORED_ATTRIBUTES,
  reload_live_endpoints: true
)
  PaperTrailAdapter.new(
    associations: associations,
    ignore: ignore,
    reload_live_endpoints: reload_live_endpoints
  ).compare_many(comparisons)
end

.diagnose(from_version, to_version, associations: []) ⇒ DiagnosticReport

Reports known reconstruction hazards without mutating application state. : (untyped, untyped, ?associations: Array[String | Symbol]) -> DiagnosticReport

Parameters:

  • (Object)
  • (Object)
  • associations: (Array[String | Symbol]) (defaults to: [])

Returns:



325
326
327
# File 'lib/paper_trail_diff.rb', line 325

def diagnose(from_version, to_version, associations: [])
  HistoryDiagnostics.new(from_version, to_version, associations: associations).call
end

.nested_changes(change, to_value = nil) ⇒ Hash[Array[String], ValueChange]

Looks inside an attribute the database stores whole, such as a JSON or jsonb column, and reports which keys changed.

change = diff.attributes.fetch('config')
PaperTrailDiff.nested_changes(change)
# => { ['theme'] => <from "dark" to "light">,
#      ['limits', 'max'] => <from 10 to 20> }

Accepts the ValueChange an attribute diff already produced, or a bare pair. Returns an empty hash when the pair is not two readable structures, which is the honest answer: a column that held text on one side and JSON on the other changed wholesale, and the caller still has that change.

Paths are arrays because a JSON key may contain a dot. Arrays are reported whole rather than by index, since their elements carry no identity and a list that merely shifted would otherwise look changed throughout. A key that was absent reads as NestedComparator::ABSENT rather than nil, which JSON uses for a present null. : (untyped, ?untyped) -> Hash[Array[String], ValueChange]

Parameters:

  • (Object)
  • (Object)

Returns:



348
349
350
351
352
353
354
# File 'lib/paper_trail_diff.rb', line 348

def nested_changes(change, to_value = nil)
  # Tested by type rather than by responding to `from`: ActiveSupport gives
  # String#from, so duck-typing here quietly reads a plain string as a pair.
  return NestedComparator.call(change.from, change.to) if change.is_a?(ValueChange)

  NestedComparator.call(change, to_value)
end

.supported_association_macrosArray[Symbol]

Returns the association macros this release can normalize. : () -> Array

Returns:

  • (Array[Symbol])


313
314
315
# File 'lib/paper_trail_diff.rb', line 313

def supported_association_macros
  SUPPORTED_ASSOCIATION_MACROS
end

.timeline(record, from: nil, to: nil, within: nil, associations: [], ignore: DEFAULT_IGNORED_ATTRIBUTES, version_scope: nil, close_on: nil) ⇒ Array[Step]

Compares every adjacent reconstructed state in an inclusive version range. : (untyped, ?from: untyped, ?to: untyped, ?within: untyped, ?associations: Array[String | Symbol], ?ignore: ignore_option, ?version_scope: untyped, ?close_on: Symbol?) -> Array

Parameters:

  • (Object)
  • from: (Object) (defaults to: nil)
  • to: (Object) (defaults to: nil)
  • within: (Object) (defaults to: nil)
  • associations: (Array[String | Symbol]) (defaults to: [])
  • ignore: (ignore_option) (defaults to: DEFAULT_IGNORED_ATTRIBUTES)
  • version_scope: (Object) (defaults to: nil)
  • close_on: (Symbol, nil) (defaults to: nil)

Returns:



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/paper_trail_diff.rb', line 155

def timeline( # rubocop:disable Metrics/ParameterLists
  record,
  from: nil,
  to: nil,
  within: nil,
  associations: [],
  ignore: DEFAULT_IGNORED_ATTRIBUTES,
  version_scope: nil,
  close_on: nil
)
  PaperTrailAdapter.new(associations: associations, ignore: ignore).timeline(
    record,
    from: from,
    to: to,
    within: within,
    version_scope: version_scope,
    close_on: close_on
  )
end