better_seeder 0.2.3 → 0.2.4

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: 20203d64e75c796bd405cb5caaabeb697ee4cd64b2a21770cc2703efaaedf815
4
- data.tar.gz: 8b218cd82cc8950284fa4fe0468443481760e092161c9a96f9ea2b0ae9974c28
3
+ metadata.gz: 7efa6650656240adf416711cabab9debe997812e5e666472e3391c59ad74ce44
4
+ data.tar.gz: 504062b646d4800f75dbb20ef7e221fc0da730bf9aa207026795341e9e1c50e3
5
5
  SHA512:
6
- metadata.gz: f193936be5c4bb4416bc27b2cdbb869c10c8dbe4a8d3046d63cc0ffd1af4e31edd7e0e613ab1828913df5a64fd225523211a158662b783491022a2109233ccb4
7
- data.tar.gz: 806324afb167aa6376f8c5dbf5fbe13083f4bcc9ec1e89c8bcbb46b021f5c29b27318580b63e2dacc42d4bfb3bf54d22afde05142acecd6a49aee82a23c561ae
6
+ metadata.gz: bc24811f8a5ea605435701ee6ceda23927c1dad77327e054cd9b31756065037ef75a77f6b02bd1c2558f92870746de38366814bea90cd5597aba29a0b85b1e11
7
+ data.tar.gz: 34c2cfc41ca466c7c4e7e4db290a47fc0ffd92503b2fc65c567c716f7123138e2de4f2ce485f4b1c5dc1e56f40f3b8b205b4d96d51deec3da5d35ffc6bc124c0
data/README.md CHANGED
@@ -130,7 +130,9 @@ module MyNamespace
130
130
  generate_data: true,
131
131
  count: 50,
132
132
  load_data: true,
133
- parent: nil
133
+ parents: [
134
+ { model: ::MyNamespace::MyModelParent, column: :column_id }
135
+ ]
134
136
  }
135
137
  end
136
138
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # lib/better_seeder/generators/structure_generator.rb
2
4
  require 'fileutils'
3
5
 
@@ -5,8 +7,8 @@ module BetterSeeder
5
7
  module Builders
6
8
  class Structure
7
9
  TEMPLATE = <<~RUBY
8
- module %{module_name}
9
- class %{class_name}Structure < ::BetterSeeder::Structure::Utils
10
+ module %<module_name>s
11
+ class %<class_name>sStructure < ::BetterSeeder::Structure::Utils
10
12
  # Defines generators for each attribute.
11
13
  def self.structure
12
14
  {
@@ -23,15 +25,15 @@ module BetterSeeder
23
25
  end
24
26
  end
25
27
 
26
- # Specific seeding configuration for %{class_name}.
28
+ # Specific seeding configuration for %<class_name>s.
27
29
  def self.seed_config
28
30
  {
29
- file_name: '%{file_name}',
31
+ file_name: '%<file_name>s',
30
32
  columns: { excluded: [] },
31
33
  generate_data: true,
32
34
  count: 10,
33
35
  load_data: true,
34
- parent: nil
36
+ # parents: [ { model: 'MyNamespace::MyModel', column: :my_column } ]
35
37
  }
36
38
  end
37
39
 
@@ -49,26 +51,23 @@ module BetterSeeder
49
51
  # @return [String] The full path to the generated file.
50
52
  def self.generate(model_name)
51
53
  # Split the model name into module parts and the actual class name.
52
- parts = model_name.split("::")
53
- class_name = parts.pop
54
- module_name = parts.empty? ? "Main" : parts.join("::")
54
+ parts = model_name.split('::')
55
+ class_name = parts.pop
56
+ module_name = parts.empty? ? 'Main' : parts.join('::')
55
57
 
56
58
  # Determine the file path.
57
59
  # For example, for "MyNamespace::MyModel", the file will be placed in:
58
60
  # lib/better_seeder/generators/my_namespace/my_model_structure.rb
59
61
  folder_path = File.join(BetterSeeder.configuration.structure_path, *parts.map(&:underscore))
60
- file_name = "#{class_name.underscore}_structure.rb"
61
- full_path = File.join(folder_path, file_name)
62
+ file_name = "#{class_name.underscore}_structure.rb"
63
+ full_path = File.join(folder_path, file_name)
62
64
 
63
65
  # Ensure the target directory exists.
64
- FileUtils.mkdir_p(folder_path) unless Dir.exist?(folder_path)
66
+ FileUtils.mkdir_p(folder_path)
65
67
 
66
68
  # Prepare the file content.
67
- content = TEMPLATE % {
68
- module_name: module_name,
69
- class_name: class_name,
70
- file_name: "#{class_name.underscore}_seed"
71
- }
69
+ content = format(TEMPLATE, module_name: module_name, class_name: class_name,
70
+ file_name: "#{class_name.underscore}_seed")
72
71
 
73
72
  # Write the template to the file.
74
73
  File.write(full_path, content)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # lib/better_seeder/configuration.rb
2
4
 
3
5
  module BetterSeeder
@@ -5,14 +7,12 @@ module BetterSeeder
5
7
  attr_accessor :log_language, :log_level, :structure_path, :preload_path
6
8
 
7
9
  def initialize
10
+ @log_language = :en
11
+ @log_level = :info
8
12
  if defined?(Rails) && Rails.respond_to?(:root)
9
- @log_language = :en
10
- @log_level = :info
11
13
  @structure_path = Rails.root.join('db', 'seed', 'structure')
12
14
  @preload_path = Rails.root.join('db', 'seed', 'preload')
13
15
  else
14
- @log_language = :en
15
- @log_level = :info
16
16
  @structure_path = File.join(Dir.pwd, 'db', 'seed', 'structure')
17
17
  @preload_path = File.join(Dir.pwd, 'db', 'seed', 'preload')
18
18
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # lib/better_seeder/exporter/base_exporter.rb
2
4
 
3
5
  module BetterSeeder
@@ -23,10 +25,10 @@ module BetterSeeder
23
25
  # @param output_path [String] Nome del file (senza estensione).
24
26
  # @param table_name [String] Nome della tabella (usato in SqlExporter).
25
27
  def initialize(data, output_path:, table_name: 'my_table')
26
- @data = data
28
+ @data = data
27
29
  # Utilizza il preload_path definito nella configurazione BetterSeeder (impostato nell'initializer).
28
30
  @output_path = File.join(BetterSeeder.configuration.preload_path, output_path)
29
- @table_name = table_name
31
+ @table_name = table_name
30
32
  end
31
33
 
32
34
  # Restituisce la directory in cui salvare i file.
@@ -39,7 +41,7 @@ module BetterSeeder
39
41
 
40
42
  # Verifica che la directory di output esista; se non esiste, la crea.
41
43
  def ensure_output_directory
42
- FileUtils.mkdir_p(output_directory) unless Dir.exist?(output_directory)
44
+ FileUtils.mkdir_p(output_directory)
43
45
  end
44
46
 
45
47
  # Costruisce il percorso completo del file di output, combinando la directory, l'output_path e l'estensione.
@@ -53,12 +55,12 @@ module BetterSeeder
53
55
  # Metodo astratto per ottenere l'estensione del file (es. ".json", ".csv", ".sql").
54
56
  # Le classi derivate devono implementarlo.
55
57
  def extension
56
- raise NotImplementedError, "Subclasses must implement #extension"
58
+ raise NotImplementedError, 'Subclasses must implement #extension'
57
59
  end
58
60
 
59
61
  # Metodo astratto per effettuare l'export.
60
62
  def export
61
- raise NotImplementedError, "Subclasses must implement the export method"
63
+ raise NotImplementedError, 'Subclasses must implement the export method'
62
64
  end
63
65
  end
64
66
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BetterSeeder
2
4
  module Exporters
3
5
  class Csv < Base
@@ -5,6 +7,7 @@ module BetterSeeder
5
7
  # Se la cartella non esiste, viene creata automaticamente.
6
8
  def export
7
9
  return if data.empty?
10
+
8
11
  headers = data.first.keys
9
12
 
10
13
  # Costruisce il percorso completo del file di output
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BetterSeeder
2
4
  module Exporters
3
5
  class Json < Base
@@ -7,9 +9,7 @@ module BetterSeeder
7
9
  # Imposta la directory di output
8
10
  full_path = File.join(full_output_path)
9
11
 
10
- File.open(full_path, 'w') do |file|
11
- file.write(JSON.pretty_generate(data))
12
- end
12
+ File.write(full_path, JSON.pretty_generate(data))
13
13
  end
14
14
 
15
15
  def extension
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BetterSeeder
2
4
  module Exporters
3
5
  class Sql < Base
@@ -11,6 +13,7 @@ module BetterSeeder
11
13
  # ... ;
12
14
  def export
13
15
  return if data.empty?
16
+
14
17
  columns = data.first.keys
15
18
 
16
19
  # Crea l'array delle tuple di valori per ciascun record.
@@ -18,7 +21,7 @@ module BetterSeeder
18
21
  row_values = columns.map do |col|
19
22
  value = row[col]
20
23
  # Se il valore è nil restituisce NULL, altrimenti esegue l'escaping delle virgolette singole.
21
- value.nil? ? "NULL" : "'#{value.to_s.gsub("'", "''")}'"
24
+ value.nil? ? 'NULL' : "'#{value.to_s.gsub("'", "''")}'"
22
25
  end
23
26
  "(#{row_values.join(', ')})"
24
27
  end
@@ -1,11 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module BetterSeeder
2
4
  module Farms
3
5
  class Farmer
4
-
5
6
  class << self
6
7
  def generate(options = {})
7
- model_name = options[:model] or raise ArgumentError, "Missing :model option"
8
- count = options[:count] || 10
8
+ model_name = options[:model] or raise ArgumentError, 'Missing :model option'
9
9
 
10
10
  # Costruisce il percorso del file di structure.
11
11
  structure_file = File.expand_path(
@@ -14,7 +14,6 @@ module BetterSeeder
14
14
  )
15
15
  raise "Structure file not found: #{structure_file}" unless File.exist?(structure_file)
16
16
 
17
- # Carica il file di structure.
18
17
  load structure_file
19
18
 
20
19
  # Costruisce il nome della classe di structure: es. "Media::Participant" => "Media::ParticipantStructure"
@@ -27,91 +26,130 @@ module BetterSeeder
27
26
  raise error
28
27
  end
29
28
 
30
- generated_records = []
29
+ seed_config = structure_class.respond_to?(:seed_config) ? structure_class.seed_config : {}
31
30
 
32
- while generated_records.size < count
33
- new_record = nil
34
- loop do
35
- new_record = build_record(model_name, structure_class)
36
- new_record = inject_parent_keys(model_name, new_record, structure_class)
37
- break if validate_record(new_record, structure_class) &&
38
- !record_exists?(model_name, new_record, structure_class, generated_records)
31
+ generated_records = []
32
+ if seed_config.key?(:childs)
33
+ # Logica per il modello child: il numero totale di record = count * childs_count
34
+ parent_count = seed_config[:count] || 10
35
+ childs_count = seed_config.dig(:childs, :count) || 10
36
+
37
+ parent_count.times do |_i|
38
+ childs_count.times do |child_index|
39
+ new_record = nil
40
+ loop do
41
+ # Passo l'indice del record figlio per far variare gli attributi definiti in childs[:attributes]
42
+ new_record = build_record(model_name, structure_class, child_index, child_mode: true)
43
+ new_record = inject_parent_keys(model_name, new_record, structure_class)
44
+ break if validate_record(new_record, structure_class) &&
45
+ !record_exists?(model_name, new_record, structure_class, generated_records)
46
+ end
47
+ generated_records.push(new_record)
48
+ end
49
+ end
50
+ else
51
+ # Logica standard per i modelli parent (o modelli senza childs)
52
+ count = options[:count] || (seed_config[:count] || 10)
53
+ count.times do |index|
54
+ new_record = nil
55
+ loop do
56
+ new_record = build_record(model_name, structure_class, index)
57
+ new_record = inject_parent_keys(model_name, new_record, structure_class)
58
+ break if validate_record(new_record, structure_class) &&
59
+ !record_exists?(model_name, new_record, structure_class, generated_records)
60
+ end
61
+ generated_records.push(new_record)
39
62
  end
40
- generated_records.push(new_record)
41
63
  end
42
64
 
43
65
  generated_records
44
66
  end
45
67
 
68
+ # Il metodo build_record ora supporta la modalità child_mode.
69
+ # Se child_mode è true e nella configurazione (seed_config) è definita la chiave childs con :attributes,
70
+ # per ogni attributo viene usato il valore dell'array corrispondente all'indice (child_index) passato.
71
+ def build_record(_model_name, structure_class, index, child_mode: false)
72
+ generation_rules = structure_class.structure
73
+ raise 'Structure must be a Hash' unless generation_rules.is_a?(Hash)
74
+
75
+ seed_config = structure_class.respond_to?(:seed_config) ? structure_class.seed_config : {}
76
+
77
+ record = {}
78
+ generation_rules.each do |attribute, rule|
79
+ generator = rule[1]
80
+ if child_mode && seed_config.dig(:childs, :attributes, attribute).is_a?(Array)
81
+ values = seed_config[:childs][:attributes][attribute]
82
+ value = values[index] # index viene passato dal loop interno
83
+ else
84
+ value = generator.respond_to?(:call) ? generator.call : generator
85
+ end
86
+ record[attribute] = value
87
+ end
88
+
89
+ record
90
+ end
91
+
92
+ # Restituisce il numero di record figli da generare per ciascun "record padre".
93
+ # Nel caso in cui nella configurazione sia presente la chiave childs, restituisce childs[:count],
94
+ # altrimenti default a 10.
95
+ def child_record_count(options = {})
96
+ model_name = options[:model] or raise ArgumentError, 'Missing :model option'
97
+
98
+ structure_file = File.expand_path(
99
+ File.join(BetterSeeder.configuration.structure_path, "#{model_name.underscore}_structure.rb"),
100
+ Dir.pwd
101
+ )
102
+ raise "Structure file not found: #{structure_file}" unless File.exist?(structure_file)
103
+
104
+ load structure_file
105
+ structure_class_name = "#{model_name}Structure"
106
+ structure_class = Object.const_get(structure_class_name)
107
+ seed_config = structure_class.respond_to?(:seed_config) ? structure_class.seed_config : {}
108
+ seed_config.dig(:childs, :count) || 10
109
+ end
110
+
46
111
  private
47
112
 
48
- def record_exists?(model_name, record, structure_class, generated_records)
49
- # Se non è definito il metodo unique_keys, non eseguiamo il controllo
113
+ def record_exists?(_model_name, record, structure_class, generated_records)
50
114
  return false unless structure_class.respond_to?(:unique_keys)
115
+
51
116
  unique_key_sets = structure_class.unique_keys
52
117
  return false if unique_key_sets.empty?
53
118
 
54
- # Determina il modello associato: si assume che il nome del modello sia
55
- # dato dalla rimozione della stringa "Structure" dal nome della classe di structure.
56
119
  model_class_name = structure_class.to_s.sub(/Structure$/, '')
57
- model_class = Object.const_get(model_class_name)
120
+ model_class = Object.const_get(model_class_name)
58
121
 
59
- # Per ogni set di chiavi uniche, costruiamo le condizioni della query
60
122
  unique_key_sets.each do |key_set|
61
123
  conditions = {}
62
124
  key_set.each do |col|
63
125
  conditions[col] = record[col]
64
126
  end
65
- # Se esiste un record nel database che soddisfa le condizioni, restituisce true.
66
- return true if generated_records.find do |record|
67
- conditions.all? { |key, value| record[key] == value }
68
- end.present?
127
+ return true if generated_records.find { |r| conditions.all? { |key, value| r[key] == value } }
69
128
  return true if model_class.where(conditions).exists?
70
129
  end
71
130
 
72
131
  false
73
132
  end
74
133
 
75
- def build_record(model_name, structure_class)
76
- generation_rules = structure_class.structure
77
- raise "Structure must be a Hash" unless generation_rules.is_a?(Hash)
78
-
79
- record = {}
80
- generation_rules.each do |attribute, rule|
81
- # Ogni rule è un array nel formato [tipo, generatore]
82
- generator = rule[1]
83
- value = generator.respond_to?(:call) ? generator.call : generator
84
- record[attribute] = value
85
- end
86
-
87
- record
88
- end
89
-
90
- def inject_parent_keys(model_name, record, structure_class)
91
- config = structure_class.respond_to?(:seed_config) ? structure_class.seed_config : {}
134
+ def inject_parent_keys(_model_name, record, structure_class)
135
+ config = structure_class.respond_to?(:seed_config) ? structure_class.seed_config : {}
92
136
  parents_spec = config[:parents]
93
- return record unless parents_spec && !parents_spec.empty?
137
+ return record if parents_spec.blank?
94
138
 
95
139
  parents_spec.each do |parent_config|
96
140
  parent_model = parent_config[:model]
97
- column = parent_config[:column]
141
+ column = parent_config[:column]
142
+ pool_key = parent_model.to_s
98
143
 
99
- # Tenta di ottenere un record del parent dal pool BetterSeeder.generated_records se disponibile.
100
- # Usiamo il nome del modello come chiave nel pool.
101
- pool_key = parent_model.to_s
102
- parent_record = if defined?(BetterSeeder.generated_records) &&
144
+ unless defined?(BetterSeeder.generated_records) &&
103
145
  BetterSeeder.generated_records[pool_key] &&
104
146
  !BetterSeeder.generated_records[pool_key].empty?
105
- BetterSeeder.generated_records[pool_key].sample
106
- else
107
- BetterSeeder.generated_records[pool_key] = parent_model.all
108
- BetterSeeder.generated_records[pool_key].sample
109
- end
147
+ BetterSeeder.generated_records[pool_key] = parent_model.all
148
+ end
110
149
 
150
+ parent_record = BetterSeeder.generated_records[pool_key].sample
111
151
  raise "Parent record not found for #{parent_model}" unless parent_record
112
152
 
113
- # Inietta nel record la chiave esterna indicata nella configurazione.
114
- # binding.pry if model_name == "Media::Participant"
115
153
  record[column] = parent_record[:id]
116
154
  end
117
155
 
@@ -127,7 +165,6 @@ module BetterSeeder
127
165
 
128
166
  raise result.errors.to_h
129
167
  end
130
-
131
168
  end
132
169
  end
133
170
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'dry-types'
2
4
 
3
5
  module BetterSeeder
@@ -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,18 +1,47 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # lib/better_seeder/utils.rb
4
+ #
5
+ # = BetterSeeder::Utils
6
+ #
7
+ # Questo modulo fornisce metodi di utilità per la gestione dei seed. In particolare,
8
+ # consente di trasformare i nomi delle classi in formato snake_case con il suffisso "_structure.rb",
9
+ # gestire i messaggi di log e configurare il livello del logger per ActiveRecord.
2
10
 
3
11
  module BetterSeeder
4
12
  module Utils
5
-
6
13
  class << self
7
- # Trasforma un nome di classe in snake_case.
8
- # Esempio: "Campaigns::Campaign" => "campaigns_campaign"
14
+ ##
15
+ # Trasforma un nome di classe in snake_case e aggiunge il suffisso "_structure.rb".
16
+ #
17
+ # ==== Esempio
18
+ # transform_class_name("Campaigns::Campaign")
19
+ # # => "campaigns/campaign_structure.rb"
20
+ #
21
+ # ==== Parametri
22
+ # * +class_name+ - Stringa che rappresenta il nome della classe, eventualmente suddiviso in
23
+ # namespace separati da "::".
24
+ #
25
+ # ==== Ritorno
26
+ # Restituisce una stringa con il nome della classe in formato snake_case e l'ultimo elemento
27
+ # terminato con "_structure.rb".
28
+ #
9
29
  def transform_class_name(class_name)
10
- elements = class_name.split("::").map(&:underscore)
30
+ elements = class_name.split('::').map(&:underscore)
11
31
  # Aggiunge "_structure.rb" all'ultimo elemento
12
32
  elements[-1] = "#{elements[-1]}_structure.rb"
13
- elements.join("/")
33
+ elements.join('/')
14
34
  end
15
35
 
36
+ ##
37
+ # Registra un messaggio usando il logger di Rails se disponibile, altrimenti lo stampa su standard output.
38
+ #
39
+ # ==== Parametri
40
+ # * +message+ - Il messaggio da loggare (può essere una stringa o nil).
41
+ #
42
+ # ==== Ritorno
43
+ # Non ritorna un valore significativo.
44
+ #
16
45
  def logger(message: nil)
17
46
  if defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
18
47
  Rails.logger.info message
@@ -21,6 +50,16 @@ module BetterSeeder
21
50
  end
22
51
  end
23
52
 
53
+ ##
54
+ # Configura il livello del logger per ActiveRecord in base alla configurazione definita in BetterSeeder.
55
+ #
56
+ # ==== Dettagli
57
+ # Il metodo imposta il livello del logger in base al valore di BetterSeeder.configuration.log_level:
58
+ # * +:debug+ -> Logger::DEBUG
59
+ # * +:info+ -> Logger::INFO
60
+ # * +:error+ -> Logger::ERROR
61
+ # Se il livello non corrisponde a nessuna delle opzioni previste, viene impostato il livello +Logger::DEBUG+.
62
+ #
24
63
  def log_level_setup
25
64
  level = case BetterSeeder.configuration.log_level
26
65
  when :debug then Logger::DEBUG
@@ -31,7 +70,6 @@ module BetterSeeder
31
70
 
32
71
  ActiveRecord::Base.logger.level = level
33
72
  end
34
-
35
73
  end
36
74
  end
37
75
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BetterSeeder
4
- VERSION = "0.2.3"
4
+ VERSION = '0.2.4'
5
5
  end
data/lib/better_seeder.rb CHANGED
@@ -1,32 +1,16 @@
1
- require_relative "better_seeder/utils"
2
- require_relative "better_seeder/configuration"
3
- require_relative "better_seeder/structure/utils"
4
- require_relative "better_seeder/farms/farmer"
5
- require_relative "better_seeder/exporters/base"
6
- require_relative "better_seeder/exporters/json"
7
- require_relative "better_seeder/exporters/csv"
8
- require_relative "better_seeder/exporters/sql"
9
- require_relative "better_seeder/builders/structure"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'better_seeder/utils'
4
+ require_relative 'better_seeder/configuration'
5
+ require_relative 'better_seeder/structure/utils'
6
+ require_relative 'better_seeder/farms/farmer'
7
+ require_relative 'better_seeder/exporters/base'
8
+ require_relative 'better_seeder/exporters/json'
9
+ require_relative 'better_seeder/exporters/csv'
10
+ require_relative 'better_seeder/exporters/sql'
11
+ require_relative 'better_seeder/builders/structure'
10
12
 
11
13
  module BetterSeeder
12
- class Configuration
13
- attr_accessor :log_language, :structure_path, :preload_path
14
-
15
- def initialize
16
- if defined?(Rails) && Rails.respond_to?(:root)
17
- @log_language = :en
18
- @log_level = :info
19
- @structure_path = Rails.root.join('db', 'seed', 'structure')
20
- @preload_path = Rails.root.join('db', 'seed', 'preload')
21
- else
22
- @log_language = :en
23
- @log_level = :info
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
 
@@ -65,7 +49,7 @@ module BetterSeeder
65
49
  # - structure_path: percorso dove sono memorizzati i file di structure (default: Rails.root/db/seed/structure)
66
50
  # - preload_path: percorso dove verranno salvati i file esportati (default: Rails.root/db/seed/preload)
67
51
  def self.install
68
- initializer_path = File.join(Rails.root, "config", "initializers", "better_seeder.rb")
52
+ initializer_path = Rails.root.join('config', 'initializers', 'better_seeder.rb').to_s
69
53
 
70
54
  if File.exist?(initializer_path)
71
55
  message = "BetterSeeder initializer already exists at #{initializer_path}"
@@ -116,8 +100,8 @@ module BetterSeeder
116
100
  message = "[LOGGER] previous log level: #{previous_log_level}, actual log level: #{ActiveRecord::Base.logger.level}"
117
101
  BetterSeeder::Utils.logger(message: message)
118
102
 
119
- start_time = Time.now
120
- stats = {} # Statistiche: modello => numero di record caricati
103
+ start_time = Time.zone.now
104
+ stats = {} # Statistiche: modello => numero di record caricati
121
105
  parent_loaded_records = {} # Per memorizzare i record creati per i modelli parent
122
106
 
123
107
  ActiveRecord::Base.transaction do
@@ -129,7 +113,7 @@ module BetterSeeder
129
113
  end
130
114
 
131
115
  ActiveRecord::Base.logger.level = previous_log_level
132
- total_time = Time.now - start_time
116
+ total_time = Time.zone.now - start_time
133
117
  log_statistics(stats, total_time)
134
118
  end
135
119
 
@@ -137,8 +121,6 @@ module BetterSeeder
137
121
  BetterSeeder::Builders::Structure.generate(model_name)
138
122
  end
139
123
 
140
- private
141
-
142
124
  # Processa la configurazione per un singolo modello.
143
125
  # Carica il file di structure corrispondente e recupera la configurazione tramite `seed_config`.
144
126
  # Quindi, esegue il recupero o la generazione dei record, iniezione di eventuali foreign key per modelli child,
@@ -168,18 +150,18 @@ module BetterSeeder
168
150
 
169
151
  # Recupera la configurazione specifica dal file di structure tramite il metodo seed_config.
170
152
  # Se non definito, vengono usati dei valori di default.
171
- seed_config = structure_class.respond_to?(:seed_config) ? structure_class.seed_config : {}
172
- file_name = seed_config[:file_name] || "#{model_name.underscore}_seed"
173
- excluded_columns = if export_type.to_s.downcase != 'sql'
174
- seed_config.dig(:columns, :excluded) || []
175
- else
153
+ seed_config = structure_class.respond_to?(:seed_config) ? structure_class.seed_config : {}
154
+ file_name = seed_config[:file_name] || "#{model_name.underscore}_seed"
155
+ excluded_columns = if export_type.to_s.downcase == 'sql'
176
156
  []
157
+ else
158
+ seed_config.dig(:columns, :excluded) || []
177
159
  end
178
- generate_data = seed_config.fetch(:generate_data, true)
179
- count = seed_config[:count] || 10
180
- load_data = seed_config.fetch(:load_data, true)
181
- parent = seed_config[:parent] # nil oppure valore (o array) per modelli child
182
- superclass = seed_config[:superclass] # nil oppure valore (o array) per modelli child
160
+ generate_data = seed_config.fetch(:generate_data, true)
161
+ count = seed_config[:count] || 10
162
+ load_data = seed_config.fetch(:load_data, true)
163
+ parent = seed_config[:parent] # nil oppure valore (o array) per modelli child
164
+ superclass = seed_config[:superclass] # nil oppure valore (o array) per modelli child
183
165
 
184
166
  # Log per indicare se il modello è parent o child.
185
167
  message = if parent.nil?
@@ -190,41 +172,42 @@ module BetterSeeder
190
172
  BetterSeeder::Utils.logger(message: message)
191
173
 
192
174
  # Recupera la classe reale del modello (ActiveRecord).
193
- model_class = Object.const_get(model_name) rescue nil
175
+ model_class = begin
176
+ Object.const_get(model_name)
177
+ rescue StandardError
178
+ nil
179
+ end
194
180
  unless model_class
195
181
  message = "[ERROR] Model #{model_name} not found."
196
182
  BetterSeeder::Utils.logger(message: message)
197
-
198
183
  raise Object.const_get(model_name)
199
184
  end
200
185
 
201
186
  # Se abilitato, carica i record nel database.
202
- if load_data && File.exist?("#{BetterSeeder.configuration.preload_path.to_s}/#{seed_config[:file_name]}.sql")
187
+ if load_data && File.exist?("#{BetterSeeder.configuration.preload_path}/#{seed_config[:file_name]}.sql")
203
188
  load_data_from_file(seed_config)
204
- stats[model_name] = model_class.all.count
189
+ stats[model_name] = model_class.count
190
+ elsif generate_data
191
+ records = Farms::Farmer.generate(model: model_name, count: count)
192
+ total_records = records.size
193
+ stats[model_name] = total_records
194
+ created_records = load_records_into_db(model_class, records, total_records, model_name, superclass)
195
+ # Se il modello è parent, salva i record creati per poterli utilizzare in seguito per i modelli child.
196
+ parent_loaded_records[model_name] = created_records if parent.nil?
205
197
  else
206
- if generate_data
207
- records = Farms::Farmer.generate(model: model_name, count: count)
208
- total_records = records.size
209
- stats[model_name] = total_records
210
- created_records = load_records_into_db(model_class, records, total_records, model_name, superclass)
211
- # Se il modello è parent, salva i record creati per poterli utilizzare in seguito per i modelli child.
212
- parent_loaded_records[model_name] = created_records if parent.nil?
213
- else
214
- model_class.all.map(&:attributes)
215
- end
198
+ model_class.all.map(&:attributes)
216
199
  end
217
200
 
218
201
  # Rimuove le colonne escluse.
219
- unless BetterSeeder.generated_records[(superclass || model_name).to_s].nil?
220
- processed_records = BetterSeeder.generated_records[(superclass || model_name).to_s]
221
- processed_records = processed_records.map do |campaign|
222
- campaign.attributes.except(*excluded_columns.map(&:to_s))
223
- end
202
+ return if BetterSeeder.generated_records[(superclass || model_name).to_s].nil?
224
203
 
225
- # Esporta i record nel formato richiesto.
226
- export_records(model_class, processed_records, export_type, file_name)
204
+ processed_records = BetterSeeder.generated_records[(superclass || model_name).to_s]
205
+ processed_records = processed_records.map do |record|
206
+ record.attributes.except(*excluded_columns.map(&:to_s))
227
207
  end
208
+
209
+ # Esporta i record nel formato richiesto.
210
+ export_records(model_class, processed_records, export_type, file_name)
228
211
  end
229
212
 
230
213
  # Carica i record nel database, utilizzando una progress bar per monitorare il progresso.
@@ -233,7 +216,7 @@ module BetterSeeder
233
216
  # @return [Array<Object>] Array dei record creati (istanze ActiveRecord)
234
217
  def self.load_records_into_db(model_class, processed_records, total_records, model_name, superclass)
235
218
  progressbar = ProgressBar.create(total: total_records, format: '%a %B %p%% %t')
236
- message = "[INFO] Starting to load #{total_records} records for model #{model_name}..."
219
+ message = "[INFO] Starting to load #{total_records} records for model #{model_name}..."
237
220
  BetterSeeder::Utils.logger(message: message)
238
221
 
239
222
  processed_records.each do |record|
@@ -270,14 +253,14 @@ module BetterSeeder
270
253
  # Log finale con le statistiche raccolte e il tempo totale di esecuzione.
271
254
  def self.log_statistics(stats, total_time)
272
255
  stats_message = stats.map { |model, count| "#{model}: #{count} records" }.join("\n")
273
- message = "[INFO] Finished processing all models in #{total_time.round(2)} seconds. Statistics: \n#{stats_message}"
256
+ message = "[INFO] Finished processing all models in #{total_time.round(2)} seconds. Statistics: \n#{stats_message}"
274
257
  BetterSeeder::Utils.logger(message: message)
275
258
  end
276
259
 
277
260
  # Metodo di utilità per trasformare il nome della classe in un formato in cui le lettere
278
261
  # sono in minuscolo e separate da underscore.
279
262
  def self.transform_class_name(class_name)
280
- class_name.split("::").map(&:underscore).join("_")
263
+ class_name.split('::').map(&:underscore).join('_')
281
264
  end
282
265
 
283
266
  def self.load_data_from_file(seed_config)
@@ -299,7 +282,7 @@ module BetterSeeder
299
282
  ActiveRecord::Base.connection.execute(sql)
300
283
  BetterSeeder::Utils.logger(message: "[INFO] Loaded seed file: #{seed_file_path}")
301
284
  true
302
- rescue => e
285
+ rescue StandardError => e
303
286
  BetterSeeder::Utils.logger(message: "[ERROR] Failed to load seed file: #{seed_file_path} - Error: #{e.message}")
304
287
  false
305
288
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # lib/generators/better_seeder/structure_generator.rb
2
- require "rails/generators"
4
+ require 'rails/generators'
3
5
 
4
6
  module BetterSeeder
5
7
  class StructureGenerator < Rails::Generators::NamedBase
@@ -7,9 +9,9 @@ module BetterSeeder
7
9
  # source_root File.expand_path("templates", __dir__)
8
10
 
9
11
  def create_structure_file
10
- say_status("info", "Generating structure file for #{name}", :green)
12
+ say_status('info', "Generating structure file for #{name}", :green)
11
13
  file_path = BetterSeeder.generate_structure(model_name: name)
12
- say_status("info", "Structure file created at #{file_path}", :green)
14
+ say_status('info', "Structure file created at #{file_path}", :green)
13
15
  end
14
16
  end
15
- end
17
+ end
metadata CHANGED
@@ -1,31 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_seeder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
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-11 00:00:00.000000000 Z
11
+ date: 2025-03-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: ffaker
14
+ name: dry-schema
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.19'
19
+ version: '1.5'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.19'
26
+ version: '1.5'
27
27
  - !ruby/object:Gem::Dependency
28
- name: dry-schema
28
+ name: dry-types
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
@@ -39,19 +39,19 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.5'
41
41
  - !ruby/object:Gem::Dependency
42
- name: dry-types
42
+ name: ffaker
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.5'
47
+ version: '2.19'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.5'
54
+ version: '2.19'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: ruby-progressbar
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.11'
69
69
  - !ruby/object:Gem::Dependency
70
- name: activesupport
70
+ name: activerecord
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '4.2'
83
83
  - !ruby/object:Gem::Dependency
84
- name: activerecord
84
+ name: activesupport
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - ">="
@@ -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
@@ -151,6 +153,7 @@ metadata:
151
153
  homepage_uri: https://github.com/alessiobussolari/better_seeder
152
154
  source_code_uri: https://github.com/alessiobussolari/better_seeder
153
155
  changelog_uri: https://github.com/alessiobussolari/better_seeder/blob/main/CHANGELOG.md
156
+ rubygems_mfa_required: 'true'
154
157
  post_install_message:
155
158
  rdoc_options: []
156
159
  require_paths: