real_data_tests 0.1.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 40264604e537da8c1f365cd1afce57fef95988d3e51d36e1c7c68c425f0e3e8b
4
- data.tar.gz: 57d486a6a25bc26522051aa2ad2a105698e28911679b1bccf6c25e1c4dd11880
3
+ metadata.gz: a8d2dd0beed227113467c6660eaa2101c603ef7c127ad3bd7fb19c835a641b1b
4
+ data.tar.gz: ac0e5fdb541110b7a523a6fa8a894d49d1c10ab9eeab86003f9ae13ebbf1968a
5
5
  SHA512:
6
- metadata.gz: d7784e89db22fd3c522a9c4b60a8cca7c4c8e15bdbc86f3d20b9aa8cce4a58dbe1f1724c0355defbec3ab00f2d26e831a4351e2b5dc6fd15c97a724ed5079c95
7
- data.tar.gz: 60ea36eb4824cb15554026431e0fd06d52ca1194417d025be3db9b9f93e093ccce8b50db48baecf4f5388e8458c76028ae687b6513f00bb1cb3c1acfb2b1637b
6
+ metadata.gz: e048bb72149153484dc179e7628ea3fc41e083906e7cbbd8c1a970b147aa1a232c5d32a6d26553de22c8c3b21a281913515bf1c51b43700c80ba0ac3dc35ffe6
7
+ data.tar.gz: 3859be802e7aea039691af38cc309bb56c81832bb5740d510e9f6438d10873a66d1efa8aae167a8cdc2a7e3f24b8b4c26f92d2481303d948797bbbd6a5d08d4d
data/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  ## [Unreleased]
2
2
 
3
- ## [0.1.0] - 2025-01-11
3
+ ## [0.2.1] - 2025-01-13
4
+ ### Fixed
5
+ - Fixed JSONB field handling to output '{}' instead of empty string for blank values
6
+ - Added test coverage for JSONB field handling in PgDumpGenerator
7
+
8
+ ## [0.2.0] - 2025-01-13
9
+ ### Added
10
+ - New preset system for managing different test data configurations
11
+ - Added `preset`, `use_preset`, and `with_preset` methods for configuration
12
+ - Support for multiple named configuration presets
13
+ - Added documentation for using presets
14
+ - New PresetConfig class to handle preset-specific configurations
4
15
 
