better_seeder 0.2.3.1 → 0.2.5

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: d5b13470c3a8af2c331ef6254593d3268c5a82654802368c4af18608ad629185
4
- data.tar.gz: ba63f74f95445e8b29bab7e33757c9ed460786a655fb9402733b0a7372436086
3
+ metadata.gz: 1d6d632652800d470d6214fa647d32b9fa48cab4c95ba88c7ff986a22093c33f
4
+ data.tar.gz: e9b16e216cd24c4f547f29f7f2fa50e690b5f31617145a84631f594186c60c6a
5
5
  SHA512:
6
- metadata.gz: 8e215fd763c8348003cff4266ba1616eca6e3430e586c754b150ae2f68c97e969c23eec7ad946fd1ba7a1656feb3c507667ef45195834cd531546ea7ecba9e42
7
- data.tar.gz: fc8b41742698a0cd0cf9b3db03a8b57bc2342b528bde096affe737a856f2a329b66063d5130b6b5a618caa1f8c87c169f60064ca4400575514ee1eca4e115feb
6
+ metadata.gz: 59358b3b0441b582abd6ec8601c97bc62e1e69b536b40e1f8137a3c1ba5b4495d66a862973da908d43ee5326c9aeebeab83cd594c665b42e10e42894380ee5a4
7
+ data.tar.gz: 3c99f4e4411e64ffb2626bd5016193792afd62122816e241f3f69f4825e8961c562850bd04eaf37e0fec90d03e26799c75a13ac24b4b4b45f168670ddc1b87e1
data/README.md CHANGED
@@ -1,7 +1,22 @@
1
+ ![BetterSeeder Logo](logo.png)
1
2
  # BetterSeeder
2
3
 
3
4
  BetterSeeder is a Rails gem designed to simplify and centralize your application's seeding process. It offers a flexible system to generate dynamic data, validate it using Dry-schema, enforce uniqueness constraints, load data into the database, and export it in various formats (SQL, CSV, JSON). The configuration is managed through a Rails initializer, while model-specific logic is defined in dedicated structure files.
4
5
 
6
+ ## Statistics
7
+
8
+ Below are two images displaying key statistics from the seeding process:
9
+
10
+ - **Initial Generation Statistics:**
11
+ This chart represents metrics from the very first generation run.
12
+
13
+ ![Initial Generation Statistics](generate.png)
14
+
15
+ - **Reload Data Statistics:**
16
+ This chart shows the metrics after reloading data (from the SQL file) into the database.
17
+
18
+ ![Reload Data Statistics](reload.png)
19
+
5
20
  ---
6
21
 
7
22
  ## Features
@@ -24,6 +39,12 @@ BetterSeeder is a Rails gem designed to simplify and centralize your application
24
39
  - **Rails Generator**
25
40
  A custom Rails generator scaffolds a structure file template for your models, ensuring a consistent configuration format.
26
41
 
42
+ - **Child Record Generation**
43
+ Now, BetterSeeder supports generating multiple child records per parent record. In your model’s seed configuration, you can define a `childs` section that specifies the number of child records to generate for each parent, along with attribute arrays to assign distinct values for each child. This allows for a total record count equal to *(parent count) × (childs count)*.
44
+
45
+ - **Preflight Data**
46
+ You can now define a `preflight` method in your structure file. The records returned by this method are inserted first before generating any additional records, ensuring that specific data is loaded as part of the seeding process. The total record count (defined in `seed_config[:count]`) includes these preflight records.
47
+
27
48
  ---
28
49
 
29
50
  ## Installation
@@ -65,7 +86,7 @@ If these values are set in the initializer, they will be used; otherwise, the ge
65
86
 
66
87
  To streamline the setup, execute the following command in your Rails console:
67
88
 
68
- ```ruby
89
+ ```bash
69
90
  BetterSeeder.install
