fixture_record 0.1.1.pre.rc → 0.1.2.pre.rc

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: 6720df231526a9d9119a2146337d2c029e5c1479eaea6f88b17df9ce8e1222fc
4
- data.tar.gz: '0579da7648101dbdf1f3ca02add8ac87a23192fb2ba635ac6749f87e394d062e'
3
+ metadata.gz: e0b73f48614260bc6e1dc1f0ecebcabe4b5bb44779eb3ba807be3942fd8439fc
4
+ data.tar.gz: 2af43ba19fd5cde723d3dede76fd21eecd17f92d1ad38693702d14fbd85939fa
5
5
  SHA512:
6
- metadata.gz: 1de630e483468ae70fb9e41351f5607fee4516ffea36f9008860a801c7a95c2347d608bf2c6d50c559d302eac7eb0deb2d606cd71e4914e8c8728e09d3bb60d1
7
- data.tar.gz: 6d21e6b3cd38b97122fdf567df30b9d657df3a7787e481ed79343dd691edfd48882b353f96fb3edc2693b7336b67e5c2448ec75bd324dd61c0453708ad5ea7e4
6
+ metadata.gz: 630ec0346571b9f9a35f2a1f319106e4041372a97e4da36980ac24038b2bc8a6f19fc64d6274813834a46a817d148cfdb3961cb9be5a9ede11a20dc7ba543b23
7
+ data.tar.gz: 1c5fa27c4b2bd560bee90fb1461d53a55fc64e380c7df15876b080b17eea315b7dc3290536b3217c758a6929477c2194766e7bb09d363607414f490c3f766d49
data/README.md CHANGED
@@ -124,6 +124,86 @@ foo_post_49:
124
124
  ...
125
125
  ```
126
126
 
127
+ ## Data Sanitizing and Obfuscation
128
+ `FixtureRecord` supports mutating data before writing the data. By default, `FixtureRecord` has a built in sanitizer that is used for `created_at` and `updated_at` fields. The reason for the `simple_timestamp` is that Rails will turn a timestamp into a complex object when calling `to_yaml`.
129
+ ```ruby
130
+ user.attributes.to_yaml
131
+ # =>
132
+ id: ...
133
+ created_at: !ruby/object:ActiveSupport::TimeWithZone
134
+ utc: 2024-03-17 23:11:31.329037000 Z
135
+ zone: &1 !ruby/object:ActiveSupport::TimeZone
136
+ name: Etc/UTC
137
+ time: 2024-03-17 23:11:31.329037000 Z
138
+ updated_at: !ruby/object:ActiveSupport::TimeWithZone
139
+ utc: 2024-03-17 23:11:31.329037000 Z
140
+ zone: *1
141
+ time: 2024-03-17 23:11:31.329037000 Z
142
+ ```
143
+ This type of timestamp structure isn't needed and can simply clutter up a fixture file. So instead, `FixtureRecord` comes with a sanitizer to clean this up.
144
+ ```ruby
145
+ # lib/fixture_record/sanitizers/simple_timestamp
146
+ module FixtureRecord
147
+ module Sanitizers
148
+ class SimpleTimestamp < FixtureRecord::Sanitizer
149
+ def cast(value)
150
+ value.to_s
151
+ end
152
+ end
153
+ FixtureRecord.registry.register_sanitizer(FixtureRecord::Sanitizers::SimpleTimestamp, as: :simple_timestamp)
154
+ end
155
+ end
156
+
157
+ # fixture_record/initializer.rb (created using the install script)
158
+ FixtureRecord.configure do |config|
159
+ ...
160
+
161
+ config.sanitize_pattern /created_at$|updated_at$/, with: :simple_timestamp
162
+
163
+ ...
164
+ end
165
+ ```
166
+
167
+ In this case, any column the regex pattern of 'created_at' or 'updated_at' will have its value passed to the registered sanitizer class.
168
+
169
+ ### Creating a Custom Sanitizer
170
+ Step one, create the custom class. Inheriting from `FixtureRecord::Sanitizer` is not a requirement currently, but there might be some nice-to-have features as part of that class in the future. At minimum, your custom class needs to have at minimum a `#cast` instance method that will receive the value that is to be sanitized and returns the newly converted value. Currently, `#cast` will be called whether the value is `nil` or not, so be sure your method can handle the `nil` scenario.
171
+ ```ruby
172
+ class MyReverseSanitizer < FixtureRecord::Sanitizer
173
+ def cast(value)
174
+ value&.reverse
175
+ end
176
+ end
177
+ ```
178
+
179
+ ### Registering the Sanitizer
180
+ In your custom class, or in the initializer, register the new sanitizer.
181
+ ```ruby
182
+ class MyReverseSanitizer < FixtureRecord::Sanitizer
183
+ ...
184
+ end
185
+
186
+ FixtureRecord.registry.register_sanitizer MyReverseSanitizer, :reverse
187
+ ```
188
+ ### Assiging the Sanitizer to a Pattern
189
+ In the fixture record initializer, use `#sanitize_pattern` to assign the registered sanitizer to a regex pattern. In the following example code, any column that matches `email` would be sent through the reverse sanitizer, this would include `email`, `user_email`, `primary_email`, etc.
190
+ ```ruby
191
+ # fixture_record/initializer.rb
192
+ FixtureRecord.configure do |config|
193
+ ...
194
+
195
+ config.sanitize_pattern /email/, with: :reverse
196
+
197
+ ...
198
+ end
199
+ ```
200
+
201
+ The pattern that is used for comparison is inclusive of the class name as well. So if you need a sanitizer to be scoped to a specific class you can use the class name in the regex pattern. Taking the example above:
202
+ ```ruby
203
+ config.sanitize_pattern /User.email/, with: :reverse
204
+ ```
205
+ Now columns on other classes that include `email` in their name won't be passed to the sanitizer. Also keep in mind the mechanism being used here is basic regex pattern matching, so `User.primary_email` wouldn't match in this case and would not be sent to the sanitizer.
206
+
127
207
  ## Installation
