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
['updated_at'].freeze
- SUPPORTED_ASSOCIATION_MACROS =
%i[ belongs_to has_one has_many has_and_belongs_to_many ].freeze
- VERSION =
'0.11.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) ⇒ Hash[Array[String], ValueChange]
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
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
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)
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
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
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
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
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
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]
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_macros ⇒ Array[Symbol]
Returns the association macros this release can normalize. : () -> Array
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
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 |