whodunit 0.1.0 → 0.2.1

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.
data/lib/whodunit.rb CHANGED
@@ -3,10 +3,10 @@
3
3
  require "active_support/all"
4
4
  require_relative "whodunit/version"
5
5
  require_relative "whodunit/current"
6
- require_relative "whodunit/soft_delete_detector"
7
6
  require_relative "whodunit/stampable"
8
7
  require_relative "whodunit/migration_helpers"
9
8
  require_relative "whodunit/controller_methods"
9
+ require_relative "whodunit/table_definition_extension"
10
10
  require_relative "whodunit/railtie"
11
11
 
12
12
  # Lightweight creator/updater/deleter tracking for ActiveRecord models.
@@ -55,9 +55,15 @@ module Whodunit
55
55
  # @return [Symbol] the deleter column name
56
56
  mattr_accessor :deleter_column, default: :deleter_id
57
57
 
58
- # Whether to automatically detect soft-delete implementations (default: true)
59
- # @return [Boolean] auto-detection setting
60
- mattr_accessor :auto_detect_soft_delete, default: true
58
+ # The column name used for soft-delete timestamps (default: nil)
59
+ # Set to a column name to enable soft-delete support (e.g., :deleted_at, :discarded_at)
60
+ # Set to nil to disable soft-delete support entirely
61
+ # @return [Symbol, nil] the soft-delete column name
62
+ mattr_accessor :soft_delete_column, default: nil
63
+
64
+ # Whether to automatically add whodunit_stamps to create_table migrations (default: true)
65
+ # @return [Boolean] auto-injection setting
66
+ mattr_accessor :auto_inject_whodunit_stamps, default: true
61
67
 
62
68
  # @!group Data Type Configuration
63
69
 
@@ -88,8 +94,10 @@ module Whodunit
88
94
  #
89
95
  # @yield [self] configuration block
90
96
  # @return [void]
97
+ # @raise [Whodunit::Error] if both creator_column and updater_column are set to nil
91
98
  def self.configure
92
99
  yield self
100
+ validate_column_configuration!
93
101
  end
94
102
 
95
103
  # Get the user class name as a string
@@ -118,4 +126,38 @@ module Whodunit
118
126
  def self.deleter_data_type
119
127
  deleter_column_type || column_data_type
120
128
  end
129
+
130
+ # Check if soft-delete is enabled
131
+ # @return [Boolean] true if soft-delete is configured (soft_delete_column is not nil)
132
+ def self.soft_delete_enabled?
133
+ !soft_delete_column.nil?
134
+ end
135
+
136
+ # Check if creator column is enabled
137
+ # @return [Boolean] true if creator_column is not nil
138
+ def self.creator_enabled?
139
+ !creator_column.nil?
140
+ end
141
+
142
+ # Check if updater column is enabled
143
+ # @return [Boolean] true if updater_column is not nil
144
+ def self.updater_enabled?
145
+ !updater_column.nil?
146
+ end
147
+
148
+ # Check if deleter column is enabled
149
+ # @return [Boolean] true if deleter_column is not nil
150
+ def self.deleter_enabled?
151
+ !deleter_column.nil?
152
+ end
153
+
154
+ # Validate that column configuration is valid
155
+ # @raise [Whodunit::Error] if both creator_column and updater_column are nil
156
+ def self.validate_column_configuration!
157
+ return if creator_enabled? || updater_enabled?
158
+
159
+ raise Whodunit::Error,
160
+ "At least one of creator_column or updater_column must be configured (not nil). " \
161
+ "Setting both to nil would disable all stamping functionality."
162
+ end
121
163
  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.1.0
4
+ version: 0.2.1
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-20 00:00:00.000000000 Z
11
+ date: 2025-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -193,11 +193,11 @@ dependencies:
193
193
  - !ruby/object:Gem::Version
194
194
  version: 0.9.37
195
195
  description: A lightweight Rails gem that provides simple auditing by tracking who
