fixture_record 0.1.1.pre.rc → 0.1.2.pre.rc
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +80 -0
- data/lib/fixture_record/association_traversal.rb +20 -1
- data/lib/fixture_record/configuration.rb +14 -0
- data/lib/fixture_record/naming.rb +8 -1
- data/lib/fixture_record/sanitizable.rb +16 -16
- data/lib/fixture_record/sanitizers/simple_timestamp.rb +1 -2
- data/lib/fixture_record/version.rb +1 -1
- data/lib/fixture_record.rb +16 -1
- data/lib/generators/fixture_record/install/install_generator.rb +11 -5
- data/lib/generators/fixture_record/install/templates/initializer.rb +14 -7
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0b73f48614260bc6e1dc1f0ecebcabe4b5bb44779eb3ba807be3942fd8439fc
|
4
|
+
data.tar.gz: 2af43ba19fd5cde723d3dede76fd21eecd17f92d1ad38693702d14fbd85939fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
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
|
-
|
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.
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
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,
|
8
|
+
FixtureRecord.registry.register_sanitizer(FixtureRecord::Sanitizers::SimpleTimestamp, as: :simple_timestamp)
|
9
9
|
end
|
10
10
|
end
|
11
|
-
|
data/lib/fixture_record.rb
CHANGED
@@ -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,
|
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
|
-
|
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
|
-
|
2
|
-
#
|
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
|
-
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
|
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.
|
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-
|
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
|