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, ArrayChange, 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
['updated_at'].freeze
- SUPPORTED_ASSOCIATION_MACROS =
%i[ belongs_to has_one has_many has_and_belongs_to_many ].freeze
- VERSION =
'0.12.0'
Class Method Summary collapse
-
.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.
-
.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.
-
.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.
-
.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.
-
.association_paths(model_or_record, max_depth: 1) ⇒ Array[AssociationDescriptor]
Discovers supported, finite association paths for a model or record.
-
.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.
-
.compare_many(comparisons, associations: [], ignore: DEFAULT_IGNORED_ATTRIBUTES, reload_live_endpoints: true) ⇒ comparison_results
Compares many independent endpoint pairs while batching current-record loading.
-
.diagnose(from_version, to_version, associations: []) ⇒ DiagnosticReport
Reports known reconstruction hazards without mutating application state.
-
.nested_changes(change, to_value = nil) ⇒ nested_changes
Looks inside an attribute the database stores whole, such as a JSON or jsonb column, and reports which keys changed.
-
.supported_association_macros ⇒ Array[Symbol]
Returns the association macros this release can normalize.
-
.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.
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
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 207 208 |
# File 'lib/paper_trail_diff.rb', line 181 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
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/paper_trail_diff.rb', line 212 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)
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/paper_trail_diff.rb', line 248 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
297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 |
# File 'lib/paper_trail_diff.rb', line 297 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
321 322 323 |
# File 'lib/paper_trail_diff.rb', line 321 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
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/paper_trail_diff.rb', line 123 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
142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/paper_trail_diff.rb', line 142 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
327 328 329 |
# File 'lib/paper_trail_diff.rb', line 327 def diagnose(from_version, to_version, associations: []) HistoryDiagnostics.new(from_version, to_version, associations: associations).call end |
.nested_changes(change, to_value = nil) ⇒ nested_changes
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) -> nested_changes
350 351 352 353 354 355 356 |
# File 'lib/paper_trail_diff.rb', line 350 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_macros ⇒ Array[Symbol]
Returns the association macros this release can normalize. : () -> Array
315 316 317 |
# File 'lib/paper_trail_diff.rb', line 315 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
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/paper_trail_diff.rb', line 157 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 |