196
- created, updated, and deleted ActiveRecord models. Features smart soft-delete detection
197
- and zero performance overhead.
196
+ created, updated, and deleted ActiveRecord models.
198
197
  email:
199
198
  - kenneth.c.demanawa@gmail.com
200
- executables: []
199
+ executables:
200
+ - whodunit
201
201
  extensions: []
202
202
  extra_rdoc_files: []
203
203
  files:
@@ -209,16 +209,19 @@ files:
209
209
  - LICENSE
210
210
  - README.md
211
211
  - Rakefile
212
+ - exe/whodunit
212
213
  - gemfiles/rails_7_2.gemfile
213
214
  - gemfiles/rails_8_2.gemfile
214
215
  - gemfiles/rails_edge.gemfile
215
216
  - lib/whodunit.rb
216
217
  - lib/whodunit/controller_methods.rb
217
218
  - lib/whodunit/current.rb
219
+ - lib/whodunit/generator.rb
220
+ - lib/whodunit/generator/application_record_integration.rb
218
221
  - lib/whodunit/migration_helpers.rb
219
222
  - lib/whodunit/railtie.rb
220
- - lib/whodunit/soft_delete_detector.rb
221
223
  - lib/whodunit/stampable.rb
224
+ - lib/whodunit/table_definition_extension.rb
222
225
  - lib/whodunit/version.rb
223
226
  - sig/whodunit.rbs
224
227
  homepage: https://github.com/kanutocd/whodunit
@@ -230,17 +233,21 @@ metadata:
230
233
  source_code_uri: https://github.com/kanutocd/whodunit.git
231
234
  changelog_uri: https://github.com/kanutocd/whodunit/blob/main/CHANGELOG.md
232
235
  bug_tracker_uri: https://github.com/kanutocd/whodunit/issues
233
- documentation_uri: https://github.com/kanutocd/whodunit/blob/main/README.md
236
+ documentation_uri: https://kanutocd.github.io/whodunit
234
237
  rubygems_mfa_required: 'true'
235
- post_install_message:
238
+ post_install_message: "\U0001F389 Thanks for installing Whodunit!\n\nWhat's next?\n\n1.
239
+ Generate configuration (recommended):\n whodunit install\n\n2. Add stamp columns
240
+ to your models:\n rails generate migration AddStampsToUsers\n # Then add: add_whodunit_stamps
241
+ :users\n\n3. Include Whodunit::Stampable in your models:\n class User < ApplicationRecord\n
242
+ \ include Whodunit::Stampable\n end\n\n\U0001F4D6 Complete documentation: https://kanutocd.github.io/whodunit\n"
236
243
  rdoc_options: []
237
244
  require_paths:
238
245
  - lib
239
246
  required_ruby_version: !ruby/object:Gem::Requirement
240
247
  requirements:
241
- - - ">="
248
+ - - ">"
242
249
  - !ruby/object:Gem::Version
243
- version: 3.0.0
250
+ version: '3.1'
244
251
  required_rubygems_version: !ruby/object:Gem::Requirement
245
252
  requirements:
246
253
  - - ">="
@@ -1,119 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Whodunit
4
- # Smart detection of soft-delete implementations.
5
- #
6
- # This class provides multi-layered detection for various soft-delete implementations
7
- # including popular gems like Discard and Paranoia, as well as custom implementations.
8
- #
9
- # @example Check if a model has soft-delete enabled
10
- # class Post < ApplicationRecord
11
- # # has deleted_at column
12
- # end
13
- #
14
- # Whodunit::SoftDeleteDetector.enabled_for?(Post) # => true
15
- #
16
- # @example With Discard gem
17
- # class Post < ApplicationRecord
18
- # include Discard::Model
19
- # end
20
- #
21
- # Whodunit::SoftDeleteDetector.enabled_for?(Post) # => true
22
- #
23
- # @since 0.1.0
24
- class SoftDeleteDetector
25
- # Main detection method that checks if soft-delete is enabled for a model.
26
- #
27
- # Uses multiple detection strategies:
28
- # 1. Gem-based detection (Discard, Paranoia, etc.)
29
- # 2. Column pattern detection (deleted_at, discarded_at, etc.)
30
- # 3. Method-based detection (respond_to? soft-delete methods)
31
- #
32
- # @param model [Class] the ActiveRecord model class to check
33
- # @return [Boolean] true if soft-delete is detected, false otherwise
34
- # @example
35
- # Whodunit::SoftDeleteDetector.enabled_for?(Post) # => true
36
- # Whodunit::SoftDeleteDetector.enabled_for?(User) # => false
37
- def self.enabled_for?(model)
38
- return false unless model.respond_to?(:columns)
39
-
40
- gem_based_detection?(model) ||
41
- column_pattern_detection(model) ||
42
- method_based_detection(model)
43
- end
44
-
45
- # Detect popular soft-delete gems.
46
- #
47
- # Detects the following gems:
48
- # - Discard (checks for Discard module inclusion)
49
- # - Paranoia (checks for paranoid? method and Paranoid ancestors)
50
- # - ActsAsParanoid (checks for acts_as_paranoid method)
51
- #
52
- # @param model [Class] the ActiveRecord model class to check
53
- # @return [Boolean] true if a gem-based soft-delete is detected
54
- # @api private
55
- def self.gem_based_detection?(model)
56
- # Discard gem
57
- return true if model.included_modules.any? { |mod| mod.to_s.include?("Discard") }
58
-
59
- # Paranoia gem
60
- return true if model.respond_to?(:paranoid?) ||
61
- model.respond_to?(:acts_as_paranoid) ||
62
- model.ancestors.any? { |a| a.to_s.include?("Paranoid") }
63
-
64
- # ActsAsParanoid (older version)
65
- return true if model.respond_to?(:acts_as_paranoid)
66
-
67
- false
68
- end
69
-
70
- # Detect soft-delete by column patterns.
71
- #
72
- # Looks for common soft-delete column names:
73
- # - deleted_at, destroyed_at, discarded_at, archived_at
74
- # - soft_deleted_at, soft_destroyed_at, removed_at
75
- #
76
- # Only considers timestamp columns (datetime, timestamp, date).
77
- #
78
- # @param model [Class] the ActiveRecord model class to check
79
- # @return [Boolean] true if soft-delete columns are found
80
- # @api private
81
- def self.column_pattern_detection(model)
82
- soft_delete_columns = %w[
83
- deleted_at destroyed_at discarded_at archived_at
84
- soft_deleted_at soft_destroyed_at removed_at
85
- ]
86
-
87
- model.columns.any? do |column|
88
- soft_delete_columns.include?(column.name) &&
89
- timestamp_column?(column)
90
- end
91
- end
92
-
93
- # Detect soft-delete by method presence.
94
- #
95
- # Checks if the model responds to common soft-delete method names.
96
- # This catches custom implementations that follow standard naming conventions.
97
- #
98
- # @param model [Class] the ActiveRecord model class to check
99
- # @return [Boolean] true if soft-delete methods are found
100
- # @api private
101
- def self.method_based_detection(model)
102
- soft_delete_methods = %w[
103
- deleted_at destroyed_at discarded_at archived_at
104
- soft_deleted_at soft_destroyed_at removed_at
105
- ]
106
-
107
- soft_delete_methods.any? { |method| model.respond_to?(method) }
108
- end
109
-
110
- # Check if a column is a timestamp type.
111
- #
112
- # @param column [Object] the column object (responds to #type)
113
- # @return [Boolean] true if the column is a timestamp type
114
- # @api private
115
- def self.timestamp_column?(column)
116
- %i[datetime timestamp date].include?(column.type)
117
- end
118
- end
119
- end