5
- - Initial release
16
+ ### Changed
17
+ - Refactored Configuration class to use preset-based approach
18
+ - Moved configuration methods into PresetConfig class
19
+ - Updated documentation with preset usage examples and best practices
20
+
21
+ ## [0.1.0] - 2025-01-11
22
+ - Initial release
data/Gemfile.lock ADDED
@@ -0,0 +1,220 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ real_data_tests (0.2.0)
5
+ activerecord (>= 5.0)
6
+ faker (~> 3.0)
7
+ pg (>= 1.1)
8
+ rails (>= 5.0)
9
+ thor (~> 1.0)
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ actioncable (7.2.2.1)
15
+ actionpack (= 7.2.2.1)
16
+ activesupport (= 7.2.2.1)
17
+ nio4r (~> 2.0)
18
+ websocket-driver (>= 0.6.1)
19
+ zeitwerk (~> 2.6)
20
+ actionmailbox (7.2.2.1)
21
+ actionpack (= 7.2.2.1)
22
+ activejob (= 7.2.2.1)
23
+ activerecord (= 7.2.2.1)
24
+ activestorage (= 7.2.2.1)
25
+ activesupport (= 7.2.2.1)
26
+ mail (>= 2.8.0)
27
+ actionmailer (7.2.2.1)
28
+ actionpack (= 7.2.2.1)
29
+ actionview (= 7.2.2.1)
30
+ activejob (= 7.2.2.1)
31
+ activesupport (= 7.2.2.1)
32
+ mail (>= 2.8.0)
33
+ rails-dom-testing (~> 2.2)
34
+ actionpack (7.2.2.1)
35
+ actionview (= 7.2.2.1)
36
+ activesupport (= 7.2.2.1)
37
+ nokogiri (>= 1.8.5)
38
+ racc
39
+ rack (>= 2.2.4, < 3.2)
40
+ rack-session (>= 1.0.1)
41
+ rack-test (>= 0.6.3)
42
+ rails-dom-testing (~> 2.2)
43
+ rails-html-sanitizer (~> 1.6)
44
+ useragent (~> 0.16)
45
+ actiontext (7.2.2.1)
46
+ actionpack (= 7.2.2.1)
47
+ activerecord (= 7.2.2.1)
48
+ activestorage (= 7.2.2.1)
49
+ activesupport (= 7.2.2.1)
50
+ globalid (>= 0.6.0)
51
+ nokogiri (>= 1.8.5)
52
+ actionview (7.2.2.1)
53
+ activesupport (= 7.2.2.1)
54
+ builder (~> 3.1)
55
+ erubi (~> 1.11)
56
+ rails-dom-testing (~> 2.2)
57
+ rails-html-sanitizer (~> 1.6)
58
+ activejob (7.2.2.1)
59
+ activesupport (= 7.2.2.1)
60
+ globalid (>= 0.3.6)
61
+ activemodel (7.2.2.1)
62
+ activesupport (= 7.2.2.1)
63
+ activerecord (7.2.2.1)
64
+ activemodel (= 7.2.2.1)
65
+ activesupport (= 7.2.2.1)
66
+ timeout (>= 0.4.0)
67
+ activestorage (7.2.2.1)
68
+ actionpack (= 7.2.2.1)
69
+ activejob (= 7.2.2.1)
70
+ activerecord (= 7.2.2.1)
71
+ activesupport (= 7.2.2.1)
72
+ marcel (~> 1.0)
73
+ activesupport (7.2.2.1)
74
+ base64
75
+ benchmark (>= 0.3)
76
+ bigdecimal
77
+ concurrent-ruby (~> 1.0, >= 1.3.1)
78
+ connection_pool (>= 2.2.5)
79
+ drb
80
+ i18n (>= 1.6, < 2)
81
+ logger (>= 1.4.2)
82
+ minitest (>= 5.1)
83
+ securerandom (>= 0.3)
84
+ tzinfo (~> 2.0, >= 2.0.5)
85
+ base64 (0.2.0)
86
+ benchmark (0.4.0)
87
+ bigdecimal (3.1.9)
88
+ builder (3.3.0)
89
+ concurrent-ruby (1.3.4)
90
+ connection_pool (2.5.0)
91
+ crass (1.0.6)
92
+ database_cleaner (2.1.0)
93
+ database_cleaner-active_record (>= 2, < 3)
94
+ database_cleaner-active_record (2.2.0)
95
+ activerecord (>= 5.a)
96
+ database_cleaner-core (~> 2.0.0)
97
+ database_cleaner-core (2.0.1)
98
+ date (3.4.1)
99
+ diff-lcs (1.5.1)
100
+ drb (2.2.1)
101
+ erubi (1.13.1)
102
+ faker (3.5.1)
103
+ i18n (>= 1.8.11, < 2)
104
+ globalid (1.2.1)
105
+ activesupport (>= 6.1)
106
+ i18n (1.14.6)
107
+ concurrent-ruby (~> 1.0)
108
+ io-console (0.8.0)
109
+ irb (1.14.3)
110
+ rdoc (>= 4.0.0)
111
+ reline (>= 0.4.2)
112
+ logger (1.6.5)
113
+ loofah (2.24.0)
114
+ crass (~> 1.0.2)
115
+ nokogiri (>= 1.12.0)
116
+ mail (2.8.1)
117
+ mini_mime (>= 0.1.1)
118
+ net-imap
119
+ net-pop
120
+ net-smtp
121
+ marcel (1.0.4)
122
+ mini_mime (1.1.5)
123
+ minitest (5.25.4)
124
+ net-imap (0.5.5)
125
+ date
126
+ net-protocol
127
+ net-pop (0.1.2)
128
+ net-protocol
129
+ net-protocol (0.2.2)
130
+ timeout
131
+ net-smtp (0.5.0)
132
+ net-protocol
133
+ nio4r (2.7.4)
134
+ nokogiri (1.18.1-x86_64-darwin)
135
+ racc (~> 1.4)
136
+ pg (1.5.9)
137
+ psych (5.2.2)
138
+ date
139
+ stringio
140
+ racc (1.8.1)
141
+ rack (3.1.8)
142
+ rack-session (2.1.0)
143
+ base64 (>= 0.1.0)
144
+ rack (>= 3.0.0)
145
+ rack-test (2.2.0)
146
+ rack (>= 1.3)
147
+ rackup (2.2.1)
148
+ rack (>= 3)
149
+ rails (7.2.2.1)
150
+ actioncable (= 7.2.2.1)
151
+ actionmailbox (= 7.2.2.1)
152
+ actionmailer (= 7.2.2.1)
153
+ actionpack (= 7.2.2.1)
154
+ actiontext (= 7.2.2.1)
155
+ actionview (= 7.2.2.1)
156
+ activejob (= 7.2.2.1)
157
+ activemodel (= 7.2.2.1)
158
+ activerecord (= 7.2.2.1)
159
+ activestorage (= 7.2.2.1)
160
+ activesupport (= 7.2.2.1)
161
+ bundler (>= 1.15.0)
162
+ railties (= 7.2.2.1)
163
+ rails-dom-testing (2.2.0)
164
+ activesupport (>= 5.0.0)
165
+ minitest
166
+ nokogiri (>= 1.6)
167
+ rails-html-sanitizer (1.6.2)
168
+ loofah (~> 2.21)
169
+ nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
170
+ railties (7.2.2.1)
171
+ actionpack (= 7.2.2.1)
172
+ activesupport (= 7.2.2.1)
173
+ irb (~> 1.13)
174
+ rackup (>= 1.0.0)
175
+ rake (>= 12.2)
176
+ thor (~> 1.0, >= 1.2.2)
177
+ zeitwerk (~> 2.6)
178
+ rake (13.2.1)
179
+ rdoc (6.10.0)
180
+ psych (>= 4.0.0)
181
+ reline (0.6.0)
182
+ io-console (~> 0.5)
183
+ rspec (3.13.0)
184
+ rspec-core (~> 3.13.0)
185
+ rspec-expectations (~> 3.13.0)
186
+ rspec-mocks (~> 3.13.0)
187
+ rspec-core (3.13.2)
188
+ rspec-support (~> 3.13.0)
189
+ rspec-expectations (3.13.3)
190
+ diff-lcs (>= 1.2.0, < 2.0)
191
+ rspec-support (~> 3.13.0)
192
+ rspec-mocks (3.13.2)
193
+ diff-lcs (>= 1.2.0, < 2.0)
194
+ rspec-support (~> 3.13.0)
195
+ rspec-support (3.13.2)
196
+ securerandom (0.4.1)
197
+ stringio (3.1.2)
198
+ thor (1.3.2)
199
+ timeout (0.4.3)
200
+ tzinfo (2.0.6)
201
+ concurrent-ruby (~> 1.0)
202
+ useragent (0.16.11)
203
+ websocket-driver (0.7.7)
204
+ base64
205
+ websocket-extensions (>= 0.1.0)
206
+ websocket-extensions (0.1.5)
207
+ zeitwerk (2.6.18)
208
+
209
+ PLATFORMS
210
+ x86_64-darwin-21
211
+
212
+ DEPENDENCIES
213
+ database_cleaner (~> 2.0)
214
+ database_cleaner-active_record
215
+ rake (~> 13.0)
216
+ real_data_tests!
217
+ rspec (~> 3.0)
218
+
219
+ BUNDLED WITH
220
+ 2.3.27
data/README.md CHANGED
@@ -50,31 +50,115 @@ Rails.application.config.after_initialize do
50
50
  # Directory where SQL dumps will be stored
