whodunit 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 323bc72651528d7bf5e205c0388462078acc718ea39b14b5775517644a2115fc
4
- data.tar.gz: d20344c823d5716ae218497ca92f61f41c6660c8e8f27a5479b0e52bc64b6b25
3
+ metadata.gz: b118c7a04ca24e4cfd6aa759e57b5c92e51be74f87b35a89ae6e5654f3a56051
4
+ data.tar.gz: db5c8c236bd170f7ce42b14682c3c44c6eaaae2dc125b6c8e9cdf9ef7a9a9596
5
5
  SHA512:
6
- metadata.gz: f893afd5307dfa5cdabd58c8de25baa2e979809f9d2c810cdb5dd029a90ebb07f79a61ab24c149e9545159aafef09b3494e2fe15cdee93a6c66e1ae35c44bd2e
7
- data.tar.gz: 9df8c395516af0720e71fd2a5e8b03a3471f4a85684f8b8a7b274222f74a19feeb1bb9a2b5b3e4795fbcf8938aef769a87e1dd380668838198efad31215d4e3b
6
+ metadata.gz: 4324dc93c29055aaa6dcc02b1999484d8108a4212eb8474185d5c0dee47e6d99fc88ed938d344f17bf75747a2eb5023ef2d6295d5308d9c838fd9b2f00c349dd
7
+ data.tar.gz: 6f31152d504e0b80a81992c3f62f190ac9de4aba73d0a964e24c116052ea5093629b6182eff58d6c9f811c2b3bec95b5385f49ef45429cc8f11d66a6d190d988
data/.rubocop.yml CHANGED
@@ -6,7 +6,7 @@ plugins:
6
6
 
7
7
  AllCops:
8
8
  NewCops: enable
9
- TargetRubyVersion: 3.1
9
+ TargetRubyVersion: 3.2
10
10
  Exclude:
11
11
  - 'vendor/**/*'
12
12
  - 'tmp/**/*'
@@ -114,12 +114,12 @@ Metrics/AbcSize:
114
114
  - 'spec/**/*'
115
115
 
116
116
  Metrics/CyclomaticComplexity:
117
- Max: 8
117
+ Max: 10
118
118
  Exclude:
119
119
  - 'spec/**/*'
120
120
 
121
121
  Metrics/PerceivedComplexity:
122
- Max: 8
122
+ Max: 10
123
123
  Exclude:
124
124
  - 'spec/**/*'
125
125
  Gemspec/DevelopmentDependencies:
data/CHANGELOG.md CHANGED
@@ -5,7 +5,45 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [Unreleased]
8
+ ## [0.4.0] - 2025-05-20
9
+
10
+ ### Breaking Changes
11
+
12
+ - Dropped support for Ruby 3.1. Minimum supported Ruby version is now **3.2**.
13
+
14
+ ### Fixed
15
+
16
+ - `TableDefinitionExtension`: replaced `included { attr_accessor :_whodunit_stamps_added }` with
17
+ explicit reader/writer methods so the accessor is defined correctly when the module is **prepended**
18
+ (as the Railtie does) rather than included. Previously the accessor was silently missing in
19
+ production, causing `@_whodunit_stamps_added` to be inaccessible via the public API.
20
+
21
+ ### Changed
22
+
23
+ - **Test suite**: eliminated all hand-rolled ActiveRecord and Railtie mocks in favour of genuine
24
+ infrastructure — real `ActiveRecord::Base` subclasses backed by an in-memory SQLite3 database,
25
+ and real `ActiveRecord::ConnectionAdapters::TableDefinition` instances for migration-helper tests.
26
+ Callbacks, dirty tracking, `belongs_to` reflections, and `column_names` now go through actual AR
27
+ code paths rather than no-op stubs.
28
+ - `spec/support/rails_mocks.rb` — emptied; `activesupport` is a runtime dependency and needs no
29
+ re-implementation in tests.
30
+ - `spec/support/test_models.rb` — replaced `MockActiveRecord` stub class with real AR models
31
+ (`WhodunitRecord`, `WhodunitSoftDeleteRecord`) on an in-memory SQLite3 schema; backward-compat
32
+ aliases preserved.
33
+ - `spec/spec_helper.rb` — added `rescue Bundler::GemNotFound` guard on `require "bundler/setup"`
34
+ to allow running specs directly without `bundle exec`; wrapped every example in an AR transaction
35
+ that rolls back on completion; added missing config keys to `ORIGINAL_WHODUNIT_CONFIG`.
36
+ - `spec/whodunit/table_definition_extension_spec.rb` — now tests the real
37
+ `ActiveRecord::ConnectionAdapters::TableDefinition` with `TableDefinitionExtension` prepended,
38
+ rather than an anonymous class that reimplemented the extension logic internally.
39
+ - `spec/whodunit/stampable_spec.rb` — `being_soft_deleted?` tests use real AR dirty tracking via
40
+ genuine attribute writes; callback-integration tests persist records and assert database values
41
+ after `reload`.
42
+ - `spec/whodunit/migration_helpers_spec.rb` — `whodunit_stamps(table_def)` path uses a real
43
+ `TableDefinitionExtension`-prepended `TableDefinition` instance instead of a double.
44
+ - `spec/whodunit/per_model_config_spec.rb`, `railtie_spec.rb`,
45
+ `reverse_associations_integration_spec.rb` — all converted to real AR anonymous subclasses;
46
+ removed stubs for `before_create`, `belongs_to`, and `column_names`.
9
47
 
