factory_seeder 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.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +111 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +445 -0
  5. data/app/assets/stylesheets/factory_seeder.css +637 -0
  6. data/app/controllers/factory_seeder/application_controller.rb +8 -0
  7. data/app/controllers/factory_seeder/custom_seeds_controller.rb +134 -0
  8. data/app/controllers/factory_seeder/dashboard_controller.rb +36 -0
  9. data/app/controllers/factory_seeder/factory_controller.rb +70 -0
  10. data/app/views/factory_seeder/custom_seeds/index.html.erb +51 -0
  11. data/app/views/factory_seeder/custom_seeds/show.html.erb +113 -0
  12. data/app/views/factory_seeder/dashboard/index.html.erb +99 -0
  13. data/app/views/factory_seeder/factory/index.html.erb +71 -0
  14. data/app/views/factory_seeder/factory/show.html.erb +108 -0
  15. data/app/views/factory_seeder/seeds/show.html.erb +2 -0
  16. data/app/views/layouts/factory_seeder/application.html.erb +25 -0
  17. data/bin/factory_seeder +27 -0
  18. data/config/factory_seeder.rb +24 -0
  19. data/config/routes.rb +20 -0
  20. data/lib/factory_seeder/asset_helper.rb +34 -0
  21. data/lib/factory_seeder/cli.rb +352 -0
  22. data/lib/factory_seeder/configuration.rb +32 -0
  23. data/lib/factory_seeder/custom_seed_loader.rb +39 -0
  24. data/lib/factory_seeder/engine.rb +16 -0
  25. data/lib/factory_seeder/execution_log_store.rb +48 -0
  26. data/lib/factory_seeder/factory_scanner.rb +149 -0
  27. data/lib/factory_seeder/loader.rb +26 -0
  28. data/lib/factory_seeder/rails_integration.rb +29 -0
  29. data/lib/factory_seeder/seed.rb +102 -0
  30. data/lib/factory_seeder/seed_builder.rb +67 -0
  31. data/lib/factory_seeder/seed_generator.rb +305 -0
  32. data/lib/factory_seeder/seed_manager.rb +128 -0
  33. data/lib/factory_seeder/seeder.rb +41 -0
  34. data/lib/factory_seeder/version.rb +5 -0
  35. data/lib/factory_seeder/web_interface.rb +119 -0
  36. data/lib/factory_seeder.rb +209 -0
  37. data/templates/seed_template.rb +84 -0
  38. metadata +276 -0