128
208
  `FixtureRecord` is only needed as a development dependency.
129
209
  ```ruby
@@ -2,7 +2,10 @@ module FixtureRecord
2
2
  module AssociationTraversal
3
3
  class UnrecognizedAssociationError < StandardError; end
4
4
 
5
+ attr_accessor :_traversed_fixture_record_associations
6
+
5
7
  def traverse_fixture_record_associations(*associations)
8
+ self._traversed_fixture_record_associations = []
6
9
  associations.each do |association|
7
10
  Builder.new(self, association).build
8
11
  end
@@ -36,8 +39,13 @@ module FixtureRecord
36
39
  def build
37
40
  raise UnrecognizedAssociationError.new(
38
41
  "#{@symbol} is not a recognized association or method on #{@source_record.class}. Is it misspelled?"
39
- ) unless @source_record.respond_to?(@symbol)
42
+ ) unless klass_association.present?
43
+
44
+ if through_assoc_option && @source_record._traversed_fixture_record_associations.exclude?(through_assoc_option)
45
+ infill_through
46
+ end
40
47
 
48
+ @source_record._traversed_fixture_record_associations << @symbol
41
49
  built_records = Array.wrap(@source_record.send(@symbol)).compact_blank
42
50
  return unless built_records.present?
43
51
 
@@ -48,6 +56,17 @@ module FixtureRecord
48
56
  end
49
57
  end
50
58
 
59
+ def infill_through
60
+ SymbolBuilder.new(@source_record, through_assoc_option).build
61
+ end
62
+
63
+ def through_assoc_option
64
+ klass_association.options[:through]
65
+ end
66
+
67
+ def klass_association
68
+ @source_record.class.reflect_on_association(@symbol)
69
+ end
51
70
  end
52
71
 
53
72
  class HashBuilder
@@ -0,0 +1,14 @@
1
+ module FixtureRecord
2
+ class Configuration
3
+ def name_records_with(proc_or_klass)
4
+ FixtureRecord.naming = proc_or_klass.is_a?(Class) ? proc_or_klass.new : proc_or_klass
5
+ end
6
+
7
+ def sanitize_pattern(pattern, with:)
8
+ registry_name_or_klass = with
9
+ klass = registry_name_or_klass.is_a?(Symbol) ? FixtureRecord.registry[registry_name_or_klass] : registry_name_or_klass
10
+ klass_instance = klass.is_a?(Class) ? klass.new : klass
11
+ FixtureRecord.registry.sanitize_pattern pattern, with: klass_instance
12
+ end
13
+ end
14
+ end
@@ -3,8 +3,15 @@ module FixtureRecord
3
3
  attr_accessor :fixture_record_prefix
4
4
  attr_accessor :fixture_record_suffix
5
5
 
6
+ class Base
7
+ def call(record)
8
+
9
+ [record.fixture_record_prefix, record.class.model_name.param_key, record.id || 'new', record.fixture_record_suffix].compact_blank.join('_')
10
+ end
11
+ end
12
+
6
13
  def test_fixture_name
7
- [fixture_record_prefix, self.class.model_name.param_key, (self.id || 'new'), fixture_record_suffix].compact_blank.join '_'
14
+ FixtureRecord.naming.call(self)
8
15
  end
9
16
  end
10
17
  end
@@ -1,9 +1,6 @@
1
1
  module FixtureRecord::Sanitizable
2
2
  extend ActiveSupport::Concern
3
3
 
4
- class_methods do
5
- end
6
-
7
4
  def sanitize_attributes_for_test_fixture
8
5
  _fixture_record_attributes.each do |attr, value|
9
6
  registry_key = [self.class.name, attr.to_s].join('.')
@@ -24,24 +21,27 @@ module FixtureRecord::Sanitizable
24
21
  end
25
22
 
26
23
  class Registry
27
- @_fixture_record_sanitizer_pattern_registry = {}
24
+ @_fixture_record_sanitizer_pattern_registry = []
28
25
  @_fixture_record_sanitizer_name_registry = {}
29
26
 
30
- def self.register_sanitizer(klass, *patterns, as: nil)
31
- if as
32
- @_fixture_record_sanitizer_name_registry[as.to_sym] = klass.new
33
- end
34
- patterns.each do |pattern|
35
- @_fixture_record_sanitizer_pattern_registry[pattern] = klass.new
36
- end
27
+ def self.[](...)
28
+ @_fixture_record_sanitizer_name_registry.send(:[], ...)
29
+ end
30
+
31
+ def self.deregister(klass_or_symbol)
32
+ @_fixture_record_sanitizer_pattern_registry.delete_if { |pattern, with| with == klass_or_symbol }
33
+ end
34
+
35
+ def self.sanitize_pattern(pattern, with:)
36
+ @_fixture_record_sanitizer_pattern_registry << [pattern, with]
37
+ end
38
+
39
+ def self.register_sanitizer(klass, as: nil)
40
+ @_fixture_record_sanitizer_name_registry[as.to_sym] = klass.new
37
41
  end
38
42
 
39
43
  def self.fetch(to_be_matched)
40
- if @_fixture_record_sanitizer_name_registry.key?(to_be_matched)
41
- @_fixture_record_sanitizer_name_registry[to_be_matched]
42
- else
43
- @_fixture_record_sanitizer_pattern_registry.select { |pattern, value| to_be_matched.match(pattern) }.values
44
- end
44
+ @_fixture_record_sanitizer_pattern_registry.select { |pattern, value| to_be_matched.match(pattern) }.map(&:last)
45
45
  end
46
46
  end
47
47
  end
@@ -5,7 +5,6 @@ module FixtureRecord
5
5
  value.to_s
6
6
  end
7
7
  end
8
- FixtureRecord.registry.register_sanitizer(FixtureRecord::Sanitizers::SimpleTimestamp, /created_at$|updated_at$/, as: :simple_timestamp)
8
+ FixtureRecord.registry.register_sanitizer(FixtureRecord::Sanitizers::SimpleTimestamp, as: :simple_timestamp)
9
9
  end
10
10
  end
11
-
@@ -1,3 +1,3 @@
1
1
  module FixtureRecord
2
- VERSION = "0.1.1-rc"
2
+ VERSION = "0.1.2-rc"
3
3
  end
@@ -7,10 +7,15 @@ require "fixture_record/association_traversal"
7
7
  require "fixture_record/filterable_attributes"
8
8
  require "fixture_record/belongs_to_updation"
9
9
  require "fixture_record/sanitizable"
10
+ require "fixture_record/configuration"
10
11
 
11
12
  module FixtureRecord
12
13
  extend ActiveSupport::Concern
13
- mattr_accessor :_locked_by, :cache, :data
14
+ mattr_accessor :_locked_by,
15
+ :cache,
16
+ :data
17
+
18
+ mattr_accessor :naming, default: FixtureRecord::Naming::Base.new
14
19
 
15
20
  included do
16
21
  attr_accessor :_fixture_record_attributes
@@ -33,7 +38,17 @@ module FixtureRecord
33
38
  FixtureRecord.release!(self)
34
39
  end
35
40
 
41
+
36
42
  class << self
43
+ def configure
44
+ yield config
45
+ end
46
+
47
+ def config
48
+ @@config ||= Configuration.new
49
+ end
50
+
51
+
37
52
  def lock!(owner)
38
53
  return if locked?
39
54
 
@@ -4,12 +4,18 @@ module FixtureRecord::Generators
4
4
  class InstallGenerator < ::Rails::Generators::Base
5
5
  source_root File.expand_path("templates", __dir__)
6
6
 
7
- def create_fixture_record_schema
8
- # TODO - implement the generator
9
- end
10
-
11
7
  def create_initializer
12
- template "initializer.rb", Rails.root.join("config/initializers/fixture_record.rb")
8
+ application(nil, env: :development) do
9
+ <<-TXT
10
+ # By default, fixture_record will only inject itself in the development environment.
11
+ # If you want it available in `test` or `production` (or other environments), please add
12
+ # this require line to those environment ruby files. Alternatively, if you want it to
13
+ # always be loaded, you can relocate the generated `fixture_record/initializer.rb` to
14
+ # `app/config/initializers/fixture_record.rb` or require this file in `config/application.rb`.
15
+ require Rails.root.join('fixture_record', 'initializer.rb')\n
16
+ TXT
17
+ end
18
+ template "initializer.rb", Rails.root.join("fixture_record/initializer.rb")
13
19
  end
14
20
  end
15
21
  end
@@ -1,9 +1,16 @@
1
- # FixtureRecord is currently only intended to be loaded in a development environment.
2
- # Change this conditional at your own risk if you want it to load in production.
1
+ FixtureRecord.configure do |config|
2
+ # To customize how fixtures are named, provide a class the responds to #call or a Proc.
3
+ # The naming object will receive the record and should return a String
4
+ # config.name_records_with = FixtureRecord::Naming::Base
3
5
 
4
- if Rails.env.development?
5
- # Inject FixtureRecord after active_record loads
6
- ActiveSupport.on_load(:active_record) do
7
- ActiveRecord::Base.include(FixtureRecord)
8
- end
6
+ # Create and register custom sanitizers to format, sanitiize, obfuscate, etc. the data before it is
7
+ # turned into a test fixture. Regex patterns are used to determine if a column should be passed to a
8
+ # sanitizer. The regex pattern that is tested is Classname.column_name - so if a sanitizer needs to be
9
+ # scoped to a specific class only, simply add the classname to the pattern, for example /User.phone_number/
10
+ # would sanitize the phone_number field for a User but not the phone_number field for a Customer.
11
+ # If there are other timestamp columns being used throughout your application, you can added them to this list.
12
+ config.sanitize_pattern /created_at$|updated_at$/, with: :simple_timestamp
13
+
14
+ # Inject FixtureRecord concern into ActiveRecord
15
+ ActiveRecord::Base.include(FixtureRecord)
9
16
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fixture_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1.pre.rc
4
+ version: 0.1.2.pre.rc
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brad Schrag
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-28 00:00:00.000000000 Z
11
+ date: 2024-03-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -39,6 +39,7 @@ files:
39
39
  - lib/fixture_record/association_traversal.rb
40
40
  - lib/fixture_record/belongs_to_updation.rb
41
41
  - lib/fixture_record/cache.rb
42
+ - lib/fixture_record/configuration.rb
42
43
  - lib/fixture_record/data.rb
43
44
  - lib/fixture_record/filterable_attributes.rb
44
45
  - lib/fixture_record/naming.rb