10
48
  ## [0.3.0] - 2025-01-24
11
49
 
data/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/whodunit.svg)](https://badge.fury.io/rb/whodunit)
4
4
  [![CI](https://github.com/kanutocd/whodunit/workflows/CI/badge.svg)](https://github.com/kanutocd/whodunit/actions)
5
5
  [![Coverage Status](https://codecov.io/gh/kanutocd/whodunit/branch/main/graph/badge.svg)](https://codecov.io/gh/kanutocd/whodunit)
6
- [![Ruby Version](https://img.shields.io/badge/ruby-%3E%3D%203.1.0-ruby.svg)](https://www.ruby-lang.org/en/)
6
+ [![Ruby Version](https://img.shields.io/badge/ruby-%3E%3D%203.2-ruby.svg)](https://www.ruby-lang.org/en/)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
8
 
9
9
  Lightweight creator/updater/deleter tracking for Rails ActiveRecord models.
@@ -16,7 +16,7 @@ Whodunit provides simple auditing for Rails applications by tracking who created
16
16
 
17
17
  ## Requirements
18
18
 
19
- - Ruby 3.1.1+ (tested on 3.1.1, 3.2.0, 3.3.0, 3.4). See the [the ruby-version matrix strategy of the CI workflow](https://github.com/kanutocd/whodunit/blob/main/.github/workflows/ci.yml#L15).
19
+ - Ruby 3.2+ (tested on 3.2, 3.3, 3.4, 4.0). See the [the ruby-version matrix strategy of the CI workflow](https://github.com/kanutocd/whodunit/blob/main/.github/workflows/ci.yml#L15).
20
20
  - Rails 7.2+ (tested on 7.2, 8.2, and edge)
21
21
  - ActiveRecord for database operations
22
22
 
@@ -405,7 +405,7 @@ end
405
405
  | User tracking | ✅ | ✅ | ✅ |
406
406
  | Change history | Via [whodunit-chronicles](https://github.com/kanutocd/whodunit-chronicles) | ✅ | ✅ |
407
407
  | Performance overhead | None | High | Medium |
408
- | Soft-delete detection | ✅ | ❌ | ❌ |
408
+ | Soft-delete support | ✅ | ❌ | ❌ |
409
409
  | Setup complexity | Low | Medium | Medium |
410
410
 
411
411
  ## Documentation
@@ -3,8 +3,8 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  # Rails 7.2 testing
6
- gem "activerecord", "~> 7.2.0"
7
- gem "activesupport", "~> 7.2.0"
6
+ gem "activerecord", ">= 7.2.0"
7
+ gem "activesupport", ">= 7.2.0"
8
8
 
9
9
  # Specify your gem's dependencies in whodunit.gemspec
10
10
  gemspec path: "../"
@@ -3,8 +3,8 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  # Rails 8.0.2 testing
6
- gem "activerecord", "~> 8.0.0"
7
- gem "activesupport", "~> 8.0.0"
6
+ gem "activerecord", ">= 8.0.0"
7
+ gem "activesupport", ">= 8.0.0"
8
8
 
9
9
  # Specify your gem's dependencies in whodunit.gemspec
10
10
  gemspec path: "../"
@@ -28,7 +28,7 @@ module Whodunit
28
28
  # @since 0.1.0
29
29
  class Current < ActiveSupport::CurrentAttributes
30
30
  # @!attribute [rw] user
31
- # @return [Integer, nil] the current user ID
31
+ # @return [Integer, nil] the current user ID
32
32
  attribute :user
33
33
 
34
34
  class << self
@@ -22,19 +22,19 @@ module Whodunit
22
22
 
23
23
  # Extend ActiveRecord with migration helpers.
24
24
  #
25
- # This initializer adds the MigrationHelpers module to ActiveRecord,
25
+ # This initializer adds the MigrationHelpers module to ActiveRecord::Migration,
26
26
  # making methods like add_whodunit_stamps available in migrations.
27
27
  # It also extends TableDefinition for automatic whodunit_stamps injection.
28
28
  #
29
29
  # @api private
30
30
  initializer "whodunit.extend_active_record" do |_app|
31
31
  ActiveSupport.on_load(:active_record) do
32
- extend Whodunit::MigrationHelpers
32
+ ActiveRecord::Migration.include(Whodunit::MigrationHelpers)
33
33
 
34
- # Extend TableDefinition for automatic whodunit_stamps injection
35
- ActiveRecord::ConnectionAdapters::TableDefinition.include(
36
- Whodunit::TableDefinitionExtension
37
- )
34
+ # We use ActiveRecord::ConnectionAdapters::TableDefinition#timestamps to automatically inject whodunit_stamps
35
+ ActiveRecord::ConnectionAdapters::TableDefinition.prepend(Whodunit::TableDefinitionExtension)
36
+ # Reuse the `whodunit_stamps` flow in Whodunit::MigrationHelpers module
37
+ ActiveRecord::ConnectionAdapters::TableDefinition.extend(Whodunit::MigrationHelpers)
38
38
  end
39
39
  end
40
40
 
@@ -145,6 +145,8 @@ module Whodunit
145
145
  private
146
146
 
147
147
  def setup_whodunit_associations
148
+ return if abstract_class?
149
+
148
150
  setup_creator_association if creator_column_exists? && model_creator_enabled?
149
151
  setup_updater_association if updater_column_exists? && model_updater_enabled?
150
152
  setup_deleter_association if deleter_column_exists? && model_deleter_enabled? && soft_delete_enabled?
@@ -28,30 +28,33 @@ module Whodunit
28
28
  module TableDefinitionExtension
29
29
  extend ActiveSupport::Concern
30
30
 
31
- included do
32
- # Track whether whodunit_stamps have been automatically added
33
- attr_accessor :_whodunit_stamps_added
31
+ def _whodunit_stamps_added
32
+ @_whodunit_stamps_added
33
+ end
34
+
35
+ def _whodunit_stamps_added=(value)
36
+ @_whodunit_stamps_added = value
34
37
  end
35
38
 
36
39
  # Override timestamps to trigger automatic whodunit_stamps injection
37
40
  def timestamps(**options)
41
+ options = options.dup
42
+ skip = options.delete(:skip_whodunit_stamps)
38
43
  result = super
39
44
 
40
- # Auto-inject whodunit_stamps after timestamps if enabled and not already added
41
- if Whodunit.auto_inject_whodunit_stamps &&
42
- !@_whodunit_stamps_added &&
43
- !options[:skip_whodunit_stamps]
45
+ if Whodunit.auto_inject_whodunit_stamps && !_whodunit_stamps_added && !skip
44
46
  whodunit_stamps(include_deleter: :auto)
45
- @_whodunit_stamps_added = true
46
47
  end
47
48
 
48
49
  result
49
50
  end
50
51
 
51
- # Also override whodunit_stamps to track that they've been added
52
- def whodunit_stamps(**options)
53
- @_whodunit_stamps_added = true
54
- super
52
+ # assign true tp the tracker `@_whodunit_stamps_added` before the
53
+ # reuse/call of the `whodunit_stamps` flow from the Whodunit::MigrationHelpers module (see railtie.rb)
54
+ #
55
+ def whodunit_stamps(include_deleter: :auto, creator_type: nil, updater_type: nil, deleter_type: nil)
56
+ self._whodunit_stamps_added = true
57
+ self.class.whodunit_stamps(self, include_deleter:, creator_type:, updater_type:, deleter_type:)
55
58
  end
56
59
  end
57
60
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Whodunit
4
- VERSION = "0.3.0"
4
+ VERSION = "0.4.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: whodunit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ken C. Demanawa
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-07-24 00:00:00.000000000 Z
11
+ date: 2026-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '7.2'
19
+ version: 7.2.2.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '7.2'
26
+ version: 7.2.2.2
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activesupport
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '7.2'
33
+ version: 7.2.3.1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '7.2'
40
+ version: 7.2.3.1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler-audit
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '2.5'
83
+ - !ruby/object:Gem::Dependency
84
+ name: ostruct
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  - !ruby/object:Gem::Dependency
84
98
  name: rake
85
99
  requirement: !ruby/object:Gem::Requirement
@@ -178,6 +192,20 @@ dependencies:
178
192
  - - ">="
179
193
  - !ruby/object:Gem::Version
180
194
  version: '3.0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: sqlite3
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: '2.9'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: '2.9'
181
209
  - !ruby/object:Gem::Dependency
182
210
  name: yard
183
211
  requirement: !ruby/object:Gem::Requirement
@@ -245,9 +273,9 @@ require_paths:
245
273
  - lib
246
274
  required_ruby_version: !ruby/object:Gem::Requirement
247
275
  requirements:
248
- - - ">"
276
+ - - ">="
249
277
  - !ruby/object:Gem::Version
250
- version: '3.1'
278
+ version: '3.2'
251
279
  required_rubygems_version: !ruby/object:Gem::Requirement
252
280
  requirements:
253
281
  - - ">="