@@ -0,0 +1,209 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Core dependencies (always required)
4
+ require 'factory_bot'
5
+ require 'json'
6
+ require 'active_support/core_ext/string/inflections'
7
+
8
+ require_relative 'factory_seeder/version'
9
+
10
+ module FactorySeeder
11
+ class << self
12
+ def configuration
13
+ @configuration ||= Configuration.new
14
+ end
15
+
16
+ def configure
17
+ yield(configuration)
18
+ end
19
+
20
+ def loader
21
+ Loader
22
+ end
23
+
24
+ def reload!
25
+ Loader.reload!
26
+ RailsIntegration.load_models
27
+ CustomSeedLoader.reload!
28
+ end
29
+
30
+ def scan_factories
31
+ # Ensure Rails integration is properly set up
32
+ FactorySeeder::RailsIntegration.setup
33
+ FactorySeeder::RailsIntegration.load_models
34
+
35
+ scanner = FactoryScanner.new
36
+ scanner.scan
37
+ end
38
+
39
+ # Méthode simplifiée qui ne liste que les noms des factories
40
+ def list_factory_names
41
+ FactoryBot.factories.map(&:name).map(&:to_s)
42
+ end
43
+
44
+ def seeder
45
+ @seeder ||= Seeder.new
46
+ end
47
+
48
+ def seed_manager
49
+ @seed_manager ||= SeedManager.new
50
+ end
51
+
52
+ def generate
53
+ yield(seeder) if block_given?
54
+ seeder
55
+ end
56
+
57
+ def define_seed(name, builder_block = nil, &execution_block)
58
+ seed_manager.define(name, builder_block, &execution_block)
59
+ end
60
+
61
+ def list_seeds
62
+ # Keep backward compatibility with old seeder
63
+ seeder.seeds
64
+ end
65
+
66
+ def list_custom_seeds
67
+ seed_manager.list
68
+ end
69
+
70
+ def find_custom_seed(name)
71
+ seed_manager.find(name)
72
+ end
73
+
74
+ def run_custom_seed(name, **kwargs)
75
+ seed_manager.run(name, **kwargs)
76
+ end
77
+
78
+ def execution_logs
79
+ Thread.current[:factory_seeder_execution_logs] ||= []
80
+ end
81
+
82
+ def clear_execution_logs!
83
+ Thread.current[:factory_seeder_execution_logs] = []
84
+ end
85
+
86
+ def log(message, level: :info, **meta)
87
+ entry = {
88
+ message: message.to_s,
89
+ level: level.to_sym,
90
+ timestamp: Time.now,
91
+ meta: meta
92
+ }
93
+ execution_logs << entry
94
+ entry
95
+ end
96
+
97
+ %i[info success warning error].each do |level_name|
98
+ define_method("log_#{level_name}") do |message, **meta|
99
+ log(message, level: level_name, **meta)
100
+ end
101
+ end
102
+
103
+ def normalized_logs(log_entries)
104
+ Array(log_entries).map do |log_entry|
105
+ timestamp = log_entry[:timestamp]
106
+ formatted_timestamp =
107
+ if timestamp.respond_to?(:iso8601)
108
+ timestamp.iso8601
109
+ else
110
+ timestamp.to_s
111
+ end
112
+
113
+ {
114
+ 'message' => log_entry[:message].to_s,
115
+ 'level' => log_entry[:level].to_s,
116
+ 'timestamp' => formatted_timestamp,
117
+ 'meta' => log_entry[:meta] || {}
118
+ }
119
+ end
120
+ end
121
+
122
+ def run(*names)
123
+ seeder.run(*names)
124
+ end
125
+
126
+ # Nouvelle méthode pour scanner les factories déjà chargées
127
+ def scan_loaded_factories
128
+ # Ensure Rails integration is properly set up
129
+ FactorySeeder::RailsIntegration.setup
130
+ FactorySeeder::RailsIntegration.load_models
131
+
132
+ factories = {}
133
+
134
+ FactoryBot.factories.each do |factory|
135
+ factory_name = factory.name.to_s
136
+ begin
137
+ # Use a safer approach to get class name without building the class
138
+ class_name = factory_name.classify
139
+
140
+ # Try to get the actual class name if possible, but don't fail if it doesn't work
141
+ begin
142
+ class_name = factory.build_class.name if factory.respond_to?(:build_class) && factory.build_class
143
+ rescue NameError, StandardError => e
144
+ # If we can't get the actual class name, use the inferred one
145
+ puts "⚠️ Using inferred class name for '#{factory_name}': #{e.message}" if configuration.verbose
146
+ end
147
+
148
+ factories[factory_name] = {
149
+ name: factory_name,
150
+ class_name: class_name,
151
+ traits: extract_traits(factory),
152
+ associations: extract_associations(factory),
153
+ attributes: extract_attributes(factory)
154
+ }
155
+ rescue NameError => e
156
+ puts "⚠️ Skipping factory '#{factory_name}': #{e.message}" if configuration.verbose
157
+ rescue StandardError => e
158
+ puts "⚠️ Error analyzing factory '#{factory_name}': #{e.message}" if configuration.verbose
159
+ end
160
+ end
161
+
162
+ factories
163
+ end
164
+
165
+ private
166
+
167
+ def extract_traits(factory)
168
+ factory.definition.defined_traits.map(&:name).map(&:to_s)
169
+ end
170
+
171
+ def extract_associations(factory)
172
+ associations = []
173
+
174
+ factory.definition.declarations.each do |declaration|
175
+ next unless declaration.is_a?(FactoryBot::Declaration::Association)
176
+
177
+ factory_name = declaration.name.to_s
178
+ associations << {
179
+ name: factory_name,
180
+ factory: factory_name.singularize,
181
+ strategy: 'create'
182
+ }
183
+ end
184
+
185
+ associations
186
+ end
187
+
188
+ def extract_attributes(factory)
189
+ attributes = []
190
+
191
+ factory.definition.declarations.each do |declaration|
192
+ next if declaration.is_a?(FactoryBot::Declaration::Association)
193
+
194
+ attributes << {
195
+ name: declaration.name.to_s,
196
+ type: declaration.class.name.demodulize.downcase
197
+ }
198
+ end
199
+
200
+ attributes
201
+ end
202
+ end
203
+ end
204
+
205
+ require_relative 'factory_seeder/loader'
206
+ FactorySeeder::Loader.setup
207
+
208
+ # Load Rails Engine only when Rails is available
209
+ require_relative 'factory_seeder/engine' if defined?(Rails::Engine)
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ # FactorySeeder Template
4
+ # This template shows common patterns for seeding your database
5
+
6
+ FactorySeeder.generate do |seeder|
7
+ # ========================================
8
+ # BASIC SEEDING
9
+ # ========================================
10
+
11
+ # Create users with different traits
12
+ seeder.create(:user, count: 10, traits: [:admin])
13
+ seeder.create(:user, count: 50, traits: [:vip])
14
+ seeder.create(:user, count: 100) # regular users
15
+
16
+ # Create posts with associations
17
+ seeder.create_with_associations(:post, count: 25, associations: {
18
+ author: { factory: :user, count: 1 }
19
+ })
20
+
21
+ # ========================================
22
+ # COMPLEX ASSOCIATIONS
23
+ # ========================================
24
+
25
+ # Create orders with multiple associations
26
+ seeder.create_with_associations(:order, count: 10, associations: {
27
+ customer: { factory: :user, traits: [:vip] },
28
+ items: { factory: :product, count: 3 }
29
+ })
30
+
31
+ # Create blog posts with comments
32
+ seeder.create_with_associations(:blog_post, count: 15, associations: {
33
+ author: { factory: :user, traits: [:admin] },
34
+ comments: { factory: :comment, count: 5 }
35
+ })
36
+
37
+ # ========================================
38
+ # CUSTOM ATTRIBUTES
39
+ # ========================================
40
+
41
+ # Override default attributes
42
+ seeder.create(:user, count: 5, attributes: {
43
+ email: 'custom@example.com',
44
+ role: 'moderator'
45
+ })
46
+
47
+ # ========================================
48
+ # DIFFERENT STRATEGIES
49
+ # ========================================
50
+
51
+ # Build records without saving (useful for testing)
52
+ seeder.create(:user, count: 3, strategy: :build, traits: [:admin])
53
+
54
+ # ========================================
55
+ # ENVIRONMENT-SPECIFIC SEEDING
56
+ # ========================================
57
+
58
+ if Rails.env.development?
59
+ # Development-specific seeds
60
+ seeder.create(:user, count: 100, traits: [:admin])
61
+ seeder.create(:post, count: 500)
62
+ elsif Rails.env.test?
63
+ # Test-specific seeds (minimal data)
64
+ seeder.create(:user, count: 5)
65
+ seeder.create(:post, count: 10)
66
+ end
67
+ end
68
+
69
+ # ========================================
70
+ # ALTERNATIVE APPROACHES
71
+ # ========================================
72
+
73
+ # You can also use the direct API
74
+ generator = FactorySeeder::SeedGenerator.new
75
+
76
+ # Create records one by one
77
+ generator.create(:user, count: 1, traits: [:admin])
78
+ generator.create(:post, count: 5, traits: [:published])
79
+
80
+ # Preview data before creating
81
+ generator.preview(:user, %i[admin vip])
82
+
83
+ # Get a summary of what was created
84
+ generator.summary
metadata ADDED
@@ -0,0 +1,276 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: factory_seeder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Wecasa
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-04-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '9.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '6.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '9.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: factory_bot
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '5.0'
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '7.0'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '5.0'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '7.0'
53
+ - !ruby/object:Gem::Dependency
54
+ name: zeitwerk
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '2.5'
60
+ - - "<"
61
+ - !ruby/object:Gem::Version
62
+ version: '3.0'
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '2.5'
70
+ - - "<"
71
+ - !ruby/object:Gem::Version
72
+ version: '3.0'
73
+ - !ruby/object:Gem::Dependency
74
+ name: thor
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '1.0'
80
+ - - "<"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '1.0'
90
+ - - "<"
91
+ - !ruby/object:Gem::Version
92
+ version: '3.0'
93
+ - !ruby/object:Gem::Dependency
94
+ name: sinatra
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '2.0'
100
+ - - "<"
101
+ - !ruby/object:Gem::Version
102
+ version: '5.0'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '2.0'
110
+ - - "<"
111
+ - !ruby/object:Gem::Version
112
+ version: '5.0'
113
+ - !ruby/object:Gem::Dependency
114
+ name: sinatra-contrib
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '2.0'
120
+ - - "<"
121
+ - !ruby/object:Gem::Version
122
+ version: '5.0'
123
+ type: :runtime
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '2.0'
130
+ - - "<"
131
+ - !ruby/object:Gem::Version
132
+ version: '5.0'
133
+ - !ruby/object:Gem::Dependency
134
+ name: pry
135
+ requirement: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: '0.14'
140
+ type: :development
141
+ prerelease: false
142
+ version_requirements: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - "~>"
145
+ - !ruby/object:Gem::Version
146
+ version: '0.14'
147
+ - !ruby/object:Gem::Dependency
148
+ name: rake
149
+ requirement: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - "~>"
152
+ - !ruby/object:Gem::Version
153
+ version: '13.0'
154
+ type: :development
155
+ prerelease: false
156
+ version_requirements: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - "~>"
159
+ - !ruby/object:Gem::Version
160
+ version: '13.0'
161
+ - !ruby/object:Gem::Dependency
162
+ name: rspec
163
+ requirement: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - "~>"
166
+ - !ruby/object:Gem::Version
167
+ version: '3.0'
168
+ type: :development
169
+ prerelease: false
170
+ version_requirements: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - "~>"
173
+ - !ruby/object:Gem::Version
174
+ version: '3.0'
175
+ - !ruby/object:Gem::Dependency
176
+ name: rubocop
177
+ requirement: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - "~>"
180
+ - !ruby/object:Gem::Version
181
+ version: '1.0'
182
+ type: :development
183
+ prerelease: false
184
+ version_requirements: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - "~>"
187
+ - !ruby/object:Gem::Version
188
+ version: '1.0'
189
+ - !ruby/object:Gem::Dependency
190
+ name: webrick
191
+ requirement: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - "~>"
194
+ - !ruby/object:Gem::Version
195
+ version: '1.7'
196
+ type: :development
197
+ prerelease: false
198
+ version_requirements: !ruby/object:Gem::Requirement
199
+ requirements:
200
+ - - "~>"
201
+ - !ruby/object:Gem::Version
202
+ version: '1.7'
203
+ description: FactorySeeder provides an intuitive interface to generate database seeds
204
+ using your existing FactoryBot factories, traits, and associations.
205
+ email:
206
+ - hugov@wecasa.fr
207
+ executables:
208
+ - factory_seeder
209
+ extensions: []
210
+ extra_rdoc_files: []
211
+ files:
212
+ - CHANGELOG.md
213
+ - LICENSE.txt
214
+ - README.md
215
+ - app/assets/stylesheets/factory_seeder.css
216
+ - app/controllers/factory_seeder/application_controller.rb
217
+ - app/controllers/factory_seeder/custom_seeds_controller.rb
218
+ - app/controllers/factory_seeder/dashboard_controller.rb
219
+ - app/controllers/factory_seeder/factory_controller.rb
220
+ - app/views/factory_seeder/custom_seeds/index.html.erb
221
+ - app/views/factory_seeder/custom_seeds/show.html.erb
222
+ - app/views/factory_seeder/dashboard/index.html.erb
223
+ - app/views/factory_seeder/factory/index.html.erb
224
+ - app/views/factory_seeder/factory/show.html.erb
225
+ - app/views/factory_seeder/seeds/show.html.erb
226
+ - app/views/layouts/factory_seeder/application.html.erb
227
+ - bin/factory_seeder
228
+ - config/factory_seeder.rb
229
+ - config/routes.rb
230
+ - lib/factory_seeder.rb
231
+ - lib/factory_seeder/asset_helper.rb
232
+ - lib/factory_seeder/cli.rb
233
+ - lib/factory_seeder/configuration.rb
234
+ - lib/factory_seeder/custom_seed_loader.rb
235
+ - lib/factory_seeder/engine.rb
236
+ - lib/factory_seeder/execution_log_store.rb
237
+ - lib/factory_seeder/factory_scanner.rb
238
+ - lib/factory_seeder/loader.rb
239
+ - lib/factory_seeder/rails_integration.rb
240
+ - lib/factory_seeder/seed.rb
241
+ - lib/factory_seeder/seed_builder.rb
242
+ - lib/factory_seeder/seed_generator.rb
243
+ - lib/factory_seeder/seed_manager.rb
244
+ - lib/factory_seeder/seeder.rb
245
+ - lib/factory_seeder/version.rb
246
+ - lib/factory_seeder/web_interface.rb
247
+ - templates/seed_template.rb
248
+ homepage: https://github.com/wecasa/factory_seeder
249
+ licenses:
250
+ - MIT
251
+ metadata:
252
+ homepage_uri: https://github.com/wecasa/factory_seeder
253
+ source_code_uri: https://github.com/wecasa/factory_seeder/tree/main
254
+ changelog_uri: https://github.com/wecasa/factory_seeder/blob/main/CHANGELOG.md
255
+ bug_tracker_uri: https://github.com/wecasa/factory_seeder/issues
256
+ rubygems_mfa_required: 'true'
257
+ post_install_message:
258
+ rdoc_options: []
259
+ require_paths:
260
+ - lib
261
+ required_ruby_version: !ruby/object:Gem::Requirement
262
+ requirements:
263
+ - - ">="
264
+ - !ruby/object:Gem::Version
265
+ version: 2.7.0
266
+ required_rubygems_version: !ruby/object:Gem::Requirement
267
+ requirements:
268
+ - - ">="
269
+ - !ruby/object:Gem::Version
270
+ version: '0'
271
+ requirements: []
272
+ rubygems_version: 3.5.22
273
+ signing_key:
274
+ specification_version: 4
275
+ summary: A gem to simplify database seeding using FactoryBot factories
276
+ test_files: []