70
91
  ```
71
92
 
@@ -85,12 +106,18 @@ For each model, create a structure file that centralizes the logic for generatin
85
106
 
86
107
  - **`seed_config`**
87
108
  Returns a hash with model-specific seeding settings:
88
- - `file_name`: The output file name (without extension)
89
- - `columns: { excluded: [...] }`: Columns to exclude from the generated data
90
- - `generate_data`: Boolean flag indicating whether to generate data dynamically (if false, existing records are used)
91
- - `count`: The number of records to generate (default: 10)
92
- - `load_data`: Boolean flag indicating whether the generated records should be inserted into the database
93
- - `parent`: For child models, specifies the parent model(s) used for injecting foreign keys
109
+ - `file_name`: The output file name (without extension)
110
+ - `columns: { excluded: [...] }`: Columns to exclude from the generated data
111
+ - `generate_data`: Boolean flag indicating whether to generate data dynamically (if false, existing records are used)
112
+ - `count`: The number of parent records to generate (default: 10)
113
+ - `load_data`: Boolean flag indicating whether the generated records should be inserted into the database
114
+ - `parent`: For child models, specifies the parent model(s) used for injecting foreign keys
115
+ - **`childs` (Optional):** A hash to define child record generation:
116
+ - `count`: The number of child records to generate for each parent.
117
+ - `attributes`: A hash mapping attribute names to an array of values. Each child record will receive a distinct value from the provided array.
118
+
119
+ - **`preflight` (Optional)**
120
+ If defined, this method should return an array of records to be inserted before generating dynamic records. These preloaded records count toward the total defined by `count`.
94
121
 
95
122
  - **`unique_keys` (Optional)**
96
123
  Returns an array of column groups (each group is an array of symbols) that must be unique. For example:
@@ -132,10 +159,20 @@ module MyNamespace
132
159
  load_data: true,
133
160
  parents: [
134
161
  { model: ::MyNamespace::MyModelParent, column: :column_id }
135
- ]
162
+ ],
163
+ childs: {
164
+ count: 3,
165
+ attributes: {
166
+ some_attribute: ['value1', 'value2', 'value3']
167
+ }
168
+ }
136
169
  }
137
170
  end
138
171
 
172
+ def self.preflight
173
+ [{ name: 'preloaded record', email: 'preloaded@example.com', created_at: Time.zone.now }]
174
+ end
175
+
139
176
  def self.unique_keys
140
177
  [[:email]]
141
178
  end
@@ -155,13 +192,16 @@ When you call `BetterSeeder.magic` with a configuration that contains an array o
155
192
  2. **Retrieve Seeding Configurations**
156
193
  Invoke the model's `seed_config` method to obtain its specific settings.
157
194
 
158
- 3. **Generate or Retrieve Records**
195
+ 3. **Preflight Data**
196
+ If a `preflight` method is defined in the structure file, its returned records will be inserted first. These records count toward the total number of records defined in `seed_config[:count]`.
197
+
198
+ 4. **Generate or Retrieve Records**
159
199
  Use the `structure` method to generate data dynamically (or fetch existing records) and validate them using `seed_schema` if defined. Uniqueness is enforced via `unique_keys`.
160
200
 
161
- 4. **Handle Parent/Child Relationships**
162
- Automatically inject foreign keys into child models using records from parent models.
201
+ 5. **Handle Parent/Child Relationships**
202
+ Automatically inject foreign keys into child models using records from parent models. With the new functionality, if a `childs` configuration is present, the gem generates child records for each parent record. For example, if `count` is set to 200 and `childs[:count]` is set to 2, a total of 400 records will be generated. Each child record receives distinct attribute values from the specified arrays.
163
203
 
164
- 5. **Load and Export Data**
204
+ 6. **Load and Export Data**
165
205
  If enabled (`load_data: true`), the generated records are inserted into the database and exported in the specified format (SQL, CSV, or JSON). Export files are saved in the directory specified by `BetterSeeder.configuration.preload_path`.
166
206
 
167
207
  ### Example Usage
@@ -257,6 +297,6 @@ BetterSeeder provides a modular, configurable, and extensible system for seeding
257
297
 
258
298
  - **Centralized Configuration:** Manage settings through a simple Rails initializer.
259
299
  - **Modular Structure Files:** Define data generation, validation, and configuration logic on a per-model basis.
260
- - **Seamless Data Handling:** Efficiently generate, validate, load, and export seed data while supporting complex relationships.
300
+ - **Seamless Data Handling:** Efficiently generate, validate, load, and export seed data while supporting complex relationships—now with enhanced child record generation for a more realistic data model.
261
301
 
262
302
  For further details or to contribute, please refer to the official repository or documentation.
@@ -6,7 +6,6 @@ module BetterSeeder
6
6
  class << self
7
7
  def generate(options = {})
8
8
  model_name = options[:model] or raise ArgumentError, 'Missing :model option'
9
- count = options[:count] || 10
10
9
 
11
10
  # Costruisce il percorso del file di structure.
12
11
  structure_file = File.expand_path(
@@ -15,10 +14,8 @@ module BetterSeeder
15
14
  )
16
15
  raise "Structure file not found: #{structure_file}" unless File.exist?(structure_file)
17
16
 
18
- # Carica il file di structure.
19
17
  load structure_file
20
18
 
21
- # Costruisce il nome della classe di structure: es. "Media::Participant" => "Media::ParticipantStructure"
22
19
  structure_class_name = "#{model_name}Structure"
23
20
  begin
24
21
  structure_class = Object.const_get(structure_class_name)
@@ -28,67 +25,118 @@ module BetterSeeder
28
25
  raise error
29
26
  end
30
27
 
28
+ seed_config = structure_class.respond_to?(:seed_config) ? structure_class.seed_config : {}
29
+ total_count = seed_config[:count] || 10
30
+
31
31
  generated_records = []
32
32
 
33
- while generated_records.size < count
34
- new_record = nil
35
- loop do
36
- new_record = build_record(model_name, structure_class)
37
- new_record = inject_parent_keys(model_name, new_record, structure_class)
38
- break if validate_record(new_record, structure_class) &&
39
- !record_exists?(model_name, new_record, structure_class, generated_records)
33
+ # Se il metodo preflight è definito, usalo per ottenere dati predefiniti
34
+ if structure_class.respond_to?(:preflight)
35
+ preflight_data = structure_class.preflight
36
+ generated_records.concat(preflight_data)
37
+ end
38
+
39
+ remaining_count = total_count - generated_records.size
40
+
41
+ if seed_config.key?(:childs)
42
+ # Modalità child: per ogni "record padre", generare childs_count record
43
+ childs_count = seed_config.dig(:childs, :count) || 10
44
+ # Calcolo: i record generati saranno i preflight + (remaining_count * childs_count)
45
+ remaining_count.times do |_i|
46
+ childs_count.times do |child_index|
47
+ new_record = nil
48
+ loop do
49
+ new_record = build_record(model_name, structure_class, child_index, child_mode: true)
50
+ new_record = inject_parent_keys(model_name, new_record, structure_class)
51
+ break if validate_record(new_record, structure_class) &&
52
+ !record_exists?(model_name, new_record, structure_class, generated_records)
53
+ end
54
+ generated_records.push(new_record)
55
+ end
56
+ end
57
+ else
58
+ # Modalità standard: genera remaining_count record
59
+ remaining_count.times do |index|
60
+ new_record = nil
61
+ loop do
62
+ new_record = build_record(model_name, structure_class, index)
63
+ new_record = inject_parent_keys(model_name, new_record, structure_class)
64
+ break if validate_record(new_record, structure_class) &&
65
+ !record_exists?(model_name, new_record, structure_class, generated_records)
66
+ end
67
+ generated_records.push(new_record)
40
68
  end
41
- generated_records.push(new_record)
42
69
  end
43
70
 
44
71
  generated_records
45
72
  end
46
73
 
74
+ # Il metodo build_record ora supporta la modalità child_mode.
75
+ # Se child_mode è true e nella configurazione (seed_config) è definita la chiave childs con :attributes,
76
+ # per ogni attributo viene usato il valore dell'array corrispondente all'indice (child_index) passato.
77
+ def build_record(_model_name, structure_class, index, child_mode: false)
78
+ generation_rules = structure_class.structure
79
+ raise 'Structure must be a Hash' unless generation_rules.is_a?(Hash)
80
+
81
+ seed_config = structure_class.respond_to?(:seed_config) ? structure_class.seed_config : {}
82
+
83
+ record = {}
84
+ generation_rules.each do |attribute, rule|
85
+ generator = rule[1]
86
+ if child_mode && seed_config.dig(:childs, :attributes, attribute).is_a?(Array)
87
+ values = seed_config[:childs][:attributes][attribute]
88
+ value = values[index] # index viene passato dal loop interno
89
+ else
90
+ value = generator.respond_to?(:call) ? generator.call : generator
91
+ end
92
+ record[attribute] = value
93
+ end
94
+
95
+ record
96
+ end
97
+
98
+ # Restituisce il numero di record figli da generare per ciascun "record padre".
99
+ # Nel caso in cui nella configurazione sia presente la chiave childs, restituisce childs[:count],
100
+ # altrimenti default a 10.
101
+ def child_record_count(options = {})
102
+ model_name = options[:model] or raise ArgumentError, 'Missing :model option'
103
+
104
+ structure_file = File.expand_path(
105
+ File.join(BetterSeeder.configuration.structure_path, "#{model_name.underscore}_structure.rb"),
106
+ Dir.pwd
107
+ )
108
+ raise "Structure file not found: #{structure_file}" unless File.exist?(structure_file)
109
+
110
+ load structure_file
111
+ structure_class_name = "#{model_name}Structure"
112
+ structure_class = Object.const_get(structure_class_name)
113
+ seed_config = structure_class.respond_to?(:seed_config) ? structure_class.seed_config : {}
114
+ seed_config.dig(:childs, :count) || 10
115
+ end
116
+
47
117
  private
48
118
 
49
119
  def record_exists?(_model_name, record, structure_class, generated_records)
50
- # Se non è definito il metodo unique_keys, non eseguiamo il controllo
51
120
  return false unless structure_class.respond_to?(:unique_keys)
52
121
 
53
122
  unique_key_sets = structure_class.unique_keys
54
123
  return false if unique_key_sets.empty?
55
124
 
56
- # Determina il modello associato: si assume che il nome del modello sia
57
- # dato dalla rimozione della stringa "Structure" dal nome della classe di structure.
58
125
  model_class_name = structure_class.to_s.sub(/Structure$/, '')
59
126
  model_class = Object.const_get(model_class_name)
60
127
 
61
- # Per ogni set di chiavi uniche, costruiamo le condizioni della query
62
128
  unique_key_sets.each do |key_set|
63
129
  conditions = {}
64
130
  key_set.each do |col|
65
131
  conditions[col] = record[col]
66
132
  end
67
- # Se esiste un record nel database che soddisfa le condizioni, restituisce true.
68
- return true if generated_records.find do |record|
69
- conditions.all? { |key, value| record[key] == value }
70
- end.present?
133
+ return true if generated_records.find { |r| conditions.all? { |key, value| r[key] == value } }
71
134
  return true if model_class.where(conditions).exists?
72
135
  end
73
136
 
74
137
  false
75
138
  end
76
139
 
77
- def build_record(_model_name, structure_class)
78
- generation_rules = structure_class.structure
79
- raise 'Structure must be a Hash' unless generation_rules.is_a?(Hash)
80
-
81
- record = {}
82
- generation_rules.each do |attribute, rule|
83
- # Ogni rule è un array nel formato [tipo, generatore]
84
- generator = rule[1]
85
- value = generator.respond_to?(:call) ? generator.call : generator
86
- record[attribute] = value
87
- end
88
-
89
- record
90
- end
91
-
92
140
  def inject_parent_keys(_model_name, record, structure_class)
93
141
  config = structure_class.respond_to?(:seed_config) ? structure_class.seed_config : {}
94
142
  parents_spec = config[:parents]
@@ -97,21 +145,17 @@ module BetterSeeder
97
145
  parents_spec.each do |parent_config|
98
146
  parent_model = parent_config[:model]
99
147
  column = parent_config[:column]
148
+ pool_key = parent_model.to_s
100
149
 
101
- # Tenta di ottenere un record del parent dal pool BetterSeeder.generated_records se disponibile.
102
- # Usiamo il nome del modello come chiave nel pool.
103
- pool_key = parent_model.to_s
104
150
  unless defined?(BetterSeeder.generated_records) &&
105
- BetterSeeder.generated_records[pool_key] &&
106
- !BetterSeeder.generated_records[pool_key].empty?
151
+ BetterSeeder.generated_records[pool_key] &&
152
+ !BetterSeeder.generated_records[pool_key].empty?
107
153
  BetterSeeder.generated_records[pool_key] = parent_model.all
108
154
  end
109
- parent_record = BetterSeeder.generated_records[pool_key].sample
110
155
 
156
+ parent_record = BetterSeeder.generated_records[pool_key].sample
111
157
  raise "Parent record not found for #{parent_model}" unless parent_record
112
158
 
113
- # Inietta nel record la chiave esterna indicata nella configurazione.
114
- # binding.pry if model_name == "Media::Participant"
115
159
  record[column] = parent_record[:id]
116
160
  end
117
161
 
@@ -0,0 +1,69 @@
1
+ module BetterSeeder
2
+ module Utils
3
+ module Common
4
+ class << self
5
+
6
+ ##
7
+ # Trasforma un nome di classe in snake_case e aggiunge il suffisso "_structure.rb".
8
+ #
9
+ # ==== Esempio
10
+ # transform_class_name("Campaigns::Campaign")
11
+ # # => "campaigns/campaign_structure.rb"
12
+ #
13
+ # ==== Parametri
14
+ # * +class_name+ - Stringa che rappresenta il nome della classe, eventualmente suddiviso in
15
+ # namespace separati da "::".
16
+ #
17
+ # ==== Ritorno
18
+ # Restituisce una stringa con il nome della classe in formato snake_case e l'ultimo elemento
19
+ # terminato con "_structure.rb".
20
+ #
21
+ def transform_class_name(class_name)
22
+ elements = class_name.split('::').map(&:underscore)
23
+ # Aggiunge "_structure.rb" all'ultimo elemento
24
+ elements[-1] = "#{elements[-1]}_structure.rb"
25
+ elements.join('/')
26
+ end
27
+
28
+ ##
29
+ # Registra un messaggio usando il logger di Rails se disponibile, altrimenti lo stampa su standard output.
30
+ #
31
+ # ==== Parametri
32
+ # * +message+ - Il messaggio da loggare (può essere una stringa o nil).
33
+ #
34
+ # ==== Ritorno
35
+ # Non ritorna un valore significativo.
36
+ #
37
+ def logger(message: nil)
38
+ if defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
39
+ Rails.logger.info message
40
+ else
41
+ puts message
42
+ end
43
+ end
44
+
45
+ ##
46
+ # Configura il livello del logger per ActiveRecord in base alla configurazione definita in BetterSeeder.
47
+ #
48
+ # ==== Dettagli
49
+ # Il metodo imposta il livello del logger in base al valore di BetterSeeder.configuration.log_level:
50
+ # * +:debug+ -> Logger::DEBUG
51
+ # * +:info+ -> Logger::INFO
52
+ # * +:error+ -> Logger::ERROR
53
+ # Se il livello non corrisponde a nessuna delle opzioni previste, viene impostato il livello +Logger::DEBUG+.
54
+ #
55
+ def log_level_setup
56
+ level = case BetterSeeder.configuration.log_level
57
+ when :debug then Logger::DEBUG
58
+ when :info then Logger::INFO
59
+ when :error then Logger::ERROR
60
+ else Logger::DEBUG
61
+ end
62
+
63
+ ActiveRecord::Base.logger.level = level
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,36 @@
1
+ # Questo file definisce il modulo +BetterSeeder::Utils::Store+ che offre
2
+ # metodi per memorizzare e recuperare record generati e per gestire la configurazione globale.
3
+ #
4
+ module BetterSeeder
5
+ module Utils
6
+ module Store
7
+ class << self
8
+
9
+ @generated_records = {}
10
+
11
+ ##
12
+ # Restituisce l'hash contenente i record generati.
13
+ #
14
+ # @return [Hash] hash con i record generati per ciascun modello.
15
+ #
16
+ def generated_records
17
+ @generated_records
18
+ end
19
+
20
+ ##
21
+ # Memorizza un record generato per il modello specificato.
22
+ #
23
+ # Se non esiste già, viene inizializzato un array vuoto per il modello.
24
+ #
25
+ # @param model_name [String, Symbol] il nome del modello
26
+ # @param record [Object] il record da memorizzare
27
+ #
28
+ def store_generated_record(model_name, record)
29
+ @generated_records[model_name.to_s] ||= []
30
+ @generated_records[model_name.to_s] << record
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BetterSeeder
4
- VERSION = '0.2.3.1'
4
+ VERSION = '0.2.5'
5
5
  end
data/lib/better_seeder.rb CHANGED
@@ -11,22 +11,6 @@ require_relative 'better_seeder/exporters/sql'
11
11
  require_relative 'better_seeder/builders/structure'
12
12
 
13
13
  module BetterSeeder
14
- class Configuration
15
- attr_accessor :log_language, :structure_path, :preload_path
16
-
17
- def initialize
18
- @log_language = :en
19
- @log_level = :info
20
- if defined?(Rails) && Rails.respond_to?(:root)
21
- @structure_path = Rails.root.join('db', 'seed', 'structure')
22
- @preload_path = Rails.root.join('db', 'seed', 'preload')
23
- else
24
- @structure_path = File.join(Dir.pwd, 'db', 'seed', 'structure')
25
- @preload_path = File.join(Dir.pwd, 'db', 'seed', 'preload')
26
- end
27
- end
28
- end
29
-
30
14
  # Definisce un hash che fungerà da pool per memorizzare i record generati per ciascun modello.
31
15
  @generated_records = {}
32
16
 
@@ -189,14 +173,13 @@ module BetterSeeder
189
173
 
190
174
  # Recupera la classe reale del modello (ActiveRecord).
191
175
  model_class = begin
192
- Object.const_get(model_name)
193
- rescue StandardError
194
- nil
195
- end
176
+ Object.const_get(model_name)
177
+ rescue StandardError
178
+ nil
179
+ end
196
180
  unless model_class
197
181
  message = "[ERROR] Model #{model_name} not found."
198
182
  BetterSeeder::Utils.logger(message: message)
199
-
200
183
  raise Object.const_get(model_name)
201
184
  end
202
185
 
@@ -208,8 +191,7 @@ module BetterSeeder
208
191
  records = Farms::Farmer.generate(model: model_name, count: count)
209
192
  total_records = records.size
210
193
  stats[model_name] = total_records
211
- created_records = load_records_into_db(model_class, records, total_records, model_name,
212
- superclass)
194
+ created_records = load_records_into_db(model_class, records, total_records, model_name, superclass)
213
195
  # Se il modello è parent, salva i record creati per poterli utilizzare in seguito per i modelli child.
214
196
  parent_loaded_records[model_name] = created_records if parent.nil?
215
197
  else
@@ -220,8 +202,8 @@ module BetterSeeder
220
202
  return if BetterSeeder.generated_records[(superclass || model_name).to_s].nil?
221
203
 
222
204
  processed_records = BetterSeeder.generated_records[(superclass || model_name).to_s]
223
- processed_records = processed_records.map do |campaign|
224
- campaign.attributes.except(*excluded_columns.map(&:to_s))
205
+ processed_records = processed_records.map do |record|
206
+ record.attributes.except(*excluded_columns.map(&:to_s))
225
207
  end
226
208
 
227
209
  # Esporta i record nel formato richiesto.
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_seeder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3.1
4
+ version: 0.2.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - alessio_bussolari
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-02-12 00:00:00.000000000 Z
11
+ date: 2025-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-schema
@@ -142,6 +142,8 @@ files:
142
142
  - lib/better_seeder/farms/farmer.rb
143
143
  - lib/better_seeder/structure/utils.rb
144
144
  - lib/better_seeder/utils.rb
145
+ - lib/better_seeder/utils/common.rb
146
+ - lib/better_seeder/utils/store.rb
145
147
  - lib/better_seeder/version.rb
146
148
  - lib/generators/better_seeder/structure_generator.rb
147
149
  homepage: https://github.com/alessiobussolari/better_seeder