dirty_seed 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ff36072911914eaea5004a422959980277fc11681483fd84d82cdb89d5677b9
4
- data.tar.gz: 2b0f743b67520ea7b5c535a4eaa55a349388bc01be02985d5e4a4a3bfe8996e8
3
+ metadata.gz: 98dffcdecbd3fa5934529401fbac06a25cb883f853896cb6f93c13cf3cfce9f5
4
+ data.tar.gz: bd502b06f80ea7d2f7003f13dc260138e2bad1b5dc64f318c043ced8e9ed4fc9
5
5
  SHA512:
6
- metadata.gz: 7b5c5620e630a0803ea2337482e2bf9579164c39976602493373f01eab4285418533b3ec226bcb5611b0acfb2f44ce4fab012d30d205876851911b28d31d3095
7
- data.tar.gz: 00a6422b95a9e8b0712d070c618f00dffa217d26704944d35c1250db3c54b0b05e262f69f8f77d282d39ef4419ae65d84d06b02ef9772ac8aa5fc87c00788d47
6
+ metadata.gz: 685799e510fd74e13965b1ba4da70b2db9a4b170e4cbf4b6e411e757877593bafedd87153257645dc7084f198d3c226ac9bce0e131359ec1b90e5c85ecd4c2c6
7
+ data.tar.gz: f3285cdea256685d2b1d163f2277dd33434d60b4e9bb2695c157e01717a253085cf60d517ec98aa0b13732f36f87ac5d3fe59f7e3b155f0966ec6fe2aa81ed50
data/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  Add this line to your application's Gemfile:
8
8
 
9
9
  ```ruby
10
- gem 'dirty_seed', '~> 0.2.0'
10
+ gem 'dirty_seed', '~> 0.2.1'
11
11
  ```
12
12
 
13
13
  And then execute:
@@ -35,7 +35,7 @@ $ rake dirty_seed:seed COUNT=42
35
35
 
36
36
  Instance that cannot be saved are simply ignored.
37
37
 
38
- For each model, the number of created created records and the recurrent errors are printed out:
38
+ For each model, the number of created records and the recurrent errors are printed out:
39
39
 
40
40
  ```bash
41
41
  rake dirty_seed:seed COUNT=15
@@ -76,7 +76,7 @@ end
76
76
 
77
77
  A value is assigned for each attribute, depending on its type.
78
78
 
79
- Special types (`hstore`, `json`, `jsonb`, `array`...) are currently ignored (no value assignment).
79
+ Special types like `json`, `jsonb` and `array` are treated.
80
80
 
81
81
  For instance, given the following schema:
82
82
 
@@ -93,6 +93,8 @@ create_table 'things' do |t|
93
93
  t.string 'a_string'
94
94
  t.text 'a_text'
95
95
  t.time 'a_time'
96
+ t.json 'a_json'
97
+ t.text[] 'an_array'
96
98
  end
97
99
  ```
98
100
 
@@ -100,7 +102,6 @@ end
100
102
 
101
103
  ```ruby
102
104
  {
103
- id: 1,
104
105
  a_binary: '13',
105
106
  a_boolean: false,
106
107
  a_date: Wed, '02 Dec 2020',
@@ -110,7 +111,9 @@ end
110
111
  a_float: 28.825997012616263,
111
112
  a_string: 'Maxime eum ratione ab quod nihil.',
112
113
  a_text: 'Autem non in est dolore.',
113
- a_time: 'Sat, 01 Jan 2000 09:31:22 UTC +00:00'
114
+ a_time: 'Sat, 01 Jan 2000 09:31:22 UTC +00:00',
115
+ a_json: { 'Autem': 'Dolore', 'Lorem': 'Nihil' },
116
+ an_array: ['Autem', 'Dolore', 'Nihil'],
114
117
  }
115
118
  ```
116
119
 
@@ -169,7 +172,6 @@ end
169
172
 
