planter 0.0.13 → 0.1.2

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: 23a4116a1fe8a8d499e8522e5d4da4dadd76cb95ba917d54855f36adeaec519f
4
- data.tar.gz: 523fcef8dd453614e4c1045aafd1ae57b54e7b6043c4fac3b3638ef35c577862
3
+ metadata.gz: 39fe6b05679379fdcf8c619b1db28fdac6a6f89eec521b3e8cf3f3667a471c49
4
+ data.tar.gz: 42693cdccc9239a069996c74455edc658b339a894eff5b984ec00bba47a88797
5
5
  SHA512:
6
- metadata.gz: eb5d69e3807c0595c4a149cc0eeb487712a18381d86cad82a9e459ca28a19286c77e35b92820932b9be3ced37563632f7d8a27d1a85bf15c55621895bc5f923b
7
- data.tar.gz: 9d32d66773a92b393fdac8a90a67ca410251588d61270a35ba8a21f8d1afe74963c5ef81702fffc33ffb59674b7fb953029f19d887f17a26bd7a5b7ae3522df3
6
+ metadata.gz: c3ffd760187e67c1f57b7daf7a1bba7f019470f1324ddaf72d1412c34930ea520eea449aebd0cea43b6b48de948f93ba80f47bafe6de782f550c35daf0bb8508
7
+ data.tar.gz: cfd8daff8e7d45a9d72411c195b31be7d1ddde9b562a03397b43f0848360c701d569289ab32e3260bf03f765752cd81fa123f3b597d9b08cc69ac9a6cab7bb6f
data/README.md CHANGED
@@ -144,8 +144,8 @@ class UsersSeeder < Planter::Seeder
144
144
  end
145
145
  ```
146
146
 
147
- `ERB` can be used in the CSV files if you end the file name with `.csv.erb`.
148
- For example, `users.csv.erb`.
147
+ `ERB` can be used in the CSV files if you end the file name with `.csv.erb` or
148
+ `.erb.csv`. For example, `users.csv.erb`.
149
149
 
150
150
  ```
151
151
  participant_id,name
@@ -207,13 +207,16 @@ Running `rails planter:seed` should now seed your `users` table.
207
207
 
208
208
  You can also seed children records for every existing record of a parent model.
209
209
  For example, to seed an address for every user, you'd need to create an
210
- `AddressesSeeder` that uses the `parent_model` option, as seen below.
210
+ `AddressesSeeder` that uses the `parent` option, as seen below. This option
211
+ should be the name of the `belongs_to` association in your model. The primary
212
+ key, foreign key, and model name of the parent will all be determined by
213
+ reflecting on the association.
211
214
 
212
215
  ```ruby
213
216
  require 'faker'
214
217
 
215
218
  class AddressesSeeder < Planter::Seeder
216
- seeding_method :data_array, parent_model: 'User'
219
+ seeding_method :data_array, parent: :user
217
220
 
218
221
  def data
219
222
  [{
@@ -227,9 +230,7 @@ end
227
230
  ```
228
231
 
229
232
  Note that specifying `number_of_records` in this instance will create that many
230
- records *for each record of the parent model*. You can also specify the
231
- association if it's different from the table name, using the `:assocation`
232
- option.
233
+ records *for each record of the parent model*.
233
234
 
234
235
  ### Custom seeds
235
236
  To write your own custom seeds, just overload the `seed` method and do whatever
@@ -26,7 +26,7 @@ module Planter
26
26
  # Another way to seed is to create records from a data array. To do this,
27
27
  # your class must implement a +data+ attribute or method, which is an array
28
28
  # of hashes. Note that this class already provides the +attr_reader+ for this
29
- # attribute, so the most you have to do it create instance variables in your
29
+ # attribute, so the most you have to do is create instance variables in your
30
30
  # constructor. If if you want your data to be different for each new record
31
31
  # (via Faker, +Array#sample+, etc.), you'll probably want to supply a method
32
32
  # called data that returns an array of new data each time.
@@ -38,15 +38,17 @@ module Planter
38
38
  # end
39
39
  # end
40
40
  #
41
- # In both of the above methods, you can specify +parent_model+ and
42
- # +association+. If specified, records will be created via that parent
43
- # model's association. If +association+ is not provided, it will be assumed
44
- # to be the model name, pluralized and snake-cased (implying a +has_many+
45
- # relationship). For example, if we're seeding the users table, and the
46
- # model is +User+, the association will default to +users+.
41
+ # In both of the above methods, you can specify a +parent+ association, which
42
+ # is the +belongs_to+ association name in your model, which, when specified,
43
+ # records will be created for each record in the parent table. For example,
44
+ # if we're seeding the users table, and the model is +User+, which belongs to
45
+ # +Person+, then doing the following will create a user record for each
46
+ # record in the Person table. Note that nothing is automatically done to
47
+ # prevent any validation errors; you must do this on your own, mostly likely
48
+ # using +Faker+ or a similar library.
47
49
  # require 'planter'
