fixtures_from_factories 0.1.0
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 +7 -0
- data/.standard.yml +3 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +208 -0
- data/LICENSE.txt +21 -0
- data/README.md +124 -0
- data/Rakefile +14 -0
- data/lib/fixtures_from_factories/base_builder.rb +17 -0
- data/lib/fixtures_from_factories/fixture_generator.rb +339 -0
- data/lib/fixtures_from_factories/generate_set.rb +53 -0
- data/lib/fixtures_from_factories/railtie.rb +7 -0
- data/lib/fixtures_from_factories/version.rb +5 -0
- data/lib/fixtures_from_factories.rb +32 -0
- data/sig/fixtures_from_factories.rbs +4 -0
- metadata +131 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 71e768e6b219f669c71efecbe203f358e3ab3db484045d49e297c3b6b3845f47
|
|
4
|
+
data.tar.gz: 3a18e1072c46a3d585b954e2b259ebf2ca1fbc9710f7c9e3a7ad39cdb59d912c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: b607d62ff84ecf91222176ec430289057dc9075d4c5a102b69aa4a404687c4b1b768a32546dcb43d142c8667bff61bea86503bdd8cf9409581ac1ba825252299
|
|
7
|
+
data.tar.gz: 2b5fa3d3e23f2f3b1f7f67807ba52904476b66fb4f1ebcfefa50b55abf68238e43c204ed27b7b3009efe663b11dfa6934c27c5c11563c24236640f23cb6cb776
|
data/.standard.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source "https://rubygems.org"
|
|
4
|
+
|
|
5
|
+
# Specify your gem's dependencies in fixtures_from_factories.gemspec
|
|
6
|
+
gemspec
|
|
7
|
+
|
|
8
|
+
gem "sqlite3"
|
|
9
|
+
|
|
10
|
+
gem "puma"
|
|
11
|
+
|
|
12
|
+
gem "rake", "~> 13.0"
|
|
13
|
+
|
|
14
|
+
gem "minitest", "~> 5.0"
|
|
15
|
+
|
|
16
|
+
gem "standard", "~> 1.3"
|
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
fixtures_from_factories (0.1.0)
|
|
5
|
+
devise
|
|
6
|
+
factory_bot
|
|
7
|
+
faker
|
|
8
|
+
rails (>= 6)
|
|
9
|
+
timecop
|
|
10
|
+
|
|
11
|
+
GEM
|
|
12
|
+
remote: https://rubygems.org/
|
|
13
|
+
specs:
|
|
14
|
+
actioncable (7.0.4)
|
|
15
|
+
actionpack (= 7.0.4)
|
|
16
|
+
activesupport (= 7.0.4)
|
|
17
|
+
nio4r (~> 2.0)
|
|
18
|
+
websocket-driver (>= 0.6.1)
|
|
19
|
+
actionmailbox (7.0.4)
|
|
20
|
+
actionpack (= 7.0.4)
|
|
21
|
+
activejob (= 7.0.4)
|
|
22
|
+
activerecord (= 7.0.4)
|
|
23
|
+
activestorage (= 7.0.4)
|
|
24
|
+
activesupport (= 7.0.4)
|
|
25
|
+
mail (>= 2.7.1)
|
|
26
|
+
net-imap
|
|
27
|
+
net-pop
|
|
28
|
+
net-smtp
|
|
29
|
+
actionmailer (7.0.4)
|
|
30
|
+
actionpack (= 7.0.4)
|
|
31
|
+
actionview (= 7.0.4)
|
|
32
|
+
activejob (= 7.0.4)
|
|
33
|
+
activesupport (= 7.0.4)
|
|
34
|
+
mail (~> 2.5, >= 2.5.4)
|
|
35
|
+
net-imap
|
|
36
|
+
net-pop
|
|
37
|
+
net-smtp
|
|
38
|
+
rails-dom-testing (~> 2.0)
|
|
39
|
+
actionpack (7.0.4)
|
|
40
|
+
actionview (= 7.0.4)
|
|
41
|
+
activesupport (= 7.0.4)
|
|
42
|
+
rack (~> 2.0, >= 2.2.0)
|
|
43
|
+
rack-test (>= 0.6.3)
|
|
44
|
+
rails-dom-testing (~> 2.0)
|
|
45
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
|
46
|
+
actiontext (7.0.4)
|
|
47
|
+
actionpack (= 7.0.4)
|
|
48
|
+
activerecord (= 7.0.4)
|
|
49
|
+
activestorage (= 7.0.4)
|
|
50
|
+
activesupport (= 7.0.4)
|
|
51
|
+
globalid (>= 0.6.0)
|
|
52
|
+
nokogiri (>= 1.8.5)
|
|
53
|
+
actionview (7.0.4)
|
|
54
|
+
activesupport (= 7.0.4)
|
|
55
|
+
builder (~> 3.1)
|
|
56
|
+
erubi (~> 1.4)
|
|
57
|
+
rails-dom-testing (~> 2.0)
|
|
58
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
|
59
|
+
activejob (7.0.4)
|
|
60
|
+
activesupport (= 7.0.4)
|
|
61
|
+
globalid (>= 0.3.6)
|
|
62
|
+
activemodel (7.0.4)
|
|
63
|
+
activesupport (= 7.0.4)
|
|
64
|
+
activerecord (7.0.4)
|
|
65
|
+
activemodel (= 7.0.4)
|
|
66
|
+
activesupport (= 7.0.4)
|
|
67
|
+
activestorage (7.0.4)
|
|
68
|
+
actionpack (= 7.0.4)
|
|
69
|
+
activejob (= 7.0.4)
|
|
70
|
+
activerecord (= 7.0.4)
|
|
71
|
+
activesupport (= 7.0.4)
|
|
72
|
+
marcel (~> 1.0)
|
|
73
|
+
mini_mime (>= 1.1.0)
|
|
74
|
+
activesupport (7.0.4)
|
|
75
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
76
|
+
i18n (>= 1.6, < 2)
|
|
77
|
+
minitest (>= 5.1)
|
|
78
|
+
tzinfo (~> 2.0)
|
|
79
|
+
ast (2.4.2)
|
|
80
|
+
bcrypt (3.1.18)
|
|
81
|
+
builder (3.2.4)
|
|
82
|
+
concurrent-ruby (1.1.10)
|
|
83
|
+
crass (1.0.6)
|
|
84
|
+
devise (4.8.1)
|
|
85
|
+
bcrypt (~> 3.0)
|
|
86
|
+
orm_adapter (~> 0.1)
|
|
87
|
+
railties (>= 4.1.0)
|
|
88
|
+
responders
|
|
89
|
+
warden (~> 1.2.3)
|
|
90
|
+
erubi (1.11.0)
|
|
91
|
+
factory_bot (6.2.1)
|
|
92
|
+
activesupport (>= 5.0.0)
|
|
93
|
+
faker (2.21.0)
|
|
94
|
+
i18n (>= 1.8.11, < 2)
|
|
95
|
+
globalid (1.0.0)
|
|
96
|
+
activesupport (>= 5.0)
|
|
97
|
+
i18n (1.12.0)
|
|
98
|
+
concurrent-ruby (~> 1.0)
|
|
99
|
+
json (2.6.2)
|
|
100
|
+
loofah (2.19.0)
|
|
101
|
+
crass (~> 1.0.2)
|
|
102
|
+
nokogiri (>= 1.5.9)
|
|
103
|
+
mail (2.7.1)
|
|
104
|
+
mini_mime (>= 0.1.1)
|
|
105
|
+
marcel (1.0.2)
|
|
106
|
+
method_source (1.0.0)
|
|
107
|
+
mini_mime (1.1.2)
|
|
108
|
+
minitest (5.16.3)
|
|
109
|
+
net-imap (0.3.1)
|
|
110
|
+
net-protocol
|
|
111
|
+
net-pop (0.1.2)
|
|
112
|
+
net-protocol
|
|
113
|
+
net-protocol (0.1.3)
|
|
114
|
+
timeout
|
|
115
|
+
net-smtp (0.3.3)
|
|
116
|
+
net-protocol
|
|
117
|
+
nio4r (2.5.8)
|
|
118
|
+
nokogiri (1.13.9-x86_64-darwin)
|
|
119
|
+
racc (~> 1.4)
|
|
120
|
+
orm_adapter (0.5.0)
|
|
121
|
+
parallel (1.22.1)
|
|
122
|
+
parser (3.1.2.1)
|
|
123
|
+
ast (~> 2.4.1)
|
|
124
|
+
puma (6.0.0)
|
|
125
|
+
nio4r (~> 2.0)
|
|
126
|
+
racc (1.6.0)
|
|
127
|
+
rack (2.2.4)
|
|
128
|
+
rack-test (2.0.2)
|
|
129
|
+
rack (>= 1.3)
|
|
130
|
+
rails (7.0.4)
|
|
131
|
+
actioncable (= 7.0.4)
|
|
132
|
+
actionmailbox (= 7.0.4)
|
|
133
|
+
actionmailer (= 7.0.4)
|
|
134
|
+
actionpack (= 7.0.4)
|
|
135
|
+
actiontext (= 7.0.4)
|
|
136
|
+
actionview (= 7.0.4)
|
|
137
|
+
activejob (= 7.0.4)
|
|
138
|
+
activemodel (= 7.0.4)
|
|
139
|
+
activerecord (= 7.0.4)
|
|
140
|
+
activestorage (= 7.0.4)
|
|
141
|
+
activesupport (= 7.0.4)
|
|
142
|
+
bundler (>= 1.15.0)
|
|
143
|
+
railties (= 7.0.4)
|
|
144
|
+
rails-dom-testing (2.0.3)
|
|
145
|
+
activesupport (>= 4.2.0)
|
|
146
|
+
nokogiri (>= 1.6)
|
|
147
|
+
rails-html-sanitizer (1.4.3)
|
|
148
|
+
loofah (~> 2.3)
|
|
149
|
+
railties (7.0.4)
|
|
150
|
+
actionpack (= 7.0.4)
|
|
151
|
+
activesupport (= 7.0.4)
|
|
152
|
+
method_source
|
|
153
|
+
rake (>= 12.2)
|
|
154
|
+
thor (~> 1.0)
|
|
155
|
+
zeitwerk (~> 2.5)
|
|
156
|
+
rainbow (3.1.1)
|
|
157
|
+
rake (13.0.6)
|
|
158
|
+
regexp_parser (2.6.0)
|
|
159
|
+
responders (3.0.1)
|
|
160
|
+
actionpack (>= 5.0)
|
|
161
|
+
railties (>= 5.0)
|
|
162
|
+
rexml (3.2.5)
|
|
163
|
+
rubocop (1.39.0)
|
|
164
|
+
json (~> 2.3)
|
|
165
|
+
parallel (~> 1.10)
|
|
166
|
+
parser (>= 3.1.2.1)
|
|
167
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
168
|
+
regexp_parser (>= 1.8, < 3.0)
|
|
169
|
+
rexml (>= 3.2.5, < 4.0)
|
|
170
|
+
rubocop-ast (>= 1.23.0, < 2.0)
|
|
171
|
+
ruby-progressbar (~> 1.7)
|
|
172
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
|
173
|
+
rubocop-ast (1.23.0)
|
|
174
|
+
parser (>= 3.1.1.0)
|
|
175
|
+
rubocop-performance (1.15.0)
|
|
176
|
+
rubocop (>= 1.7.0, < 2.0)
|
|
177
|
+
rubocop-ast (>= 0.4.0)
|
|
178
|
+
ruby-progressbar (1.11.0)
|
|
179
|
+
sqlite3 (1.5.4-x86_64-darwin)
|
|
180
|
+
standard (1.18.0)
|
|
181
|
+
rubocop (= 1.39.0)
|
|
182
|
+
rubocop-performance (= 1.15.0)
|
|
183
|
+
thor (1.2.1)
|
|
184
|
+
timecop (0.9.5)
|
|
185
|
+
timeout (0.3.0)
|
|
186
|
+
tzinfo (2.0.5)
|
|
187
|
+
concurrent-ruby (~> 1.0)
|
|
188
|
+
unicode-display_width (2.3.0)
|
|
189
|
+
warden (1.2.9)
|
|
190
|
+
rack (>= 2.0.9)
|
|
191
|
+
websocket-driver (0.7.5)
|
|
192
|
+
websocket-extensions (>= 0.1.0)
|
|
193
|
+
websocket-extensions (0.1.5)
|
|
194
|
+
zeitwerk (2.6.6)
|
|
195
|
+
|
|
196
|
+
PLATFORMS
|
|
197
|
+
x86_64-darwin-21
|
|
198
|
+
|
|
199
|
+
DEPENDENCIES
|
|
200
|
+
fixtures_from_factories!
|
|
201
|
+
minitest (~> 5.0)
|
|
202
|
+
puma
|
|
203
|
+
rake (~> 13.0)
|
|
204
|
+
sqlite3
|
|
205
|
+
standard (~> 1.3)
|
|
206
|
+
|
|
207
|
+
BUNDLED WITH
|
|
208
|
+
2.3.19
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Stephen Ierodiaconou
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# FixturesFromFactories
|
|
2
|
+
|
|
3
|
+
A tool to help build a set of Fixtures for your Rails app, using your test suite's FactoryBot factories.
|
|
4
|
+
|
|
5
|
+
## Why?
|
|
6
|
+
|
|
7
|
+
So you can build a full set of "fake data" for your development environment or for your QA/demo or test environments.
|
|
8
|
+
|
|
9
|
+
Instead of manually maintaining a set of fixtures you can write a script which uses you existing Factories to
|
|
10
|
+
build out the data set. Ie we generate fixture files from a script which uses FactoryBot factories to define the setup.
|
|
11
|
+
|
|
12
|
+
`FixturesFromFactories` sets up a clean DB, runs your setup script, and then dumps records to fixture YAML files!
|
|
13
|
+
|
|
14
|
+
Your Fixtures can then be very quickly loaded into the database to setup a new dev env with data to work with, or
|
|
15
|
+
reset a demo environment between demos to prospective clients.
|
|
16
|
+
|
|
17
|
+
Features:
|
|
18
|
+
- TODO
|
|
19
|
+
|
|
20
|
+
## Prior art (`fixture-builder` gem)
|
|
21
|
+
|
|
22
|
+
The logic to dump the entities to YAML is based partly on [fixture-builder](https://github.com/rdy/fixture_builder).
|
|
23
|
+
|
|
24
|
+
Big thanks to the many contributors to that project.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
Install the gem and add to the application's Gemfile by executing:
|
|
30
|
+
|
|
31
|
+
$ bundle add fixtures_from_factories
|
|
32
|
+
|
|
33
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
|
34
|
+
|
|
35
|
+
$ gem install fixtures_from_factories
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
Write a script (rake task or otherwise) which calls `GenerateSet` and gives it the name of a class which exposes
|
|
40
|
+
a "generate" method. This class should be a subclass of `FixturesFromFactories::BaseBuilder` and should
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
FixturesFromFactories::GenerateSet.call(
|
|
44
|
+
DemoFixturesBuilder, # The custom class which will setup the data
|
|
45
|
+
fixtures_path, # path to the directory where the fixtures will be written, eg Rails.root.join("demos", "fixtures")
|
|
46
|
+
time_cop_now: [Time.zone.now], # The time to freeze "now" to
|
|
47
|
+
faker_seed: 42, # A seed value for faker to ensure consistent data between runs
|
|
48
|
+
options: { # Any options to pass to the data builder class, available as `options` in the builder class
|
|
49
|
+
# ...
|
|
50
|
+
}
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The `DemoFixturesBuilder` class should look something like this:
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
class DemoFixturesBuilder < FixturesFromFactories::BaseBuilder
|
|
58
|
+
def generate
|
|
59
|
+
# Add data that was seeded (already in newly created database) to fixtures
|
|
60
|
+
# Here the Category records will be added with names "category_<id>"
|
|
61
|
+
generator.add_collection(Category.all)
|
|
62
|
+
# Here the tag records will be added with names "tag_<name attribute parameterized and underscored>"
|
|
63
|
+
# eg a Tag(name: "Foo Bar") will be added as "tag_foo_bar"
|
|
64
|
+
generator.add_collection(Tag.all) { |t| t.name.parameterize.underscore }
|
|
65
|
+
|
|
66
|
+
# Setup for tables with no primary key ID (eg joins tables), note must have an AR model class
|
|
67
|
+
generator.configure_name(CategoriesPosts, :category_id, :post_id)
|
|
68
|
+
|
|
69
|
+
# Create an author
|
|
70
|
+
author = generator.create(
|
|
71
|
+
:first_author, # name of the fixture
|
|
72
|
+
:user, # factory name
|
|
73
|
+
:with_comments, # optional traits
|
|
74
|
+
first_name: "John", # optional attributes
|
|
75
|
+
last_name: "Doe"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Create 6 blog posts for the author - will be named "first_author_post_1", "first_author_post_2", etc
|
|
79
|
+
generator.create_multiple(:first_author_post, :post, 1, 6) do |post_index|
|
|
80
|
+
# from the block return the attributes for the factory
|
|
81
|
+
{
|
|
82
|
+
author: author, # or generator.get(:first_author)
|
|
83
|
+
text: Faker::Lorem.paragraphs(number: 3).join("\n\n"),
|
|
84
|
+
published_at: generator.make_fake_time(post_index.days.ago, (post_index - 1).days.ago)
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
generator.create(
|
|
89
|
+
:category_to_post,
|
|
90
|
+
:categories_post,
|
|
91
|
+
category: generator.get(:category_12), # You can get a previously created record using its name
|
|
92
|
+
post: generator.get(:first_author_post_1)
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# ... etc
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
To load the generated fixtures to your DB
|
|
102
|
+
|
|
103
|
+
rake db:fixtures:load FIXTURES_PATH=demos/fixtures
|
|
104
|
+
|
|
105
|
+
*NOTE:* if you are adding something where the records have no primary 'id' key (eg on HABTM joins table) you must
|
|
106
|
+
specify the columns to use when comparing records in the generator. Ie you must specify a set of attributes
|
|
107
|
+
which uniquely identify each row (for example in a join table the pair of IDs in the row). This is done in
|
|
108
|
+
`TestFixturesGenerators::Index` at the start of the model generation process.
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
## Development
|
|
113
|
+
|
|
114
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
115
|
+
|
|
116
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
117
|
+
|
|
118
|
+
## Contributing
|
|
119
|
+
|
|
120
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/fixtures_from_factories.
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/gem_tasks"
|
|
4
|
+
require "rake/testtask"
|
|
5
|
+
|
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
|
7
|
+
t.libs << "test"
|
|
8
|
+
t.libs << "lib"
|
|
9
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
require "standard/rake"
|
|
13
|
+
|
|
14
|
+
task default: %i[test standard]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FixturesFromFactories
|
|
4
|
+
class BaseBuilder
|
|
5
|
+
def initialize(generator, rand_seed, options)
|
|
6
|
+
@generator = generator
|
|
7
|
+
@rand_seed = rand_seed
|
|
8
|
+
@options = options
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
attr_reader :generator, :options
|
|
12
|
+
|
|
13
|
+
def generate
|
|
14
|
+
raise NotImplementedError
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "factory_bot"
|
|
4
|
+
require "faker"
|
|
5
|
+
|
|
6
|
+
module FixturesFromFactories
|
|
7
|
+
class FixtureGenerator
|
|
8
|
+
attr_reader :model_cache, :name_config, :excluded_tables, :output_path
|
|
9
|
+
|
|
10
|
+
def initialize(
|
|
11
|
+
output_path,
|
|
12
|
+
excluded_tables = FixturesFromFactories.configuration.excluded_tables
|
|
13
|
+
)
|
|
14
|
+
@model_cache = {}
|
|
15
|
+
@name_config = {}
|
|
16
|
+
@output_path = output_path
|
|
17
|
+
@excluded_tables = excluded_tables
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def generate(&blk)
|
|
21
|
+
instance_eval(&blk)
|
|
22
|
+
dump_tables
|
|
23
|
+
dump_record_index
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Record creation DSL
|
|
27
|
+
|
|
28
|
+
# Create a single named record using FactoryBot
|
|
29
|
+
def create(name_or_prefix, factory_or_index, *bot_args)
|
|
30
|
+
item_name, factory =
|
|
31
|
+
if factory_or_index.is_a?(Symbol) || factory_or_index.is_a?(Array)
|
|
32
|
+
[name_or_prefix, factory_or_index]
|
|
33
|
+
else
|
|
34
|
+
["#{name_or_prefix}_#{factory_or_index}".to_sym, bot_args.shift]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
Rails.logger.info "Creating record: #{item_name}"
|
|
38
|
+
record = FactoryBot.create(*(Array.wrap(factory) + bot_args))
|
|
39
|
+
if record.nil? || !record.persisted?
|
|
40
|
+
raise StandardError, "A record failed to save, #{record.class.name}, #{bot_args}"
|
|
41
|
+
end
|
|
42
|
+
add_record(item_name, record)
|
|
43
|
+
record
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Create multiple records from factory within index range, where the name has the index appended
|
|
47
|
+
def create_multiple(name, factory, start_index, end_index, items = nil)
|
|
48
|
+
(start_index..end_index).map.with_index do |instance_num, index|
|
|
49
|
+
bot_args = block_given? ? yield(instance_num) : items&.at(index)
|
|
50
|
+
create(name, instance_num, factory, bot_args)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def create_multiple_with_names(name_prefix, factory, names, items = nil)
|
|
55
|
+
names.map.with_index do |config, index|
|
|
56
|
+
parts = config.is_a?(Hash) ? config[:names] : config
|
|
57
|
+
n_index = Array.wrap(parts).map { |s| s.to_s.parameterize.underscore }.join("_").to_sym
|
|
58
|
+
n = "#{name_prefix}_#{n_index}".to_sym
|
|
59
|
+
bot_args = block_given? ? yield(n, n_index, config, index) : items&.at(index)
|
|
60
|
+
create(n, factory, bot_args)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Get an existing record
|
|
65
|
+
def get(name, index = nil)
|
|
66
|
+
model_cache.fetch(index.present? ? "#{name}_#{index}".to_sym : name)[:record]
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def generate_name_from_humanized(model, *parts)
|
|
70
|
+
"#{model}_#{parts.map { |s| s.to_s.parameterize.underscore }.join("_")}".to_sym
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Setup naming logic for a specific table
|
|
74
|
+
def configure_name(model_klass, *attrs)
|
|
75
|
+
name_config[model_klass.name] = {klass: model_klass, attrs: attrs}
|
|
76
|
+
name_config[model_klass.name] = ->(record, other) do
|
|
77
|
+
attrs.all? { |attr| record.attributes[attr.to_s] == other[attr.to_s] }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def add_record(item_name, record)
|
|
82
|
+
raise "Adding nil record! #{item_name}" if record.nil?
|
|
83
|
+
Rails.logger.info "Adding record #{item_name}..."
|
|
84
|
+
model_cache.merge!({item_name => cached_record(record)}) do |key|
|
|
85
|
+
raise "Duplicate key: #{key}"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def add_collection(collection, collection_name: nil)
|
|
90
|
+
c_name = collection_name || collection.name.underscore
|
|
91
|
+
added_count = 0
|
|
92
|
+
collection.find_in_batches do |group|
|
|
93
|
+
group.each do |model|
|
|
94
|
+
id = block_given? ? yield(model) : model.id.to_s
|
|
95
|
+
name = "#{c_name}_#{id}".to_sym
|
|
96
|
+
add_record(name, model)
|
|
97
|
+
added_count += 1
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
added_count
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def make_fake_time(from, to)
|
|
104
|
+
Faker::Time.between(from: from.utc, to: to.utc).utc
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
def dump_record_index
|
|
110
|
+
path = File.join(output_path, "record_index.txt")
|
|
111
|
+
File.open(File.expand_path(path), "w") do |file|
|
|
112
|
+
file.write "# ----------------------------------------------------------------------------\n"
|
|
113
|
+
file.write "# Do not edit this file manually! It is generated by ./db/generate_fixtures.rb\n"
|
|
114
|
+
file.write "# ----------------------------------------------------------------------------\n"
|
|
115
|
+
file.write model_cache.keys.join("\n")
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def cached_record(record)
|
|
120
|
+
{
|
|
121
|
+
record: record,
|
|
122
|
+
klass: record.class,
|
|
123
|
+
comparison: ->(record, other) do
|
|
124
|
+
if name_config[record.class.name]
|
|
125
|
+
name_config[record.class.name].call(record, other)
|
|
126
|
+
elsif record.id.present?
|
|
127
|
+
record.id.to_s == other["id"]&.to_s
|
|
128
|
+
else
|
|
129
|
+
raise StandardError,
|
|
130
|
+
"You maybe missing a call to `configure_name` for a table without a primary id key"
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
}
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def class_from_table(table_name)
|
|
137
|
+
table_name.classify.constantize
|
|
138
|
+
rescue
|
|
139
|
+
nil
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def get_record_name(needle, table_name)
|
|
143
|
+
generate_record_name(needle, table_name, nil)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Based on https://github.com/rdy/fixture_builder
|
|
147
|
+
def generate_record_name(needle, table_name, row_index)
|
|
148
|
+
table_klass = class_from_table(table_name)
|
|
149
|
+
generated_name =
|
|
150
|
+
if table_klass
|
|
151
|
+
generate_record_name_with_model(needle, table_klass, row_index)
|
|
152
|
+
elsif row_index
|
|
153
|
+
[table_name, row_index.succ!].join("_")
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
generated_name&.to_s
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def generate_record_name_with_model(needle, table_klass, row_index)
|
|
160
|
+
found_name = get_record_name_from_cache(needle, table_klass)
|
|
161
|
+
if found_name.present?
|
|
162
|
+
found_name
|
|
163
|
+
elsif row_index
|
|
164
|
+
[table_klass.name, row_index.succ!].join("_")
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def get_record_name_from_cache(needle, table_klass)
|
|
169
|
+
# Check if the model is in the cache and get its name, otherwise generate a name from a sequence
|
|
170
|
+
# Note if row_index is not set and the model isnt in the cache (ie it was not explicitly created by us) then
|
|
171
|
+
# nil is returned
|
|
172
|
+
klasses = [table_klass]
|
|
173
|
+
klasses.concat(table_klass.subclasses) if table_klass.subclasses.present?
|
|
174
|
+
found_name =
|
|
175
|
+
model_cache.find do |_key, cached|
|
|
176
|
+
klasses.include?(cached[:klass]) && cached[:comparison].call(cached[:record], needle)
|
|
177
|
+
end
|
|
178
|
+
found_name&.first
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Taken from https://github.com/rdy/fixture_builder
|
|
182
|
+
def tables
|
|
183
|
+
ActiveRecord::Base.connection.tables - excluded_tables
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Based on https://github.com/rdy/fixture_builder but we replace references with a named reference and let Rails
|
|
187
|
+
# generate stable IDs. In cases where a record has been created indirectly by a factory (and not explicity by this
|
|
188
|
+
# generator) it will stay as a reference with a hardcoded ID
|
|
189
|
+
def dump_tables
|
|
190
|
+
default_date_format = Date::DATE_FORMATS[:default]
|
|
191
|
+
Date::DATE_FORMATS[:default] = Date::DATE_FORMATS[:db]
|
|
192
|
+
begin
|
|
193
|
+
fixtures =
|
|
194
|
+
tables.inject([]) do |files, table_name|
|
|
195
|
+
rows = process_table(table_name)
|
|
196
|
+
next files if rows.empty?
|
|
197
|
+
|
|
198
|
+
fixture_data = prepare_fixture_data(rows, table_name)
|
|
199
|
+
write_fixture_file(fixture_data, table_name)
|
|
200
|
+
files + [File.basename(fixture_file(table_name))]
|
|
201
|
+
end
|
|
202
|
+
ensure
|
|
203
|
+
Date::DATE_FORMATS[:default] = default_date_format
|
|
204
|
+
end
|
|
205
|
+
Rails.logger.info "Built #{fixtures.to_sentence}"
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def process_table(table_name)
|
|
209
|
+
table_klass = class_from_table(table_name)
|
|
210
|
+
if table_klass && table_klass < ActiveRecord::Base
|
|
211
|
+
process_table_with_model(table_klass)
|
|
212
|
+
else
|
|
213
|
+
process_table_without_model(table_name)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def process_table_with_model(table_klass)
|
|
218
|
+
table_klass.unscoped do
|
|
219
|
+
table_klass.all.map do |obj|
|
|
220
|
+
attrs = obj.attributes.select { |attr_name| table_klass.column_names.include?(attr_name) }
|
|
221
|
+
attrs.each_with_object({}) do |(attr_name, value), hash|
|
|
222
|
+
replace_association_with_named(table_klass, attrs, hash, attr_name, value)
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Some records are
|
|
229
|
+
def replace_association_with_named(table_klass, attrs, hash, attr_name, value)
|
|
230
|
+
# If the record attribute is a relation, then get the other model name and use it instead of a ID value
|
|
231
|
+
# but only if there is a AR model for the table
|
|
232
|
+
attr_name_without_id = attr_name.sub(/_id$/, "")
|
|
233
|
+
reflection = table_klass.reflect_on_association(attr_name_without_id)
|
|
234
|
+
if reflection&.kind_of?(ActiveRecord::Reflection::AssociationReflection) && value.present?
|
|
235
|
+
related_klass_name =
|
|
236
|
+
begin
|
|
237
|
+
# Polymorphic
|
|
238
|
+
association_type = attrs[attr_name_without_id + "_type"]
|
|
239
|
+
association_type.presence || reflection.class_name
|
|
240
|
+
end
|
|
241
|
+
other_name = get_record_name({"id" => value}, related_klass_name.constantize.table_name)
|
|
242
|
+
if other_name
|
|
243
|
+
hash[attr_name_without_id] = other_name.to_s
|
|
244
|
+
return hash
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
hash[attr_name] = serialized_value_if_needed(table_klass, attr_name, value)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Some tables have no model (eg joins) and should be dumped.
|
|
251
|
+
def process_table_without_model(table_name)
|
|
252
|
+
ActiveRecord::Base
|
|
253
|
+
.connection
|
|
254
|
+
.select_all(
|
|
255
|
+
"SELECT * FROM %<table>s" % {
|
|
256
|
+
table: ActiveRecord::Base.connection.quote_table_name(table_name)
|
|
257
|
+
}
|
|
258
|
+
)
|
|
259
|
+
.map do |row|
|
|
260
|
+
row.each_with_object({}) do |(attr_name, value), hash|
|
|
261
|
+
# If the record attribute is a relation, then get the other model name and use it instead of a ID value
|
|
262
|
+
if attr_name.end_with?("_id") && value.present?
|
|
263
|
+
attr_name_without_id = attr_name.sub(/_id$/, "")
|
|
264
|
+
klass = class_from_table(attr_name_without_id)
|
|
265
|
+
if klass
|
|
266
|
+
other_name = get_record_name({"id" => value}, klass.table_name)
|
|
267
|
+
|
|
268
|
+
# Note when there is no model for the table then retain '_id' attr name, as the fixtures setup code
|
|
269
|
+
# doesnt know about a relation named with the value of <attr_name_without_id> since there is no Model class
|
|
270
|
+
hash[attr_name] = other_name ? other_name.to_s : value
|
|
271
|
+
else
|
|
272
|
+
hash[attr_name] = value
|
|
273
|
+
end
|
|
274
|
+
else
|
|
275
|
+
hash[attr_name] = value
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def prepare_fixture_data(rows, table_name)
|
|
282
|
+
# This will be mutated by calls to generate_record_name in cases where the index is needed
|
|
283
|
+
row_index = +"000"
|
|
284
|
+
rows.inject({}) do |hash, record|
|
|
285
|
+
# If this was created by us, dont store the ID, use the rails stable ID
|
|
286
|
+
obj_name = get_record_name(record, table_name)
|
|
287
|
+
record_name = generate_record_name(record, table_name, row_index)
|
|
288
|
+
if obj_name
|
|
289
|
+
Rails.logger.debug "Writing #{obj_name} (#{table_name})"
|
|
290
|
+
record.delete("id")
|
|
291
|
+
else
|
|
292
|
+
Rails
|
|
293
|
+
.logger.debug "Writing a record which was created indirectly by a factory (#{table_name})"
|
|
294
|
+
end
|
|
295
|
+
hash.merge(record_name => record)
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
# Taken from https://github.com/rdy/fixture_builder
|
|
300
|
+
def serialized_value_if_needed(table_klass, attr_name, value)
|
|
301
|
+
if table_klass.respond_to?(:type_for_attribute)
|
|
302
|
+
serialize_according_to_type(table_klass, attr_name, value)
|
|
303
|
+
elsif table_klass.serialized_attributes.has_key? attr_name
|
|
304
|
+
table_klass.serialized_attributes[attr_name].dump(value)
|
|
305
|
+
else
|
|
306
|
+
value
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def serialize_according_to_type(klass, attr_name, value)
|
|
311
|
+
attr_type = klass.type_for_attribute(attr_name)
|
|
312
|
+
if attr_type.type == :jsonb || attr_type.type == :json
|
|
313
|
+
value
|
|
314
|
+
elsif attr_type.type == :time
|
|
315
|
+
# Serialise as an ActiveSupport::TimeWithZone
|
|
316
|
+
value
|
|
317
|
+
elsif attr_type.respond_to?(:serialize)
|
|
318
|
+
attr_type.serialize(value)
|
|
319
|
+
elsif attr_type.respond_to?(:type_cast_for_database)
|
|
320
|
+
attr_type.type_cast_for_database(value)
|
|
321
|
+
else
|
|
322
|
+
attr_type.type_cast_for_schema(value)
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def write_fixture_file(fixture_data, table_name)
|
|
327
|
+
File.open(fixture_file(table_name), "w") do |file|
|
|
328
|
+
file.write "# ----------------------------------------------------------------------------\n"
|
|
329
|
+
file.write "# Do not edit this file manually! It is generated by ./db/generate_fixtures.rb\n"
|
|
330
|
+
file.write "# ----------------------------------------------------------------------------\n"
|
|
331
|
+
file.write fixture_data.to_yaml
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
def fixture_file(table_name)
|
|
336
|
+
File.expand_path(File.join(output_path, "#{table_name}.yml"))
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "./fixture_generator"
|
|
4
|
+
require "timecop"
|
|
5
|
+
|
|
6
|
+
module FixturesFromFactories
|
|
7
|
+
class GenerateSet
|
|
8
|
+
class << self
|
|
9
|
+
def call(generator_index_klass, output_path, time_cop_now:, faker_seed:, options: {})
|
|
10
|
+
raise "Do not run fixture generation in a production environment" if ::Rails.env.production?
|
|
11
|
+
|
|
12
|
+
# Seed with known value to always end up with same result
|
|
13
|
+
::Faker::Config.random = Random.new(faker_seed)
|
|
14
|
+
::Faker::Config.locale = "en"
|
|
15
|
+
|
|
16
|
+
# Freeze the time to avoid having changing timestamps when regenerating
|
|
17
|
+
::Timecop.freeze(*time_cop_now)
|
|
18
|
+
|
|
19
|
+
# TODO: what is a better solution here?
|
|
20
|
+
# Monkey patch Devise encryptor so that we generate stable password hashes
|
|
21
|
+
if defined?(Devise)
|
|
22
|
+
::Devise::Encryptor.define_singleton_method(:digest) do |_klass, _password|
|
|
23
|
+
FixturesFromFactories.configuration.devise_password_hash
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
database_env_setup = "RAILS_ENV=#{ENV["RAILS_ENV"]}"
|
|
28
|
+
puts "Setup database for fixtures #{database_env_setup}"
|
|
29
|
+
system("#{database_env_setup} bin/rails db:environment:set RAILS_ENV=development")
|
|
30
|
+
# TODO: should we just use db:reset here?
|
|
31
|
+
system("#{database_env_setup} rake db:drop")
|
|
32
|
+
system("#{database_env_setup} rake db:create")
|
|
33
|
+
system("#{database_env_setup} rake db:migrate")
|
|
34
|
+
system("#{database_env_setup} rake db:seed")
|
|
35
|
+
|
|
36
|
+
if FixturesFromFactories.configuration.factory_bot_definition_file_paths
|
|
37
|
+
FactoryBot.definition_file_paths = FixturesFromFactories.configuration.factory_bot_definition_file_paths
|
|
38
|
+
end
|
|
39
|
+
FactoryBot.find_definitions
|
|
40
|
+
|
|
41
|
+
# Prepare the fixture files
|
|
42
|
+
FixtureGenerator.new(output_path).generate do
|
|
43
|
+
generator_index_klass.new(self, faker_seed, options).generate
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# After fixtures are build the Rails env set in the DB is lost, so set it manually
|
|
47
|
+
system("#{database_env_setup} bin/rails db:environment:set RAILS_ENV=development")
|
|
48
|
+
|
|
49
|
+
::Timecop.return
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "fixtures_from_factories/version"
|
|
4
|
+
require_relative "fixtures_from_factories/base_builder"
|
|
5
|
+
require_relative "fixtures_from_factories/fixture_generator"
|
|
6
|
+
require_relative "fixtures_from_factories/generate_set"
|
|
7
|
+
require_relative "fixtures_from_factories/railtie"
|
|
8
|
+
|
|
9
|
+
module FixturesFromFactories
|
|
10
|
+
class << self
|
|
11
|
+
def configuration
|
|
12
|
+
@configuration ||= Configuration.new
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def configure
|
|
16
|
+
yield(configuration) if block_given?
|
|
17
|
+
configuration
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Configuration class for initializer
|
|
22
|
+
class Configuration
|
|
23
|
+
# @dynamic devise_password_hash
|
|
24
|
+
attr_accessor :devise_password_hash, :excluded_tables, :factory_bot_definition_file_paths
|
|
25
|
+
|
|
26
|
+
def initialize
|
|
27
|
+
@devise_password_hash = "$2a$11$M8e7PEPxv4JEx2JHLw4XnuvfVVafJjFb6DfMnODxSUy5WhIgfbF1y" # 'password' TODO: make this not use the hashed value but let it be hashed at creation time
|
|
28
|
+
@excluded_tables = %w[schema_migrations spatial_ref_sys ar_internal_metadata]
|
|
29
|
+
@factory_bot_definition_file_paths = nil
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: fixtures_from_factories
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Stephen Ierodiaconou
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2022-11-23 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rails
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - ">="
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '6'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - ">="
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '6'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: factory_bot
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: faker
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: devise
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: timecop
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
83
|
+
description: A tool to help build a set of Fixtures for your Rails app, using your
|
|
84
|
+
test suite's FactoryBot factories. .
|
|
85
|
+
email:
|
|
86
|
+
- stevegeek@gmail.com
|
|
87
|
+
executables: []
|
|
88
|
+
extensions: []
|
|
89
|
+
extra_rdoc_files: []
|
|
90
|
+
files:
|
|
91
|
+
- ".standard.yml"
|
|
92
|
+
- CHANGELOG.md
|
|
93
|
+
- Gemfile
|
|
94
|
+
- Gemfile.lock
|
|
95
|
+
- LICENSE.txt
|
|
96
|
+
- README.md
|
|
97
|
+
- Rakefile
|
|
98
|
+
- lib/fixtures_from_factories.rb
|
|
99
|
+
- lib/fixtures_from_factories/base_builder.rb
|
|
100
|
+
- lib/fixtures_from_factories/fixture_generator.rb
|
|
101
|
+
- lib/fixtures_from_factories/generate_set.rb
|
|
102
|
+
- lib/fixtures_from_factories/railtie.rb
|
|
103
|
+
- lib/fixtures_from_factories/version.rb
|
|
104
|
+
- sig/fixtures_from_factories.rbs
|
|
105
|
+
homepage: https://github.com/stevegeek/fixtures_from_factories
|
|
106
|
+
licenses:
|
|
107
|
+
- MIT
|
|
108
|
+
metadata:
|
|
109
|
+
homepage_uri: https://github.com/stevegeek/fixtures_from_factories
|
|
110
|
+
source_code_uri: https://github.com/stevegeek/fixtures_from_factories
|
|
111
|
+
post_install_message:
|
|
112
|
+
rdoc_options: []
|
|
113
|
+
require_paths:
|
|
114
|
+
- lib
|
|
115
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
116
|
+
requirements:
|
|
117
|
+
- - ">="
|
|
118
|
+
- !ruby/object:Gem::Version
|
|
119
|
+
version: 2.7.0
|
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
|
+
requirements:
|
|
122
|
+
- - ">="
|
|
123
|
+
- !ruby/object:Gem::Version
|
|
124
|
+
version: '0'
|
|
125
|
+
requirements: []
|
|
126
|
+
rubygems_version: 3.3.7
|
|
127
|
+
signing_key:
|
|
128
|
+
specification_version: 4
|
|
129
|
+
summary: Build a set of Fixtures for your Rails app, using your test suite's FactoryBot
|
|
130
|
+
factories.
|
|
131
|
+
test_files: []
|