fixture_farm 1.0.1 → 1.1.2
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 +4 -4
- data/README.md +51 -16
- data/bin/fixture_farm.rb +13 -3
- data/lib/fixture_farm/fixture_recorder.rb +31 -7
- data/lib/fixture_farm/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 205e12a455e71ef917424e9451052b3be1517b11d46f9066a5311d51e889a667
|
4
|
+
data.tar.gz: 360d8805f8844a6a391cf5877f13a9f2433820a6bb94c0d35ee29444ae08b415
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 303bb7ecad05b844de71cbe3a68a814ec70a76b4adfa2eaf570752bf6de253c87c85b2a795ec69d6d0b6a7530753a73033df1d2b45366814846d401528272184
|
7
|
+
data.tar.gz: 6fdb88f7da8c21e4531152b7a1262b951ed0622a000cd27c61b1fc1f47ccebf5b64ca4c1cad1387e02d93612f82c71c0b73a88e7b0c6f33b2bbcf592a4d33d37
|
data/README.md
CHANGED
@@ -55,7 +55,12 @@ include FixtureFarm::ActiveJobHook if defined?(FixtureFarm)
|
|
55
55
|
Then start/stop recording using tasks:
|
56
56
|
|
57
57
|
```bash
|
58
|
-
bundle exec fixture_farm record
|
58
|
+
bundle exec fixture_farm record
|
59
|
+
# OR
|
60
|
+
bundle exec fixture_farm record name_prefix
|
61
|
+
# OR
|
62
|
+
bundle exec fixture_farm record name_prefix:replaces_name
|
63
|
+
|
59
64
|
bundle exec fixture_farm status
|
60
65
|
bundle exec fixture_farm stop
|
61
66
|
```
|
@@ -98,27 +103,63 @@ It's possible to lower the priority of given parent assiciations when it comes t
|
|
98
103
|
FixtureFarm.low_priority_parent_model_for_naming = -> { _1.is_a?(TenantModel) }
|
99
104
|
```
|
100
105
|
|
106
|
+
#### Fixture Name Replacement
|
107
|
+
|
108
|
+
`record_fixtures` also supports hash arguments for advanced fixture naming control:
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
# Replace 'client_1' with 'new_client' in fixture names, or use 'new_client' as prefix if not found
|
112
|
+
record_fixtures(new_client: :client_1) do
|
113
|
+
User.create!(name: 'Test User', email: 'test@example.com')
|
114
|
+
end
|
115
|
+
```
|
116
|
+
|
117
|
+
This works in two ways:
|
118
|
+
- **Replacement**: If a generated fixture name contains `client_1`, it gets replaced with `new_client`
|
119
|
+
- **Prefixing**: If a generated fixture name doesn't contain `client_1`, it gets prefixed with `new_client_`
|
120
|
+
|
121
|
+
For example:
|
122
|
+
- A user fixture that would be named `client_1_user_1` becomes `new_client_user_1` (replacement)
|
123
|
+
- A user fixture that would be named `user_1` becomes `new_client_user_1` (prefixing)
|
124
|
+
|
101
125
|
### Attachment fixtures
|
102
126
|
|
103
|
-
Rather than [manually crafting attachment fixtures](https://guides.rubyonrails.org/v8.0/active_storage_overview.html#adding-attachments-to-fixtures), we can get the gem do the
|
127
|
+
Rather than [manually crafting attachment fixtures](https://guides.rubyonrails.org/v8.0/active_storage_overview.html#adding-attachments-to-fixtures), we can get the gem to do the work. Not only is this less boring, but it's also going to generate variant fixtures.
|
104
128
|
|
105
|
-
|
129
|
+
If we then check the generated blob files into git (along with the fixture files themselves), no attachment processing will be happening in tests or after `rails db:fixtures:load`.
|
106
130
|
|
107
|
-
|
108
|
-
|
109
|
-
|
131
|
+
We'll need a special storage service for the fixture blobs we want to keep versioned. For example:
|
132
|
+
|
133
|
+
```yml
|
134
|
+
# config/storage.yml
|
135
|
+
test_fixtures:
|
136
|
+
service: Disk
|
137
|
+
root: <%= Rails.root.join("test/fixtures/files/active_storage_blobs") %>
|
110
138
|
```
|
111
139
|
|
112
|
-
Now
|
140
|
+
Now a test like the one below is either going to fail if some product fixtures have no attachments, or, if run with `GENERATE_FIXTURES=1`, is going to generate those attachment fixtures, their variant fixtures if needed, along with all the blob files tucked away in a separate (from regular throw away storage) folder that can be checked in:
|
113
141
|
|
114
142
|
```ruby
|
143
|
+
if ENV["GENERATE_FIXTURES"]
|
144
|
+
setup do
|
145
|
+
@original_queue_adapter = ActiveJob::Base.queue_adapter
|
146
|
+
# This is so that variants get generated and blobs analyzed
|
147
|
+
ActiveJob::Base.queue_adapter = :inline
|
148
|
+
|
149
|
+
@original_storage_service = ActiveStorage::Blob.service
|
150
|
+
ActiveStorage::Blob.service = ActiveStorage::Blob.services.fetch(:test_fixtures)
|
151
|
+
end
|
152
|
+
|
153
|
+
teardown do
|
154
|
+
ActiveJob::Base.queue_adapter = @original_queue_adapter
|
155
|
+
ActiveStorage::Blob.service = @original_storage_service
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
115
159
|
test "product fixtures have images" do
|
116
160
|
offending_records = Product.where.missing(:images_attachments)
|
117
161
|
|
118
162
|
if ENV["GENERATE_FIXTURES"]
|
119
|
-
# Makes generation idempotent
|
120
|
-
`git restore --staged storage`
|
121
|
-
|
122
163
|
record_fixtures do |recorder|
|
123
164
|
ActiveStorage::Attachment.where(record_type: 'Product').destroy_all
|
124
165
|
|
@@ -128,13 +169,7 @@ test "product fixtures have images" do
|
|
128
169
|
filename: "#{product.fixture_name}.jpg",
|
129
170
|
content_type: "image/jpeg"
|
130
171
|
)
|
131
|
-
# This generates variants
|
132
|
-
perform_enqueued_jobs
|
133
172
|
end
|
134
|
-
|
135
|
-
recorder.stop!
|
136
|
-
|
137
|
-
`git add -f #{recorder.new_blob_file_paths.join(' ')}`
|
138
173
|
end
|
139
174
|
else
|
140
175
|
assert_empty offending_records.map(&:fixture_name),
|
data/bin/fixture_farm.rb
CHANGED
@@ -4,14 +4,24 @@
|
|
4
4
|
require_relative '../lib/fixture_farm/fixture_recorder'
|
5
5
|
|
6
6
|
def usage
|
7
|
-
puts 'Usage: bundle exec fixture_farm <record|status|stop> [
|
7
|
+
puts 'Usage: bundle exec fixture_farm <record|status|stop> [name_prefix|name_prefix:replaces_name]'
|
8
8
|
exit 1
|
9
9
|
end
|
10
10
|
|
11
11
|
case ARGV[0]
|
12
12
|
when 'record'
|
13
|
-
|
14
|
-
|
13
|
+
prefix_arg = ARGV[1]
|
14
|
+
|
15
|
+
# Parse hash syntax like "new_user:user_1" into {new_user: :user_1}
|
16
|
+
if prefix_arg&.include?(':')
|
17
|
+
parts = prefix_arg.split(':', 2)
|
18
|
+
parsed_prefix = { parts[0].to_sym => parts[1].to_sym }
|
19
|
+
else
|
20
|
+
parsed_prefix = prefix_arg
|
21
|
+
end
|
22
|
+
|
23
|
+
FixtureFarm::FixtureRecorder.start_recording_session!(parsed_prefix)
|
24
|
+
puts "Recording fixtures#{" with prefix #{prefix_arg}" unless prefix_arg.nil?}"
|
15
25
|
when 'status'
|
16
26
|
if FixtureFarm::FixtureRecorder.recording_session_in_progress?
|
17
27
|
puts 'Recording is on'
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module FixtureFarm
|
4
|
-
|
5
4
|
mattr_accessor :low_priority_parent_model_for_naming
|
6
5
|
|
7
6
|
class FixtureRecorder
|
@@ -16,7 +15,13 @@ module FixtureFarm
|
|
16
15
|
end
|
17
16
|
|
18
17
|
def initialize(fixture_name_prefix, new_models = [])
|
19
|
-
|
18
|
+
if fixture_name_prefix.is_a?(Hash)
|
19
|
+
@fixture_name_replacements = fixture_name_prefix
|
20
|
+
@fixture_name_prefix = nil
|
21
|
+
else
|
22
|
+
@fixture_name_prefix = fixture_name_prefix
|
23
|
+
@fixture_name_replacements = {}
|
24
|
+
end
|
20
25
|
@new_models = new_models
|
21
26
|
@deleted_models = {}
|
22
27
|
@initial_now = Time.zone.now
|
@@ -95,9 +100,11 @@ module FixtureFarm
|
|
95
100
|
end
|
96
101
|
end
|
97
102
|
|
98
|
-
yield self
|
103
|
+
result = yield self
|
99
104
|
|
100
105
|
stop! unless @stopped
|
106
|
+
|
107
|
+
result
|
101
108
|
ensure
|
102
109
|
ActiveSupport::Notifications.unsubscribe(@subscriber)
|
103
110
|
end
|
@@ -144,8 +151,10 @@ module FixtureFarm
|
|
144
151
|
|
145
152
|
blob.update!(key: new_key)
|
146
153
|
|
147
|
-
|
148
|
-
|
154
|
+
blobs_root_path = Pathname.new(ActiveStorage::Blob.service.root)
|
155
|
+
|
156
|
+
from_path = blobs_root_path.join(old_key[0..1], old_key[2..3], old_key)
|
157
|
+
to_dir = blobs_root_path.join(new_key[0..1], new_key[2..3])
|
149
158
|
to_path = to_dir.join(new_key)
|
150
159
|
|
151
160
|
`mkdir -p #{to_dir}`
|
@@ -257,6 +266,8 @@ module FixtureFarm
|
|
257
266
|
value.to_f
|
258
267
|
when Hash
|
259
268
|
value.to_json
|
269
|
+
when IPAddr
|
270
|
+
value.to_s
|
260
271
|
else
|
261
272
|
value
|
262
273
|
end
|
@@ -366,12 +377,25 @@ module FixtureFarm
|
|
366
377
|
fixture_name(model_instance) || begin
|
367
378
|
existing_fixtures = existing_fixtures_for_model(model_instance)
|
368
379
|
|
369
|
-
|
380
|
+
base_name = [
|
370
381
|
first_belongs_to_fixture_name(model_instance).presence || @fixture_name_prefix,
|
371
382
|
"#{model_instance.class.name.underscore.split('/').last}_1"
|
372
383
|
].select(&:present?).join('_')
|
373
384
|
|
374
|
-
|
385
|
+
@fixture_name_replacements.each do |new_name, old_name|
|
386
|
+
# Only apply replacement if the base_name doesn't already start with new_name
|
387
|
+
# This prevents double-application of replacements
|
388
|
+
next if base_name.start_with?("#{new_name}_")
|
389
|
+
|
390
|
+
original_name = base_name
|
391
|
+
base_name = base_name.gsub(/\b#{Regexp.escape(old_name.to_s)}\b/, new_name.to_s)
|
392
|
+
|
393
|
+
# If no replacement occurred, use new_name as prefix
|
394
|
+
base_name = "#{new_name}_#{base_name}" if base_name == original_name
|
395
|
+
end
|
396
|
+
|
397
|
+
new_fixture_name = base_name
|
398
|
+
while @named_new_fixtures[new_fixture_name] || (existing_fixtures[new_fixture_name] && !@deleted_models[new_fixture_name])
|
375
399
|
new_fixture_name = new_fixture_name.sub(/_(\d+)$/, "_#{Regexp.last_match(1).to_i + 1}")
|
376
400
|
end
|
377
401
|
|
data/lib/fixture_farm/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fixture_farm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- artemave
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-08-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|