48
50
  # class UsersSeeder < Planter::Seeder
49
- # seeding_method :data_array, parent_model: 'Person', association: :users
51
+ # seeding_method :data_array, parent: :person
50
52
  # def data
51
53
  # [{foo: 'bar', baz: 'bar'}]
52
54
  # end
@@ -54,9 +56,8 @@ module Planter
54
56
  #
55
57
  # You can also set +number_of_records+ to determine how many times each
56
58
  # record in the +data+ array will get created. The default is 1. Note that if
57
- # this attribute is set alongside +parent_model+ and +association+,
58
- # +number_of_records+ will be how many records will be created for each
59
- # record in the parent table.
59
+ # this attribute is set alongside +parent+, +number_of_records+ will be how
60
+ # many records will be created for each record in the parent table.
60
61
  # require 'planter'
61
62
  # class UsersSeeder < Planter::Seeder
62
63
  # seeding_method :data_array, number_of_records: 5
@@ -127,7 +128,7 @@ module Planter
127
128
  # class must set this attribute via +seeding_method+.
128
129
  #
129
130
  # @return [String]
130
- class_attribute :parent_model
131
+ class_attribute :parent
131
132
 
132
133
  ##
133
134
  # The number of records to create from each record in the +data+ array. If
@@ -137,116 +138,72 @@ module Planter
137
138
  # @return [Integer]
138
139
  class_attribute :number_of_records
139
140
 
140
- ##
141
- # When using +parent_model+, the association name. Your class can set this
142
- # attribute via +seeding_method+.
143
- #
144
- # @return [Symbol]
145
- class_attribute :association
146
-
147
141
  ##
148
142
  # The csv file corresponding to the model.
149
143
  #
150
144
  # @return [String]
151
- class_attribute :csv_file
145
+ class_attribute :csv_name
152
146
 
153
147
  ##
154
148
  # The seeding method specified.
155
149
  #
156
150
  # @return [Symbol]
157
- class_attribute :seeding_method
151
+ class_attribute :seed_method
158
152
 
159
153
  ##
160
- # Access the metaclass so we can define public and private class methods.
161
- class << self
162
- ##
163
- # If your class is going to use the inherited +seed+ method, you must tell
164
- # it which +seeding_method+ to use. The argument to this method must be
165
- # included in the +SEEDING_METHODS+ array.
166
- #
167
- # @param [Symbol] seeding_method
168
- #
169
- # @kwarg [Integer] number_of_records
170
- #
171
- # @kwarg [String] model
172
- #
173
- # @kwarg [String] parent_model
174
- #
175
- # @kwarg [Symbol, String] association
176
- #
177
- # @kwarg [Symbol, String] csv_name
178
- #
179
- # @kwarg [Symbol, String] unique_columns
180
- #
181
- # @kwarg [String] erb_trim_mode
182
- #
183
- # @example
184
- # require 'planter'
185
- # class UsersSeeder < Planter::Seeder
186
- # seeding_method :csv,
187
- # number_of_records: 2,
188
- # model: 'User'
189
- # parent_model: 'Person',
190
- # association: :users,
191
- # csv_name: :awesome_users,
192
- # unique_columns %i[username email],
193
- # erb_trim_mode: '<>'
194
- # end
195
- def seeding_method(
196
- method,
197
- number_of_records: 1,
198
- model: nil,
199
- parent_model: nil,
200
- association: nil,
201
- csv_name: nil,
202
- unique_columns: nil,
203
- erb_trim_mode: nil
204
- )
205
- if !SEEDING_METHODS.include?(method.intern)
206
- raise ArgumentError, "Method must be: #{SEEDING_METHODS.join(', ')}"
207
- elsif association && !parent_model
208
- raise ArgumentError, "Must specify :parent_model with :association"
209
- end
210
-
211
- self.seeding_method = method
212
- self.number_of_records = number_of_records
213
- self.model = model || to_s.delete_suffix('Seeder').singularize
214
- self.parent_model = parent_model
215
- self.association = parent_model && (association || determine_association)
216
- self.csv_file = determine_csv_filename(csv_name) if seeding_method == :csv
217
- self.erb_trim_mode = erb_trim_mode || Planter.config.erb_trim_mode
218
- self.unique_columns =
219
- case unique_columns
220
- when String, Symbol then [unique_columns.intern]
221
- when Array then unique_columns.map(&:intern)
222
- end
223
- end
224
-
225
- private
226
-
227
- def determine_association # :nodoc:
228
- associations =
229
- parent_model.constantize.reflect_on_all_associations.map(&:name)
230
- table = to_s.delete_suffix('Seeder').underscore.split('/').last
231
-
232
- [table, table.singularize].map(&:intern).each do |t|
233
- return t if associations.include?(t)
234
- end
235
-
236
- raise ArgumentError, "Couldn't determine association name"
154
+ # If your class is going to use the inherited +seed+ method, you must tell
155
+ # it which +seeding_method+ to use. The argument to this method must be
156
+ # included in the +SEEDING_METHODS+ array.
157
+ #
158
+ # @param [Symbol] seed_method
159
+ #
160
+ # @kwarg [Integer] number_of_records
161
+ #
162
+ # @kwarg [String] model
163
+ #
164
+ # @kwarg [Symbol, String] parent
165
+ #
166
+ # @kwarg [Symbol, String] csv_name
167
+ #
168
+ # @kwarg [Symbol, String] unique_columns
169
+ #
170
+ # @kwarg [String] erb_trim_mode
171
+ #
172
+ # @example
173
+ # require 'planter'
174
+ # class UsersSeeder < Planter::Seeder
175
+ # seeding_method :csv,
176
+ # number_of_records: 2,
177
+ # model: 'User'
178
+ # parent: :person,
179
+ # csv_name: :awesome_users,
180
+ # unique_columns %i[username email],
181
+ # erb_trim_mode: '<>'
182
+ # end
183
+ def self.seeding_method(
184
+ seed_method,
185
+ number_of_records: 1,
186
+ model: nil,
187
+ parent: nil,
188
+ csv_name: nil,
189
+ unique_columns: nil,
190
+ erb_trim_mode: nil
191
+ )
192
+ if !SEEDING_METHODS.include?(seed_method.intern)
193
+ raise ArgumentError, "Method must be: #{SEEDING_METHODS.join(', ')}"
237
194
  end