51
51
  config.dump_path = 'spec/fixtures/real_data_dumps'
52
52
 
53
- # Global associations (apply to all models)
54
- config.include_associations(
55
- :user,
56
- :organization,
57
- :profile
58
- )
59
-
60
- # Model-specific associations
61
- config.include_associations_for 'Patient', :visit_notes, :treatment_reports
62
- config.include_associations_for 'Discipline', :organization, :user
63
-
64
- # Control association loading behavior
65
- config.limit_association 'Patient.visit_notes', 10
66
- config.prevent_reciprocal 'VisitNoteType.visit_notes'
67
-
68
- # Configure data anonymization
69
- config.anonymize 'User', {
70
- first_name: -> (_) { Faker::Name.first_name },
71
- last_name: -> (_) { Faker::Name.last_name },
72
- email: -> (user) { Faker::Internet.email(name: "user#{user.id}") }
53
+ # Define a preset for collecting patient visit data
54
+ config.preset :patient_visits do |p|
55
+ p.include_associations(
56
+ :visit_note_type,
57
+ :patient_status
58
+ )
59
+
60
+ p.include_associations_for 'Patient',
61
+ :visit_notes,
62
+ :treatment_reports
63
+
64
+ p.prevent_reciprocal 'VisitNoteType.visit_notes'
65
+
66
+ p.anonymize 'Patient', {
67
+ first_name: -> (_) { Faker::Name.first_name },
68
+ last_name: -> (_) { Faker::Name.last_name }
69
+ }
70
+ end
71
+
72
+ # Define a preset for organization structure
73
+ config.preset :org_structure do |p|
74
+ p.include_associations(
75
+ :organization,
76
+ :user
77
+ )
78
+
79
+ p.include_associations_for 'Department',
80
+ :employees,
81
+ :managers
82
+
83
+ p.limit_association 'Department.employees', 100
84
+
85
+ p.anonymize 'User', {
86
+ email: -> (user) { Faker::Internet.email(name: "user#{user.id}") }
87
+ }
88
+ end
89
+ end
90
+ end
91
+ ```
92
+
93
+ ## Using Presets
94
+
95
+ Real Data Tests allows you to define multiple configuration presets for different data extraction needs. This is particularly useful when you need different association rules and anonymization settings for different testing scenarios.
96
+
97
+ ### Defining Presets
98
+
99
+ You can define presets in your configuration:
100
+
101
+ ```ruby
102
+ RealDataTests.configure do |config|
103
+ # Define a preset for patient data
104
+ config.preset :patient_data do |p|
105
+ p.include_associations(:patient_status, :visit_note_type)
106
+ p.include_associations_for 'Patient', :visit_notes
107
+ p.limit_association 'Patient.visit_notes', 10
108
+ end
109
+
110
+ # Define another preset for billing data
111
+ config.preset :billing_data do |p|
112
+ p.include_associations(:payment_method, :insurance_provider)
113
+ p.include_associations_for 'Invoice', :line_items, :payments
114
+ p.anonymize 'PaymentMethod', {
115
+ account_number: -> (_) { Faker::Finance.credit_card }
73
116
  }
74
117
  end
75
118
  end
76
119
  ```
77
120
 
121
+ ### Using Presets in Your Code
122
+
123
+ You can use presets in several ways:
124
+
125
+ ```ruby
126
+ # Create dump file using a specific preset
127
+ RealDataTests.with_preset(:patient_data) do
128
+ RealDataTests.create_dump_file(patient, name: "patient_with_visits")
129
+ end
130
+
131
+ # Switch to a different preset
132
+ RealDataTests.use_preset(:billing_data)
133
+ RealDataTests.create_dump_file(invoice, name: "invoice_with_payments")
134
+
135
+ # Use in tests
136
+ RSpec.describe "Patient Visits" do
137
+ it "loads visit data correctly" do
138
+ RealDataTests.with_preset(:patient_data) do
139
+ load_real_test_data("patient_with_visits")
140
+ # Your test code here
141
+ end
142
+ end
143
+ end
144
+ ```
145
+
146
+ ### Benefits of Using Presets
147
+
148
+ - **Organized Configuration**: Keep related association rules and anonymization settings together
149
+ - **Reusability**: Define configurations once and reuse them across different tests
150
+ - **Clarity**: Make it clear what data is being extracted for each testing scenario
151
+ - **Flexibility**: Easily switch between different data extraction rules
152
+ - **Maintainability**: Update all related settings in one place
153
+
154
+ ### Best Practices for Presets
155
+
156
+ 1. **Descriptive Names**: Use clear, purpose-indicating names for your presets
157
+ 2. **Single Responsibility**: Each preset should focus on a specific testing scenario
158
+ 3. **Documentation**: Comment your presets to explain their purpose and usage
159
+ 4. **Composition**: Group related models and their associations in the same preset
160
+ 5. **Version Control**: Keep preset definitions with your test code for easy reference
161
+
78
162
  ## Usage
79
163
 
80
164
  ### 1. Preparing Test Data
@@ -1,53 +1,75 @@
1
- # lib/real_data_tests/configuration.rb
2
1
  module RealDataTests
3
2
  class Configuration
4
- attr_accessor :dump_path, :cleanup_models
5
- attr_reader :association_filter_mode, :association_filter_list, :anonymization_rules,
6
- :model_specific_associations, :association_limits, :prevent_reciprocal_loading
3
+ attr_accessor :dump_path, :current_preset
4
+ attr_reader :presets
7
5
 
8
6
  def initialize
9
7
  @dump_path = 'spec/fixtures/real_data_dumps'
10
- @anonymization_rules = {}
11
- @association_filter_mode = nil
12
- @association_filter_list = []
13
- @model_specific_associations = {}
14
- @cleanup_models = []
15
- @association_limits = {}
16
- @prevent_reciprocal_loading = {}
8
+ @presets = {}
9
+ @current_preset = nil
10
+ create_preset(:default) # Always have a default preset
17
11
  end
18
12
 
19
- def anonymize(model_name, mappings = {})
20
- if defined?(::Rails::Engine)
21
- unless ::Rails::Engine.subclasses.map(&:name).include?('RealDataTests::Engine')
22
- @delayed_anonymizations << [model_name, mappings]
23
- return
24
- end
25
- end
13
+ private def create_preset(name)
14
+ @presets[name] = PresetConfig.new
15
+ @current_preset = @presets[name]
16
+ end
26
17
 
27
- begin
28
- model = model_name.to_s.constantize
29
- @anonymization_rules[model_name.to_s] = mappings
30
- rescue => e
31
- warn "Note: Anonymization for #{model_name} will be configured when Rails is fully initialized."
32
- end
18
+ def get_association_limit(record_class, association_name)
19
+ current_preset&.get_association_limit(record_class, association_name)
33
20
  end
34
21
 
35
- def process_delayed_anonymizations
36
- return unless @delayed_anonymizations
22
+ def prevent_reciprocal?(record_class, association_name)
23
+ current_preset&.prevent_reciprocal?(record_class, association_name)
24
+ end
37
25
 
38
- @delayed_anonymizations.each do |model_name, mappings|
39
- anonymize(model_name, mappings)
40
- end
41
- @delayed_anonymizations = []
26
+ def preset(name, &block)
27
+ name = name.to_sym
28
+ @presets[name] = PresetConfig.new
29
+ @current_preset = @presets[name]
30
+ yield(@current_preset) if block_given?
31
+ @current_preset = @presets[:default]
42
32
  end
43
33
 
44
- def exclude_associations(*associations)
45
- if @association_filter_mode == :whitelist
46
- raise Error, "Cannot set excluded_associations when included_associations is already set"
34
+ def use_preset(name)
35
+ name = name.to_sym
36
+ raise Error, "Preset '#{name}' not found" unless @presets.key?(name)
37
+ @current_preset = @presets[name]
38
+ end
39
+
40
+ def with_preset(name)
41
+ previous_preset = @current_preset
42
+ use_preset(name)
43
+ yield if block_given?
44
+ ensure
45
+ @current_preset = previous_preset
46
+ end
47
+
48
+ def method_missing(method_name, *args, &block)
49
+ if @current_preset.respond_to?(method_name)
50
+ @current_preset.public_send(method_name, *args, &block)
51
+ else
52
+ super
47
53
  end
54
+ end
48
55
 
49
- @association_filter_mode = :blacklist
50
- @association_filter_list = associations.flatten
56
+ def respond_to_missing?(method_name, include_private = false)
57
+ @current_preset.respond_to?(method_name) || super
58
+ end
59
+ end
60
+
61
+ class PresetConfig
62
+ attr_reader :association_filter_mode, :association_filter_list,
63
+ :model_specific_associations, :association_limits,
64
+ :prevent_reciprocal_loading, :anonymization_rules
65
+
66
+ def initialize
67
+ @association_filter_mode = nil
68
+ @association_filter_list = []
69
+ @model_specific_associations = {}
70
+ @association_limits = {}
71
+ @prevent_reciprocal_loading = {}
72
+ @anonymization_rules = {}
51
73
  end
52
74
 
53
75
  def include_associations(*associations)
@@ -58,21 +80,48 @@ module RealDataTests
58
80
  @association_filter_list = associations.flatten
59
81
  end
60
82
 
61
- # New method for model-specific association rules
83
+ def exclude_associations(*associations)
84
+ if @association_filter_mode == :whitelist
85
+ raise Error, "Cannot set excluded_associations when included_associations is already set"
86
+ end
87
+ @association_filter_mode = :blacklist
88
+ @association_filter_list = associations.flatten
89
+ end
90
+
62
91
  def include_associations_for(model, *associations)
63
92
  model_name = model.is_a?(String) ? model : model.name
64
93
  @model_specific_associations[model_name] = associations.flatten
65
94
  end
66
95
 
96
+ def limit_association(path, limit)
97
+ @association_limits[path.to_s] = limit
98
+ end
99
+
100
+ def get_association_limit(record_class, association_name)
101
+ path = "#{record_class.name}.#{association_name}"
102
+ @association_limits[path]
103
+ end
104
+
105
+ def prevent_reciprocal?(record_class, association_name)
106
+ path = "#{record_class.name}.#{association_name}"
107
+ @prevent_reciprocal_loading[path]
108
+ end
109
+
110
+ def prevent_reciprocal(path)
111
+ @prevent_reciprocal_loading[path.to_s] = true
112
+ end
113
+
114
+ def anonymize(model_name, mappings = {})
115
+ @anonymization_rules[model_name.to_s] = mappings
116
+ end
117
+
67
118
  def should_process_association?(model, association_name)
68
119
  model_name = model.is_a?(Class) ? model.name : model.class.name
69
120
 
70
- # Check model-specific rules first
71
121
  if @model_specific_associations.key?(model_name)
72
122
  return @model_specific_associations[model_name].include?(association_name)
73
123
  end
74
124
 
75
- # Fall back to global rules
76
125
  case @association_filter_mode
77
126
  when :whitelist
78
127
  @association_filter_list.include?(association_name)
@@ -82,35 +131,5 @@ module RealDataTests
82
131
  true
83
132
  end
84
133
  end
85
-
86
- def configure_cleanup(*models)
87
- @cleanup_models = models.flatten
88
- end
89
-
90
- # Configure limits for specific associations
91
- # Example: limit_association 'Patient.visit_notes', 10
92
- def limit_association(path, limit)
93
- @association_limits[path.to_s] = limit
94
- end
95
-
96
- # Prevent loading reciprocal associations
97
- # Example: prevent_reciprocal 'VisitNoteType.visit_notes'
98
- def prevent_reciprocal(path)
99
- @prevent_reciprocal_loading[path.to_s] = true
100
- end
101
-
102
- # Get limit for a specific association
103
- def get_association_limit(record_class, association_name)
104
- path = "#{record_class.name}.#{association_name}"
105
- @association_limits[path]
106
- end
107
-
108
- # Check if reciprocal loading should be prevented
109
- def prevent_reciprocal?(record_class, association_name)
110
- path = "#{record_class.name}.#{association_name}"
111
- @prevent_reciprocal_loading[path]
112
- end
113
134
  end
114
-
115
- class Error < StandardError; end
116
135
  end
@@ -3,8 +3,8 @@ require 'faker'
3
3
 
4
4
  module RealDataTests
5
5
  class DataAnonymizer
6
- def initialize(configuration)
7
- @configuration = configuration
6
+ def initialize(preset_config)
7
+ @preset_config = preset_config
8
8
  end
9
9
 
10
10
  def anonymize_records(records)
@@ -16,38 +16,32 @@ module RealDataTests
16
16
  def anonymize_record(record)
17
17
  return record unless should_anonymize?(record)
18
18
 
19
- anonymization_rules = @configuration.anonymization_rules[record.class.name]
20
-
19
+ anonymization_rules = @preset_config.anonymization_rules[record.class.name]
21
20
  anonymization_rules.each do |attribute, anonymizer|
22
21
  begin
23
22
  new_value = case anonymizer
24
23
  when String
25
- # Handle legacy string-based Faker calls
26
24
  process_faker_string(anonymizer)
27
25
  when Proc, Lambda
28
- # Handle lambda-based anonymizers
29
26
  anonymizer.call(record)
30
27
  else
31
28
  raise Error, "Unsupported anonymizer type: #{anonymizer.class}"
32
29
  end
33
-
34
30
  record.send("#{attribute}=", new_value)
35
31
  rescue => e
36
32
  raise Error, "Failed to anonymize #{attribute} using #{anonymizer.inspect}: #{e.message}"
37
33
  end
38
34
  end
39
-
40
35
  record
41
36
  end
42
37
 
43
38
  private
44
39
 
45
40
  def should_anonymize?(record)
46
- @configuration.anonymization_rules.key?(record.class.name)
41
+ @preset_config.anonymization_rules.key?(record.class.name)
47
42
  end
48
43
 
49
44
  def process_faker_string(faker_method)
50
- # Support legacy string format like "Faker::Name.first_name"
51
45
  faker_class, faker_method = faker_method.split('::')[1..].join('::').split('.')
52
46
  faker_class = Object.const_get("Faker::#{faker_class}")
53
47
  faker_class.send(faker_method)
@@ -7,11 +7,5 @@ module RealDataTests
7
7
  config.before_configuration do
8
8
  RealDataTests.configuration
9
9
  end
10
-
11
- initializer 'real_data_tests.initialize' do |app|
12
- if RealDataTests.configuration
13
- RealDataTests.configuration.process_delayed_anonymizations
14
- end
15
- end
16
10
  end
17
11
  end
@@ -138,8 +138,14 @@ module RealDataTests
138
138
  value.to_s
139
139
  when :boolean
140
140
  value.to_s
141
- when :array, :json, :jsonb
142
- parse_and_format_special_type(value, column_info)
141
+ when :jsonb, :json
142
+ if value.blank?
143
+ "'{}'" # Return empty JSON object for blank JSONB/JSON fields
144
+ else
145
+ sanitize_string(value.is_a?(String) ? value : value.to_json)
146
+ end
147
+ when :array
148
+ parse_and_format_array(value, column_info[:sql_type])
143
149
  else
144
150
  if column_info[:array]
145
151
  parse_and_format_array(value, column_info[:sql_type])
@@ -8,19 +8,17 @@ module RealDataTests
8
8
  def create_dump_file
9
9
  records = RealDataTests::RecordCollector.new(@record).collect
10
10
 
11
- # Only anonymize if rules are configured
12
- if RealDataTests.configuration.anonymization_rules.any?
11
+ # Only anonymize if rules are configured in the current preset
12
+ if RealDataTests.configuration.current_preset.anonymization_rules.any?
13
13
  puts "\nAnonymizing records..."
14
- anonymizer = RealDataTests::DataAnonymizer.new(RealDataTests.configuration)
15
- anonymizer.anonymize_records(records)
14
+ anonymizer = RealDataTests::DataAnonymizer.new(RealDataTests.configuration.current_preset)
15
+ records = anonymizer.anonymize_records(records)
16
16
  end
17
17
 
18
18
  dump_content = RealDataTests::PgDumpGenerator.new(records).generate
19
19
  dump_path = dump_file_path
20
-
21
20
  FileUtils.mkdir_p(File.dirname(dump_path))
22
21
  File.write(dump_path, dump_content)
23
-
24
22
  puts "\nDump file created at: #{dump_path}"
25
23
  dump_path
26
24
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RealDataTests
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.1"
5
5
  end
@@ -1,13 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'real_data_tests/configuration'
4
- require 'real_data_tests/data_anonymizer'
5
- require 'real_data_tests/engine' if defined?(Rails)
6
- require 'real_data_tests/pg_dump_generator'
7
- require 'real_data_tests/record_collector'
8
- require 'real_data_tests/rspec_helper'
9
- require 'real_data_tests/test_data_builder'
10
- require 'real_data_tests/version'
3
+ require 'rails'
4
+ require_relative 'real_data_tests/version'
5
+ require_relative 'real_data_tests/configuration'
6
+ require_relative 'real_data_tests/data_anonymizer'
7
+ require_relative 'real_data_tests/engine' if defined?(Rails)
8
+ require_relative 'real_data_tests/pg_dump_generator'
9
+ require_relative 'real_data_tests/record_collector'
10
+ require_relative 'real_data_tests/rspec_helper'
11
+ require_relative 'real_data_tests/test_data_builder'
11
12
 
12
13
  module RealDataTests
13
14
  class Error < StandardError; end
@@ -28,6 +29,18 @@ module RealDataTests
28
29
  @configuration = Configuration.new
29
30
  end
30
31
 
32
+ def use_preset(name)
33
+ configuration.use_preset(name)
34
+ end
35
+
36
+ def with_preset(name)
37
+ previous_preset = configuration.current_preset
38
+ configuration.use_preset(name)
39
+ yield if block_given?
40
+ ensure
41
+ configuration.current_preset = previous_preset
42
+ end
43
+
31
44
  def create_dump_file(record, name: nil)
32
45
  raise ConfigurationError, "Configuration not initialized" unless @configuration
33
46
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: real_data_tests
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
  - Kevin Dias
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-01-11 00:00:00.000000000 Z
11
+ date: 2025-01-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -108,6 +108,20 @@ dependencies:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
110
  version: '2.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: database_cleaner-active_record
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: faker
113
127
  requirement: !ruby/object:Gem::Requirement
@@ -134,6 +148,7 @@ files:
134
148
  - CHANGELOG.md
135
149
  - CODE_OF_CONDUCT.md
136
150
  - Gemfile
151
+ - Gemfile.lock
137
152
  - LICENSE.txt
138
153
  - README.md
139
154
  - Rakefile
@@ -146,7 +161,6 @@ files:
146
161
  - lib/real_data_tests/rspec_helper.rb
147
162
  - lib/real_data_tests/test_data_builder.rb
148
163
  - lib/real_data_tests/version.rb
149
- - sig/real_data_tests.rbs
150
164
  homepage: https://github.com/diasks2/real_data_tests
151
165
  licenses:
152
166
  - MIT
@@ -1,4 +0,0 @@
1
- module RealDataTests
2
- VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
- end