170
173
  ```ruby
171
174
  {
172
- :id => 1,
173
175
  :thing_id => 42,
174
176
  :notifiable_type => 'User',
175
177
  :notifiable_id => 6,
@@ -187,14 +189,21 @@ For attributes requiring validations, assigned value is adapted.
187
189
 
188
190
  Currently, the following validations are treated:
189
191
 
190
- - `uniqueness`
191
192
  - `absence`
193
+ - `format: { with: regex }`
192
194
  - `inclusion: { in: [x, y] }`
195
+ - `length: { minimum: x }`
196
+ - `length: { maximum: x }`
197
+ - `length: { in: x..y }`
198
+ - `length: { is: x }`
193
199
  - `numericality: { greater_than: x }`
194
200
  - `numericality: { greater_than_or_equal_to: x }`
195
201
  - `numericality: { lesser_than: x }`
196
202
  - `numericality: { lesser_than_or_equal_to: x }`
197
203
  - `numericality: { in: x..y }`
204
+ - `uniqueness`
205
+
206
+ Attribute with an `enum` are treated too.
198
207
 
199
208
  Custom validations are not inspected.
200
209
 
@@ -226,7 +235,6 @@ end
226
235
 
227
236
  ```ruby
228
237
  {
229
- id: 1,
230
238
  first_name: 'Emory',
231
239
  last_name: 'Franecki',
232
240
  address: '843 Schneider Squares, Port Olenmouth, TN 12657',
@@ -270,16 +278,14 @@ The current attribute names treated this way are:
270
278
  - `username`
271
279
  - `uuid`
272
280
 
273
- More meanings will be added soon and will extend the mechanism to other formats (e.g. an `age` integer).
274
-
275
281
  ## License
276
282
 
277
283
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
278
284
 
279
285
  ## Next features and improvements
280
286
 
281
- * Add specs to validate specific errors rescue.
287
+ * Add specs to validate all specific errors rescue.
282
288
  * Manage validations on dates and times.
283
289
  * Detect more meaningful attributes.
284
- * Detect more protected attributes (to ignore).
290
+ * Detect more protected attributes (attributes to ignore).
285
291
  * Add a configuration system to define how to seed: excluded models, default values, faker method...
@@ -24,10 +24,10 @@ module DirtySeed
24
24
  # @param verbose [Boolean] true if logs should be outputed
25
25
  # @return [void]
26
26
  def seed(count, verbose: false)
27
- logger.verbose! if verbose
27
+ logger.verbose = verbose
28
28
  # check if ApplicationRecord is defined first (or raise error)
29
29
  ::ApplicationRecord && seeders.each { |seeder| seeder.seed(count) }
30
- print_logs
30
+ logger.summary(seeders)
31
31
  end
32
32
 
33
33
  # Creates and returns a seeder for each model
@@ -53,12 +53,5 @@ module DirtySeed
53
53
  def active_record_models
54
54
  ::ApplicationRecord.descendants.reject(&:abstract_class)
55
55
  end
56
-
57
- # Prints logs in the console
58
- # @return [void]
59
- def print_logs
60
- logger.break_line
61
- seeders.each { |seeder| logger.seeder_data(seeder) }
62
- end
63
56
  end
64
57
  end
@@ -6,73 +6,57 @@ module DirtySeed
6
6
  class Logger
7
7
  include Singleton
8
8
 
9
- # Sets verbose to true
10
- # @return [void]
11
- def verbose!
12
- @verbose = true
13
- end
9
+ attr_accessor :verbose
14
10
 
15
11
  # Outputs before seeding a model
16
12
  # @param model [DirtySeed::Model]
17
13
  # @return [void]
18
- def seed(model)
19
- verbose && puts("Seeding #{model.name.underscore.pluralize}")
14
+ def seed_model_message(model)
15
+ return unless verbose
16
+
17
+ puts('')
18
+ puts("Seeding #{model.name.underscore.pluralize}")
19
+ print('> ')
20
20
  end
21
21
 
22
- # Outputs the start of a new line
23
- # @return [void]
24
- def start_line
25
- verbose && print('> ')
22
+ # Cleans the message before output (remove linebreak and truncate)
23
+ # @param message [String]
24
+ # @return string
25
+ def clean(message)
26
+ base = message.tr("\n", "\t")
27
+ # #truncate is defined in ActiveSupport and then could be undefined
28
+ base.respond_to?(:truncate) ? base.truncate(150) : base.slice(150)
26
29
  end
27
30
 
28
31
  # Outputs a success message
29
32
  # @return [void]
30
33
  def success
31
- verbose && print("\e[#{green}m.\e[0m")
34
+ verbose && print("\e[32m.\e[0m")
32
35
  end
33
36
 
34
37
  # Outputs a fail message
35
38
  # @return [void]
36
- def fail
37
- verbose && print("\e[#{red}mx\e[0m")
38
- end
39
-
40
- # Outputs an error message
41
- # @return [void]
42
- def error
43
- verbose && print("\e[#{red}m!\e[0m")
39
+ def failure
40
+ verbose && print("\e[31mx\e[0m")
44
41
  end
45
42
 
46
- # Outputs a line break
43
+ # Outputs an abort message
47
44
  # @return [void]
48
- def break_line
49
- verbose && puts('')
45
+ def abort
46
+ verbose && print("\e[31m | too many errors -> abort\e[0m")
50
47
  end
51
48
 
52
49
  # Outputs seeder data
53
50
  # @return [void]
54
- def seeder_data(seeder)
51
+ def summary(seeders)
55
52
  return unless verbose
56
53
 
57
- puts seeder.model.name
58
- puts " \e[#{green}mseeded: #{seeder.score}\e[0m"
59
- puts " \e[#{red}merrors: #{seeder.error_list}\e[0m" if seeder.errors.any?
60
- end
61
-
62
- private
63
-
64
- attr_reader :verbose
65
-
66
- # Returns color code for green
67
- # @return [Integer]
68
- def green
69
- 32
70
- end
71
-
72
- # Returns color code for red
73
- # @return [Integer]
74
- def red
75
- 31
54
+ puts ''
55
+ seeders.each do |seeder|
56
+ puts seeder.model.name
57
+ puts " \e[32mseeded: #{seeder.records.count}\e[0m"
58
+ puts " \e[31merrors: #{seeder.errors.join(', ')}\e[0m" if seeder.errors.any?
59
+ end
76
60
  end
77
61
  end
78
62
  end
@@ -3,42 +3,32 @@
3
3
  module DirtySeed
4
4
  # Represents an Active Record model
5
5
  class Seeder
6
- attr_reader :model, :instances, :errors
6
+ attr_reader :model, :records, :errors
7
7
 
8
- # Initializes an instance
8
+ # Initializes an record
9
9
  # @param model [DirtySeed::Model]
10
10
  # @return [DirtySeed::Seeder]
11
11
  def initialize(model)
12
12
  @model = model
13
- @instances = []
13
+ @records = []
14
14
  @errors = []
15
15
  end
16
16
 
17
17
  # Creates records
18
18
  # @param count [Integer]
19
19
  # @return [Array<Object>]
20
- def seed(count)
21
- logger.seed(model)
22
- @count = count
20
+ def seed(qty = 1)
21
+ self.quantity = qty
22
+ logger.seed_model_message(model)
23
23
  create_records
24
- @errors.uniq!
25
- instances
26
- end
27
-
28
- # Returns the number of successfully seeded records
29
- # @return [Integer]
30
- def score
31
- instances.count
32
- end
33
-
34
- # Returns the errors as list
35
- # @return [String]
36
- def error_list
37
- errors.join(', ')
24
+ records
38
25
  end
39
26
 
40
27
  private
41
28
 
29
+ attr_accessor :successive_errors, :quantity
30
+ attr_writer :errors
31
+
42
32
  # Returns the logger
43
33
  # @return [DirtySeed::Logger]
44
34
  def logger
@@ -47,42 +37,80 @@ module DirtySeed
47
37
 
48
38
  # Creates records
49
39
  # @return [void]
40
+ # @note To take advantage of the faker uniqueness system, all params needs to be defined
41
+ # Then all records can be created with these params
42
+ # In other words: do not justcreate record one after the other
50
43
  def create_records
51
- logger.start_line
52
- data = params_collection
53
- @count.times do |i|
54
- instance = model.new(data[i])
55
- save(instance)
56
- # rescue from errors on initialize
57
- rescue StandardError => e
58
- @errors << e.message
59
- logger.error
44
+ self.successive_errors = 0
45
+ params_collection.each do |params|
46
+ break if exceeded_successive_errors?
47
+
48
+ record = initialize_record(params)
49
+ record && save(record)
60
50
  end
61
- logger.break_line
62
51
  end
63
52
 
64
- # Tries to save instance in database
65
- # Populates instances and errors and log message
53
+ # Is the successive errors maximum reached?
54
+ # @return [Boolean]
55
+ # @note The purpose is to stop trying to seed if to many errors happen
56
+ def exceeded_successive_errors?
57
+ return false if successive_errors < 3
58
+
59
+ logger.abort
60
+ true
61
+ end
62
+
63
+ # Initialize a record
64
+ # @param params [Hash] params to pass to #new
65
+ # @return [Object] instance of model
66
+ def initialize_record(params)
67
+ model.new(params)
68
+ # rescue from errors on initialize
69
+ rescue StandardError => e
70
+ add_standard_error(e)
71
+ end
72
+
73
+ # Tries to save record in database
74
+ # Populates records and errors and log message
66
75
  # @return [void]
67
- def save(instance)
68
- if instance.save
76
+ def save(record)
77
+ if record.save
78
+ records << record
79
+ self.successive_errors = 0
69
80
  logger.success
70
- @instances << instance
71
81
  else
72
- logger.fail
73
- @errors.concat(instance.errors.full_messages)
82
+ add_record_errors(record)
74
83
  end
75
84
  # rescue from errors on save
76
85
  rescue StandardError => e
77
- @errors << e.message
78
- logger.error
86
+ add_standard_error(e)
87
+ end
88
+
89
+ # Adds record errors
90
+ # @param record [Object] instance of model
91
+ # @return [void]
92
+ def add_record_errors(record)
93
+ self.errors |= record.errors.full_messages
94
+ self.successive_errors = successive_errors + 1
95
+ logger.failure
96
+ end
97
+
98
+ # Adds standard error
99
+ # @param error [Error] error inheriting from StandardError
100
+ # @return [void]
101
+ def add_standard_error(error)
102
+ self.errors |= [logger.clean(error.message)]
103
+ self.successive_errors = successive_errors + 1
104
+ logger.failure
79
105
  end
80
106
 
81
107
  # Generate records params
82
108
  # @return [Array<Hash>] where Hash is params for one record
109
+ # @note If model has no attributes and no associations, return empty hashes
83
110
  def params_collection
84
111
  data = Hash[attributes_collection + associations_collection]
85
- data.values.transpose.map { |vs| data.keys.zip(vs).to_h }
112
+ data = data.values.transpose.map { |vs| data.keys.zip(vs).to_h }
113
+ data.any? ? data : Array.new(quantity, {})
86
114
  end
87
115
 
88
116
  # Generate attributes params
@@ -96,7 +124,7 @@ module DirtySeed
96
124
  def attributes_collection
97
125
  model.attributes.map do |attribute|
98
126
  Faker::UniqueGenerator.clear
99
- [attribute.name, Array.new(@count) { attribute.value }]
127
+ [attribute.name, Array.new(quantity) { attribute.value }]
100
128
  end
101
129
  end
102
130
 
@@ -110,7 +138,7 @@ module DirtySeed
110
138
  # ]
111
139
  def associations_collection
112
140
  model.associations.map do |association|
113
- [association.name, Array.new(@count) { association.value }]
141
+ [association.name, Array.new(quantity) { association.value }]
114
142
  end
115
143
  end
116
144
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DirtySeed
4
- VERSION = '0.2.0'
4
+ VERSION = '0.2.1'
5
5
  public_constant :VERSION
6
6
  end
@@ -4,10 +4,20 @@ class Alfa < ApplicationRecord
4
4
  has_many :julietts
5
5
 
6
6
  after_initialize do |alfa|
7
- raise StandardError if alfa.a_string == '39763e57-f8a0-483a-8b26-cc670de8cbfd'
7
+ raise StandardError, dirty_message('initialize') if alfa.a_string == '39763e57-f8a0-483a-8b26-cc670de8cbfd'
8
8
  end
9
9
 
10
10
  before_save do |alfa|
11
- raise StandardError if alfa.a_string == '5ecb793c-e0fd-4315-b60d-66f34c1c17e3'
11
+ raise StandardError, dirty_message('save') if alfa.a_string == '5ecb793c-e0fd-4315-b60d-66f34c1c17e3'
12
+ end
13
+
14
+ def dirty_message(action)
15
+ <<~DIRTY
16
+ a dirty message on #{action}
17
+ taking several
18
+ lines and with a lot of
19
+ characters
20
+ #{Faker::Lorem.paragraph_by_chars(number: 500, supplemental: false)}
21
+ DIRTY
12
22
  end
13
23
  end