238
195
 
239
- def determine_csv_filename(csv_name) # :nodoc:
240
- file = (
241
- csv_name || "#{to_s.delete_suffix('Seeder').underscore}"
242
- ).to_s + '.csv'
243
- [file, "#{file}.erb"].each do |f|
244
- fname = Rails.root.join(Planter.config.csv_files_directory, f).to_s
245
- return fname if ::File.file?(fname)
196
+ self.seed_method = seed_method
197
+ self.number_of_records = number_of_records
198
+ self.model = model || to_s.delete_suffix('Seeder').singularize
199
+ self.parent = parent
200
+ self.csv_name = csv_name || to_s.delete_suffix('Seeder').underscore
201
+ self.erb_trim_mode = erb_trim_mode || Planter.config.erb_trim_mode
202
+ self.unique_columns =
203
+ case unique_columns
204
+ when String, Symbol then [unique_columns.intern]
205
+ when Array then unique_columns.map(&:intern)
246
206
  end
247
-
248
- raise ArgumentError, "Couldn't find csv for #{model}"
249
- end
250
207
  end
251
208
 
252
209
  ##
@@ -254,8 +211,9 @@ module Planter
254
211
  # valid +seeding_method+, and not implement its own +seed+ method.
255
212
  def seed
256
213
  validate_attributes
214
+ extract_data_from_csv if seed_method == :csv
257
215
 
258
- parent_model ? create_records_from_parent : create_records
216
+ parent ? create_records_from_parent : create_records
259
217
  end
260
218
 
261
219
  protected
@@ -263,69 +221,82 @@ module Planter
263
221
  ##
264
222
  # Creates records from the +data+ attribute.
265
223
  def create_records
266
- data.each do |rec|
267
- number_of_records.times do
268
- rec.transform_values { |value| value == 'NULL' ? nil : value }
269
- unique, attrs = split_record(rec)
270
- model.constantize.where(unique).first_or_create!(attrs)
271
- end
272
- end
224
+ data.each { |record| create_record(record) }
273
225
  end
274
226
 
275
227
  ##
276
- # Create records from the +data+ attribute for each record in the
277
- # +parent_table+, via the specified +association+.
228
+ # Create records from the +data+ attribute for each record in the +parent+.
278
229
  def create_records_from_parent
279
- parent_model.constantize.all.each do |assoc_rec|
280
- number_of_records.times do
281
- data.each { |rec| send(create_method, assoc_rec, association, rec) }
282
- end
230
+ parent_model.constantize.pluck(primary_key).each do |parent_id|
231
+ data.each { |record| create_record(record, parent_id: parent_id) }
283
232
  end
284
233
  end
285
234
 
286
- private
287
-
288
- def create_method # :nodoc:
289
- parent_model.constantize.reflect_on_association(
290
- association
291
- ).macro.to_s.include?('many') ? :create_has_many : :create_has_one
292
- end
293
-
294
- def create_has_many(assoc_rec, association, rec) # :nodoc:
295
- unique, attrs = split_record(rec)
296
- assoc_rec.public_send(association).where(unique).first_or_create!(attrs)
297
- end
298
-
299
- def create_has_one(assoc_rec, association, rec) # :nodoc:
300
- if assoc_rec.public_send(association)
301
- assoc_rec.public_send(association).update_attributes(rec)
302
- else
303
- assoc_rec.public_send("create_#{association}", rec)
235
+ def create_record(record, parent_id: nil)
236
+ number_of_records.times do
237
+ unique, attrs = split_record(record)
238
+ model.constantize.where(
239
+ unique.tap { |u| u[foreign_key] = parent_id if parent_id }
240
+ ).first_or_create!(attrs)
304
241
  end
305
242
  end
306
243
 
307
244
  def validate_attributes # :nodoc:
308
- case seeding_method.intern
245
+ case seed_method.intern
309
246
  when :csv
310
- contents = ::File.read(csv_file)
311
- if csv_file.end_with?('.erb')
312
- contents = ERB.new(contents, trim_mode: erb_trim_mode).result(binding)
313
- end
314
-
315
- @data ||= ::CSV.parse(
316
- contents, headers: true, header_converters: :symbol
317
- ).map(&:to_hash)
247
+ raise "Couldn't find csv for #{model}" unless full_csv_name
318
248
  when :data_array
319
- raise "Must define '@data'" if public_send(:data).nil?
249
+ raise 'data is not defined in the seeder' if public_send(:data).nil?
320
250
  else
321
- raise("Must set 'seeding_method'")
251
+ raise 'seeding_method not defined in the seeder'
322
252
  end
323
253
  end
324
254
 
325
255
  def split_record(rec) # :nodoc:
326
256
  return [rec, {}] unless unique_columns
257
+
327
258
  u = unique_columns.each_with_object({}) { |c, h| h[c] = rec.delete(c) }
328
259
  [u, rec]
329
260
  end
261
+
262
+ def association_options
263
+ @association_options ||=
264
+ model.constantize.reflect_on_association(parent).options
265
+ end
266
+
267
+ def primary_key
268
+ @primary_key ||=
269
+ association_options.fetch(:primary_key, :id)
270
+ end
271
+
272
+ def foreign_key
273
+ @foreign_key ||=
274
+ association_options.fetch(:foreign_key, "#{parent}_id")
275
+ end
276
+
277
+ def parent_model
278
+ @parent_model ||=
279
+ association_options.fetch(:class_name, parent.to_s.classify)
280
+ end
281
+
282
+ def full_csv_name
283
+ @full_csv_name ||=
284
+ %W[#{csv_name}.csv #{csv_name}.csv.erb #{csv_name}.erb.csv]
285
+ .map { |f| Rails.root.join(Planter.config.csv_files_directory, f).to_s }
286
+ .find { |f| ::File.file?(f) }
287
+ end
288
+
289
+ def extract_data_from_csv
290
+ contents = ::File.read(full_csv_name)
291
+ if full_csv_name.include?('.erb')
292
+ contents = ERB.new(contents, trim_mode: erb_trim_mode).result(binding)
293
+ end
294
+
295
+ @data ||= ::CSV.parse(
296
+ contents,
297
+ headers: true,
298
+ header_converters: :symbol
299
+ ).map(&:to_hash)
300
+ end
330
301
  end
331
302
  end
@@ -15,13 +15,13 @@ module Planter
15
15
  # Minor version.
16
16
  #
17
17
  # @return [Integer]
18
- MINOR = 0
18
+ MINOR = 1
19
19
 
20
20
  ##
21
21
  # Patch version.
22
22
  #
23
23
  # @return [Integer]
24
- PATCH = 13
24
+ PATCH = 2
25
25
 
26
26
  ##
27
27
  # Version as +[MAJOR, MINOR, PATCH]+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: planter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.13
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Gray
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-27 00:00:00.000000000 Z
11
+ date: 2021-12-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -16,20 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 6.1.3
20
- - - ">="
21
- - !ruby/object:Gem::Version
22
- version: 6.1.3.1
19
+ version: 6.1.4.4
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
24
  - - "~>"
28
25
  - !ruby/object:Gem::Version
29
- version: 6.1.3
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: 6.1.3.1
26
+ version: 6.1.4.4
33
27
  description: Create a seeder for each table in your database, and easily seed from
34
28
  CSV or custom methods
35
29
  email: