dirty_seed 0.1.5 → 0.1.6

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: a892d4bb8402a4a51882d9b1b0917903a5a2a1ecfced0a29c05c4c68d9b47ada
4
- data.tar.gz: 65d335ed1f25ac5ef2ef71c92be56186a85ffb7bedff6512ad5541816879ed05
3
+ metadata.gz: 8eac8a564716c1859fb212114a00596eb82d80f335204e224feca8356d34901b
4
+ data.tar.gz: 6211c5a287f117be9078c1ad4e88f7a8a2bd4d781f8921bcff840dcc5a033a0a
5
5
  SHA512:
6
- metadata.gz: 52d3672671bba02cdbc421b6c0033c6732d52c05cb66ccf35fc79573b964b8762e13c12f965d10c2ab25eaeedc2a1b3405171eb7fc7ef77490002125289557ec
7
- data.tar.gz: cefb338d2283c36e005b8b7b45352d4cfad5bfd940bd83b44e8678e5936d597cb54d8120156b0400837c7f370ed08ac113d88366b8a5153fe41270697f0ec59b
6
+ metadata.gz: dab9f9eae8cd32e59142cada451d8ba38dfec944c06726b7da82f968c39a6a3e77521879633b8496fe7086cba6acf32c626e0784aa4fe007842aae3f5c6b8373
7
+ data.tar.gz: 36504d9781746ee02493ef3a4092356eee9a93295fc5ddef9624e99a0b30d8a47fceee18593099d5a09994e33fe4d3ce9499b24c0ea07fa6a3d679eece304da3
data/README.md CHANGED
@@ -2,7 +2,20 @@
2
2
 
3
3
  # DirtySeed
4
4
 
5
- Populate the database with records matching associations and validations, in order to quickly test application.
5
+ :seedling: Populate the database with records matching associations and validations in order to quickly test the application rendering.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'dirty_seed', '~> 0.1.6'
13
+ ```
14
+
15
+ And then execute:
16
+ ```bash
17
+ $ bundle
18
+ ```
6
19
 
7
20
  ## Usage
8
21
 
@@ -13,32 +26,253 @@ To seed dirty data, run:
13
26
  $ rake dirty_seed:seed
14
27
  ```
15
28
 
16
- This will try to create instances for each of your models inheriting from `ApplicationRecord`.
29
+ This will create records for each model inheriting from `ApplicationRecord`.
17
30
 
18
- If the instance cannot be saved, it is simply ignored.
31
+ Instance that cannot be saved ar simply ignored.
19
32
 
20
- Number of instances created and recurrent errors will be outputed.
33
+ For each model, the number of created created records and the recurrent errors are logged:
21
34
 
22
- ## Installation
35
+ ```bash
36
+ rake dirty_seed:seed
37
+ User
38
+ created: 15
39
+ Article
40
+ created: 9
41
+ errors: Title should match a specific regex
42
+ ```
23
43
 
24
- Add this line to your application's Gemfile:
44
+ ### Database population
45
+
46
+ For each model inheriting from `ApplicationRecord`, 15 records are created.
47
+
48
+ Models are sorted by their dependency to each others (through a `belongs_to` association) to ensure that some records exist before seeding an instance that requires one.
49
+
50
+ For instance, given the following models, the order of seeding will be `User`, `Article` and `Notification`:
25
51
 
26
52
  ```ruby
27
- gem 'dirty_seed', git: 'https://github.com/BigBigDoudou/dirty_seed'
53
+ # app/models/article
54
+ class Article
55
+ belongs_to :user
56
+ has_many :notifications, as: :notifiable
57
+ end
58
+
59
+ class User
60
+ has_many :articles
61
+ has_many :notifications, as: :notifiable
62
+ end
63
+
64
+ class Notification
65
+ belongs_to :notifiable, polymorphic: true
66
+ end
28
67
  ```
29
68
 
30
- And then execute:
31
- ```bash
32
- $ bundle
69
+ ### Value assignment
70
+
71
+ A value is assigned for each attribute, depending on its type.
72
+
73
+ Special types (`hstore`, `json`, `jsonb`, `array`...) are currently ignored (no value assignment).
74
+
75
+ For instance, given the following schema:
76
+
77
+ ```ruby
78
+ # db/schema.rb
79
+ create_table 'things' do |t|
80
+ t.binary 'a_binary'
81
+ t.boolean 'a_boolean'
82
+ t.date 'a_date'
83
+ t.datetime 'a_datetime'
84
+ t.decimal 'a_decimal'
85
+ t.integer 'an_integer'
86
+ t.float 'a_float'
87
+ t.string 'a_string'
88
+ t.text 'a_text'
89
+ t.time 'a_time'
90
+ end
91
+ ```
92
+
93
+ ...then a dirty seeded `thing` looks like:
94
+
95
+ ```ruby
96
+ {
97
+ id: 1,
98
+ a_binary: '13',
99
+ a_boolean: false,
100
+ a_date: Wed, '02 Dec 2020',
101
+ a_datetime: 'Sun, 08 Nov 2020 03:01:34 UTC +00:00',
102
+ a_decimal: 19.8812490973183,
103
+ an_integer: 6,
104
+ a_float: 28.825997012616263,
105
+ a_string: 'Maxime eum ratione ab quod nihil.',
106
+ a_text: 'Autem non in est dolore.',
107
+ a_time: 'Sat, 01 Jan 2000 09:31:22 UTC +00:00'
108
+ }
109
+ ```
110
+
111
+ ### Ignored attributes
112
+
113
+ Some "special" attributes are not getting a value because:
114
+ - Rails assigns it (STI type...);
115
+ - or the RDBMS (PostgreSQL, SQLite...) assigns it;
116
+ - or it is used in specific cases (authentication...).
117
+
118
+ These attributes are currently:
119
+
120
+ - `id`
121
+ - `created_at`
122
+ - `updated_at`
123
+ - `type` (for STI)
124
+ - `encrypted_password` (authentication usage)
125
+ - `reset_password_token` (authentication usage)
126
+ - `reset_password_sent_at` (authentication usage)
127
+ - `remember_created_at` (authentication usage)
128
+
129
+ ### Associations
130
+
131
+ For attributes related to an association, an instance matching the `belongs_to` is assigned.
132
+
133
+ Polymorphic associations work too and only an instance of a model that `has_one` or `has_many` of this association can be assigned.
134
+
135
+ For instance, given the following schema:
136
+
137
+ ```ruby
138
+ # schema.rb
139
+ create_table :notifications do |t|
140
+ t.references :thing
141
+ t.references :notifiable, polymorphic: true, null: false
142
+ t.references :foo, null: false, foreign_key: { to_table: :things }
143
+ end
144
+ ```
145
+
146
+ ...and the models:
147
+
148
+ ```ruby
149
+ # app/models/notification.rb
150
+ class Notification < ApplicationRecord
151
+ belongs_to :notifiable, polymorphic: true
152
+ belongs_to :thing
153
+ belongs_to :bar, class_name: 'Thing', foreign_key: :foo_id
154
+ end
155
+
156
+ # app/models/user.rb
157
+ class User < ApplicationRecord
158
+ has_many :notifications, as: :notifiable
159
+ end
33
160
  ```
34
161
 
162
+ ...then a dirty seeded `notification` looks like:
163
+
164
+ ```ruby
165
+ {
166
+ :id => 1,
167
+ :thing_id => 42,
168
+ :notifiable_type => 'User',
169
+ :notifiable_id => 6,
170
+ :foo_id => 75
171
+ }
172
+
173
+ notification.notifiable.class # User
174
+ notification.thing.class # Thing
175
+ notification.bar.class # Thing
176
+ ```
177
+
178
+ ### Validations
179
+
180
+ For attributes requiring validations, assigned value is adapted.
181
+
182
+ Currently, only the following validations are treated:
183
+
184
+ - `numericality: { greater_than: x }`
185
+ - `numericality: { greater_than_or_equal_to: x }`
186
+ - `numericality: { lesser_than: x }`
187
+ - `numericality: { lesser_than_or_equal_to: x }`
188
+ - `numericality: { in: x..y }`
189
+
190
+ Much more validations will be treated soon: `uniqueness`, `absence`, `inclusion`, `exclusion`, `length`...
191
+
192
+ Custom validations are not inspected.
193
+
194
+ ### Meaning detection
195
+
196
+ Some string attribute meanings are guessed by name: `email`, `first_name`, `latitude`...
197
+
198
+ Values are then built with the `faker` gem.
199
+
200
+ For instance, given the following schema:
201
+
202
+ ```ruby
203
+ # db/schema.rb
204
+ create_table "users" do |t|
205
+ t.string "first_name"
206
+ t.string "last_name"
207
+ t.string "address"
208
+ t.string "city"
209
+ t.string "country"
210
+ t.string "email"
211
+ t.string "password"
212
+ t.string "phone"
213
+ t.string "username"
214
+ # ...
215
+ end
216
+ ```
217
+
218
+ ...then a dirty seeded `user` looks like:
219
+
220
+ ```ruby
221
+ {
222
+ id: 1,
223
+ first_name: 'Emory',
224
+ last_name: 'Franecki',
225
+ address: '843 Schneider Squares, Port Olenmouth, TN 12657',
226
+ city: 'Torpshire',
227
+ country: 'United Arab Emirates',
228
+ email: 'scottie_friesen@example.net',
229
+ password: 'ZkUtNtFg4L',
230
+ phone: '(814) 382-6102 x036',
231
+ username: 'ernestine_rau',
232
+ # ...
233
+ }
234
+ ```
235
+
236
+ The current attribute names treated this way are:
237
+
238
+ - `address`
239
+ - `city`
240
+ - `country`
241
+ - `description`
242
+ - `email`
243
+ - `first_name`
244
+ - `firstname`
245
+ - `last_name`
246
+ - `lastname`
247
+ - `lat`
248
+ - `latitute`
249
+ - `lng`
250
+ - `locale`
251
+ - `longitude`
252
+ - `middlename`
253
+ - `middle_name`
254
+ - `password`
255
+ - `phone`
256
+ - `phone_number`
257
+ - `reference`
258
+ - `title`
259
+ - `user_name`
260
+ - `username`
261
+ - `uuid`
262
+
263
+ More meanings will be added and will extend the mechanism to other formats (e.g. an `age` integer).
264
+
35
265
  ## License
36
266
 
37
267
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
38
268
 
39
269
  ## Next features
40
270
 
271
+ * Add a configuration system to define how to seed: number of instances, models to skip, default values, etc.
41
272
  * Assign values for more data types (json, array, etc.).
273
+ * Detect more "special" attributes to ignore.
42
274
  * Integrate more validations (uniqueness, inclusion, length, absence, etc.).
43
- * Use instance errors to adjust values.
44
- * Add a configuration system to define how to seed: number of instances, models to skip, default values, etc.
275
+ * Detect more meanings and extend it to other formats.
276
+ * Use instance errors to adjust values and eventually match custom validations.
277
+
278
+
@@ -2,7 +2,7 @@
2
2
 
3
3
  module DirtySeed
4
4
  module Assigners
5
- # Draws a boolean value matching validators
5
+ # Draws a value matching validators
6
6
  class DirtyBoolean < DirtyAssigner
7
7
  # Returns a boolean
8
8
  # @return [Boolean]
@@ -2,7 +2,7 @@
2
2
 
3
3
  module DirtySeed
4
4
  module Assigners
5
- # Draws a Date matching validators
5
+ # Draws a value matching validators
6
6
  class DirtyDate < DirtyAssigner
7
7
  # Returns a date matching all validators
8
8
  # @return [Date]
@@ -4,7 +4,7 @@ module DirtySeed
4
4
  module Assigners
5
5
  # Draws an Float matching validators
6
6
  class DirtyFloat < DirtyAssigner
7
- # Returns a float matching all validators
7
+ # Returns a value matching all validators
8
8
  # @return [Float]
9
9
  def value
10
10
  integer + decimals
@@ -12,13 +12,13 @@ module DirtySeed
12
12
 
13
13
  private
14
14
 
15
- # Returns an Integer matching all validators
15
+ # Returns a value matching all validators
16
16
  # @return [Integer]
17
17
  def integer
18
18
  DirtySeed::Assigners::DirtyInteger.new(dirty_attribute, 0).value
19
19
  end
20
20
 
21
- # Returns a Float between 0 and 1
21
+ # Returns a value between 0 and 1
22
22
  # @return [Float]
23
23
  def decimals
24
24
  rand(0..Float(1))
@@ -6,7 +6,7 @@ module DirtySeed
6
6
  class DirtyInteger < DirtyAssigner
7
7
  attr_reader :min, :max
8
8
 
9
- # Returns an integer matching all validators
9
+ # Returns an value matching all validators
10
10
  # @return [Integer]
11
11
  def value
12
12
  define_min_and_max
@@ -31,7 +31,7 @@ module DirtySeed
31
31
  end
32
32
  end
33
33
 
34
- # Returns a random integer
34
+ # Returns a random value
35
35
  # @return [Integer]
36
36
  def random
37
37
  rand(sequence..42)
@@ -64,7 +64,7 @@ module DirtySeed
64
64
  @max = max_for(validator) if @max.nil? || max_for(validator) < @max
65
65
  end
66
66
 
67
- # Returns an integer representing the minimal acceptable value
67
+ # Returns an value representing the minimal acceptable value
68
68
  # @param validator [ActiveModel::Validations::EachValidator]
69
69
  # @return [Integer]
70
70
  def min_for(validator)
@@ -73,7 +73,7 @@ module DirtySeed
73
73
  validator.options[:in]&.min
74
74
  end
75
75
 
76
- # Returns an integer representing the maximal acceptable value
76
+ # Returns an value representing the maximal acceptable value
77
77
  # @param validator [ActiveModel::Validations::EachValidator]
78
78
  # @return [Integer]
79
79
  def max_for(validator)
@@ -4,41 +4,46 @@ module DirtySeed
4
4
  module Assigners
5
5
  # Draws a String matching validators
6
6
  class DirtyString < DirtyAssigner
7
- SPECIFIC_ATTRIBUTES = {
8
- address: -> { Faker::Address.unique.full_address },
9
- city: -> { Faker::Address.unique.city },
10
- country: -> { Faker::Address.unique.country },
11
- description: -> { Faker::Lorem.unique.paragraph(sentence_count: 2, random_sentences_to_add: 4) },
12
- email: -> { Faker::Internet.unique.email(domain: 'example') },
13
- first_name: -> { ::Faker::Name.unique.first_name },
14
- firstname: -> { ::Faker::Name.unique.first_name },
15
- last_name: -> { ::Faker::Name.unique.last_name },
16
- lastname: -> { ::Faker::Name.unique.last_name },
17
- lat: -> { Faker::Address.unique.latitude },
18
- latitutde: -> { Faker::Address.unique.latitude },
19
- lng: -> { Faker::Address.unique.longitude },
20
- locale: -> { Faker::Address.unique.country_code },
21
- longitude: -> { Faker::Address.unique.longitude },
22
- middlename: -> { ::Faker::Name.unique.middle_name },
23
- middle_name: -> { ::Faker::Name.unique.middle_name },
24
- password: -> { ::Faker::Internet.unique.password },
25
- phone: -> { Faker::PhoneNumber.unique.phone_number },
26
- phone_number: -> { Faker::PhoneNumber.unique.phone_number },
27
- reference: -> { Faker::Internet.unique.uuid },
28
- title: -> { Faker::Lorem.unique.sentence(word_count: 3, random_words_to_add: 4) },
29
- username: -> { Faker::Internet.unique.username }
30
- }.freeze
31
- private_constant :SPECIFIC_ATTRIBUTES
32
-
33
- # Returns a string matching all validators
7
+ # Returns a value matching all validators
34
8
  # @return [String]
35
9
  # @note First try to guess attribute meaning by its name and use Faker to return a coherent value
36
10
  def value
37
- SPECIFIC_ATTRIBUTES[dirty_attribute.name]&.call || default
11
+ specific = specific_attributes[dirty_attribute.name]
12
+ return faker_value(specific) if specific
13
+
14
+ default
38
15
  end
39
16
 
40
17
  private
41
18
 
19
+ # Returns specific attributes
20
+ # @return [Hash]
21
+ # @example
22
+ # { address: { category: 'Address', method: 'full_address' } }
23
+ def specific_attributes
24
+ YAML.safe_load(
25
+ File.read(
26
+ DirtySeed::Engine.root.join('lib', 'dirty_seed', 'assigners', 'fakers.yml')
27
+ )
28
+ ).deep_symbolize_keys
29
+ end
30
+
31
+ # Returns a value matching the requirements
32
+ # @param category [Symbol] fake category
33
+ # @param method [Symbol] fake method
34
+ # @param unique [Boolean] should the value be unique
35
+ # @param options [Hash] options used by faker
36
+ # @return [String]
37
+ def faker_value(category:, method:, unique: false, options: nil)
38
+ action = "::Faker::#{category}".constantize
39
+ action = action.unique if unique
40
+ if options
41
+ action.public_send(method, options)
42
+ else
43
+ action.public_send(method)
44
+ end
45
+ end
46
+
42
47
  # Returns a standard string
43
48
  # @return [String]
44
49
  def default