data_seeder 0.0.5 → 1.0.0

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +71 -98
  3. data/app/models/data_seeder/seed_file.rb +54 -14
  4. data/lib/data_seeder.rb +30 -10
  5. data/lib/data_seeder/config.rb +39 -17
  6. data/lib/data_seeder/loader.rb +80 -85
  7. data/lib/data_seeder/loader/csv.rb +2 -1
  8. data/lib/data_seeder/loader/txt.rb +1 -6
  9. data/lib/data_seeder/loader/yaml.rb +1 -1
  10. data/lib/data_seeder/version.rb +1 -1
  11. data/test/dummy/app/models/app_error_data_seeder.rb +10 -8
  12. data/test/dummy/app/models/country.rb +0 -12
  13. data/test/dummy/db/development.sqlite3 +0 -0
  14. data/test/dummy/db/seed.test/{bar.err → bar_err/bar.err} +0 -0
  15. data/test/dummy/db/seed.test/countries_csv/countries.cfg +9 -0
  16. data/test/dummy/db/seed.test/countries_csv/countries.csv +249 -0
  17. data/test/dummy/db/seed.test/countries_txt/countries.cfg +6 -0
  18. data/test/dummy/db/seed.test/{countries.txt → countries_txt/countries.txt} +0 -0
  19. data/test/dummy/db/seed.test/{foo.err → foo_err/foo.err} +0 -0
  20. data/test/dummy/db/seed.test/{states.csv → states_csv/states.csv} +0 -0
  21. data/test/dummy/db/seed.test/states_json/states.cfg +1 -0
  22. data/test/dummy/db/seed.test/{states.json → states_json/states.json} +0 -1
  23. data/test/dummy/db/seed.test/states_txt/states.cfg +6 -0
  24. data/test/dummy/db/seed.test/{states.txt → states_txt/states.txt} +0 -1
  25. data/test/dummy/db/seed.test/states_yml/states.cfg +1 -0
  26. data/test/dummy/db/seed.test/{states.yml → states_yml/states.yml} +0 -1
  27. data/test/dummy/db/seed.test/{zulu.err → zulu_err/zulu.err} +0 -0
  28. data/test/dummy/db/test.sqlite3 +0 -0
  29. data/test/dummy/log/development.log +126 -0
  30. data/test/dummy/log/test.log +90945 -0
  31. data/test/models/data_seeder_test.rb +50 -30
  32. metadata +33 -20
  33. data/lib/data_seeder/logger.rb +0 -15
@@ -2,68 +2,42 @@ require 'English'
2
2
 
3
3
  module DataSeeder
4
4
  module Loader
5
- attr_accessor :file_config, :key_attribute
6
- attr_reader :path, :path_minus_ext
7
-
8
- def initialize(options={})
9
- @only = options[:only]
10
- @except = options[:except]
11
- if options.has_key?(:purge)
12
- @purge = options[:purge]
13
- else
14
- @purge = true
15
- end
16
- @old_keys = []
17
- end
18
-
19
- def config
20
- DataSeeder.config
5
+ attr_reader :seeder_config, :config, :key_attribute, :klass, :path, :path_minus_ext
6
+
7
+ def initialize(config)
8
+ @seeder_config = DataSeeder.config
9
+ @config = config
10
+ @key_attribute = config[:key_attribute] || :id
11
+ @klass = config[:klass]
12
+ @path = config[:path]
13
+ @path_minus_ext = config[:path_minus_ext]
14
+ # Default purge to true if unspecified
15
+ @config[:purge] = true unless config.has_key?(:purge)
16
+ @old_ids = Set.new
21
17
  end
22
18
 
23
19
  def logger
24
- DataSeeder.logger
25
- end
26
-
27
- def klass!
28
- @path_minus_ext.classify.constantize
29
- rescue NameError => e
30
- raise "#{@path} doesn't match a corresponding model"
31
- end
32
-
33
- def klass
34
- # This should always translate to a class except for custom loaders
35
- @path_minus_ext.classify.constantize rescue nil
20
+ @seeder_config.logger
36
21
  end
37
22
 
38
- def process(path)
39
- @path = path
40
- dot_index = @path.rindex('.')
41
- @path_minus_ext = @path[0, dot_index]
42
- @file_config = {}
43
- cfg_file = "#{@path_minus_ext}.cfg"
44
- @file_config = eval(File.read(cfg_file)) if File.exist?(cfg_file)
45
- File.open(@path, 'r') do |fin|
46
- load_file_config(fin) if @file_config.empty?
47
- @file_config = ActiveSupport::HashWithIndifferentAccess.new(@file_config)
48
- setup
49
- load(fin)
50
- teardown
51
- end
52
- call_file_method(:teardown)
23
+ def process(io)
24
+ setup
25
+ load(io)
26
+ teardown
53
27
  end
54
28
 
55
29
  def setup
56
- @key_attribute = self.file_config[:key_attribute] || :id
57
- @old_keys = self.klass!.all.pluck(@key_attribute).map(&:to_s) if @purge
58
- logger.info { "Loading #{@path}" }
59
- call_file_method(:setup)
30
+ @old_ids = klass.all.pluck(:id).to_set if config[:purge]
60
31
  end
61
32
 
62
33
  def teardown
63
- @old_keys.each do |key|
64
- if model = self.klass!.find_by(@key_attribute => key)
65
- logger.info { " Destroying #{model_info(model)}"}
66
- model.destroy
34
+ destroy_models(klass, @old_ids)
35
+ end
36
+
37
+ def destroy_models(klass, ids)
38
+ ids.each do |id|
39
+ if model = klass.find_by(id: id)
40
+ destroy_model(model)
67
41
  end
68
42
  end
69
43
  end
@@ -72,68 +46,89 @@ module DataSeeder
72
46
  # The changes argument will be the model.changes on an update.
73
47
  def model_info(model, changes=nil)
74
48
  if changes
75
- attr = @file_config[:update_display_method] || @key_attribute
76
- "#{model.send(attr)}: #{changes.inspect}"
49
+ if attr = config[:update_display_method]
50
+ "#{model.send(attr)}: #{changes.inspect}"
51
+ elsif @key_attribute.kind_of?(Enumerable)
52
+ label = @key_attribute.map {|k| "#{k}=#{model.send(k)}"}.join(' ')
53
+ "#{label}: #{changes.inspect}"
54
+ else
55
+ "#{model.send(@key_attribute)}: #{changes.inspect}"
56
+ end
77
57
  else
78
58
  model.inspect
79
59
  end
80
60
  end
81
61
 
82
- def load_file_config(fin)
83
- config_line = fin.readline
84
- if match = config_line.match(/^\s*#\s*config:(.*)/)
85
- @file_config = eval(match[1])
86
- else
87
- fin.seek(0)
88
- if self.klass && self.klass.respond_to?(:data_seeder_config)
89
- @file_config = self.klass.data_seeder_config
90
- end
91
- end
92
- end
93
-
94
- def load(fin)
62
+ def load(io)
95
63
  throw 'Must override load'
96
64
  end
97
65
 
66
+ # This doesn't work in some versions of JRuby (version 9.0.3.0?)
98
67
  def line_number
99
68
  $INPUT_LINE_NUMBER
100
69
  end
101
70
 
102
71
  def save(attr)
103
- if @file_config[:use_line_number_as_id]
104
- key = self.line_number
72
+ attr = call_method(:postprocess, attr) || attr
73
+ if config[:use_line_number_as_id]
74
+ find_hash = { @key_attribute => self.line_number }
75
+ elsif @key_attribute.kind_of?(Enumerable)
76
+ find_hash = {}
77
+ @key_attribute.each do |k|
78
+ find_hash[k] = attr[k.to_s] || attr[k.to_sym]
79
+ end
105
80
  else
106
81
  key = attr[@key_attribute.to_s] || attr[@key_attribute.to_sym]
107
82
  raise "No #{@key_attribute} in #{attr.inspect}" unless key
83
+ find_hash = { @key_attribute => key }
108
84
  end
109
- if method = @file_config[:postprocess]
110
- method.call(attr)
111
- elsif self.klass!.respond_to?(:data_seeder_postprocess)
112
- self.klass!.send(:data_seeder_postprocess, attr)
113
- end
114
- @old_keys.delete(key.to_s)
115
- model = self.klass!.find_or_initialize_by(@key_attribute => key)
85
+ model = self.klass.find_or_initialize_by(find_hash)
116
86
  model.attributes = attr
117
87
  save_model(model)
118
88
  end
119
89
 
120
90
  def save_model(model)
121
91
  if model.new_record?
122
- logger.info { " Saving #{model_info(model)}" }
92
+ log_save(model)
123
93
  else
124
- changes = model.changes
125
- return if changes.empty?
126
- logger.info { " Updating #{model_info(model, changes)}" }
94
+ @old_ids.delete(model.id)
95
+ return unless model.changed?
96
+ log_update(model)
127
97
  end
128
98
  model.save!
129
99
  end
130
100
 
131
- def call_file_method(name, *args)
132
- if method = @file_config[name]
133
- return method.call(*args)
134
- else
135
- class_method = "data_seeder_#{name}"
136
- return self.klass.send(class_method, *args) if @klass.respond_to?(class_method)
101
+ # Allow override for potential soft-delete
102
+ def destroy_model(model)
103
+ log_destroy(model)
104
+ model.destroy
105
+ end
106
+
107
+ def log_save(model)
108
+ logger.debug { "Saving #{model_info(model)}" }
109
+ end
110
+
111
+ def log_update(model)
112
+ logger.debug { "Updating #{model_info(model, model.changes)}" }
113
+ end
114
+
115
+ def log_destroy(model)
116
+ logger.debug { "Destroying #{model_info(model)}" }
117
+ end
118
+
119
+ def log_indent(&block)
120
+ @seeder_config.log_indent(&block)
121
+ end
122
+
123
+ def call_method(name, *args)
124
+ if self.respond_to?(name)
125
+ return send(name, *args)
126
+ elsif val = config[name]
127
+ if val.kind_of?(Proc)
128
+ return val.call(*args)
129
+ else
130
+ return val
131
+ end
137
132
  end
138
133
  return nil
139
134
  end
@@ -9,7 +9,8 @@ module DataSeeder
9
9
 
10
10
  def load(io)
11
11
  @line_number = 0
12
- ::CSV.foreach(io, headers: true) do |row|
12
+ csv = ::CSV.new(io, headers: true)
13
+ csv.each do |row|
13
14
  @line_number += 1
14
15
  save(row.to_hash)
15
16
  end
@@ -4,16 +4,11 @@ module DataSeeder
4
4
  include Loader
5
5
 
6
6
  def load(io)
7
- if method = self.file_config[:line]
7
+ if method = config[:line]
8
8
  io.each_line do |line|
9
9
  next if line.blank? || line.match(/^\s*#/)
10
10
  save(method.call(line))
11
11
  end
12
- elsif self.klass.respond_to?(:data_seeder_line)
13
- io.each_line do |line|
14
- next if line.blank? || line.match(/^\s*#/)
15
- save(self.klass.send(:data_seeder_line, line))
16
- end
17
12
  else
18
13
  raise "No line method defined for #{self.klass.name}"
19
14
  end
@@ -6,7 +6,7 @@ module DataSeeder
6
6
  include Loader
7
7
 
8
8
  def load(io)
9
- yaml = ::YAML.load(io.read)
9
+ yaml = ::YAML.load(ERB.new(io.read).result)
10
10
  if yaml.kind_of?(Hash)
11
11
  yaml.each do |key, attr|
12
12
  attr[self.key_attribute] = key if self.key_attribute
@@ -1,3 +1,3 @@
1
1
  module DataSeeder
2
- VERSION = "0.0.5"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -7,10 +7,10 @@ class AppErrorDataSeeder
7
7
  @app = App.find_or_initialize_by(name: self.path_minus_ext)
8
8
  @existing_errors = {}
9
9
  if @app.new_record?
10
- logger.info "Loading errors for new App: #{@app.name}"
10
+ logger.debug { "Loading errors for new App: #{@app.name}" }
11
11
  @app.save!
12
12
  else
13
- logger.info "Loading errors for existing App: #{@app.name}"
13
+ logger.debug { "Loading errors for existing App: #{@app.name}" }
14
14
  @app.app_errors.each do |app_error|
15
15
  @existing_errors[app_error.code] = app_error
16
16
  end
@@ -19,10 +19,12 @@ class AppErrorDataSeeder
19
19
 
20
20
  def teardown
21
21
  unless @existing_errors.empty?
22
- logger.info { " The following are begin removed:" }
23
- @existing_errors.each do |code, app_error|
24
- logger.info " #{code}: #{app_error.message}"
25
- app_error.destroy
22
+ logger.debug { "The following are begin removed:" }
23
+ log_indent do
24
+ @existing_errors.each do |code, app_error|
25
+ logger.debug { "#{code}: #{app_error.message}" }
26
+ app_error.destroy
27
+ end
26
28
  end
27
29
  end
28
30
  end
@@ -40,11 +42,11 @@ class AppErrorDataSeeder
40
42
  @existing_errors.delete(code)
41
43
  app_error.message = message
42
44
  unless app_error.changes.empty?
43
- logger.info { " Changing #{code}: #{app_error.changes}" }
45
+ logger.debug { "Changing #{code}: #{app_error.changes}" }
44
46
  app_error.save!
45
47
  end
46
48
  else
47
- logger.info { " Creating #{code}: #{message}" }
49
+ logger.debug { "Creating #{code}: #{message}" }
48
50
  @app.app_errors.create!(code: code, message: message)
49
51
  end
50
52
  end
@@ -1,14 +1,2 @@
1
1
  class Country < ActiveRecord::Base
2
- def self.data_seeder_line(line)
3
- {
4
- code: line[0,2],
5
- name: line[3...-1],
6
- }
7
- end
8
-
9
- def self.data_seeder_config
10
- {
11
- key_attribute: :code
12
- }
13
- end
14
2
  end
Binary file
@@ -0,0 +1,9 @@
1
+ {
2
+ key_attribute: 'code',
3
+ postprocess: ->(attrs) {
4
+ {
5
+ code: attrs['country_code'],
6
+ name: attrs['country']
7
+ }
8
+ }
9
+ }
@@ -0,0 +1,249 @@
1
+ country_code,country
2
+ AD,"Andorra"
3
+ AE,"United Arab Emirates"
4
+ AF,"Afghanistan"
5
+ AG,"Antigua and Barbuda"
6
+ AI,"Anguilla"
7
+ AL,"Albania"
8
+ AM,"Armenia"
9
+ AO,"Angola"
10
+ AQ,"Antarctica"
11
+ AR,"Argentina"
12
+ AS,"American Samoa"
13
+ AT,"Austria"
14
+ AU,"Australia"
15
+ AW,"Aruba"
16
+ AX,"Åland Islands"
17
+ AZ,"Azerbaijan"
18
+ BA,"Bosnia and Herzegovina"
19
+ BB,"Barbados"
20
+ BD,"Bangladesh"
21
+ BE,"Belgium"
22
+ BF,"Burkina Faso"
23
+ BG,"Bulgaria"
24
+ BH,"Bahrain"
25
+ BI,"Burundi"
26
+ BJ,"Benin"
27
+ BL,"Saint Barthélemy"
28
+ BM,"Bermuda"
29
+ BN,"Brunei Darussalam"
30
+ BO,"Bolivia, Plurinational State of"
31
+ BQ,"Bonaire, Sint Eustatius and Saba"
32
+ BR,"Brazil"
33
+ BS,"Bahamas"
34
+ BT,"Bhutan"
35
+ BV,"Bouvet Island"
36
+ BW,"Botswana"
37
+ BY,"Belarus"
38
+ BZ,"Belize"
39
+ CA,"Canada"
40
+ CC,"Cocos (Keeling) Islands"
41
+ CD,"Congo, the Democratic Republic of the"
42
+ CF,"Central African Republic"
43
+ CG,"Congo"
44
+ CH,"Switzerland"
45
+ CI,"Côte d'Ivoire"
46
+ CK,"Cook Islands"
47
+ CL,"Chile"
48
+ CM,"Cameroon"
49
+ CN,"China"
50
+ CO,"Colombia"
51
+ CR,"Costa Rica"
52
+ CU,"Cuba"
53
+ CV,"Cape Verde"
54
+ CW,"Curaçao"
55
+ CX,"Christmas Island"
56
+ CY,"Cyprus"
57
+ CZ,"Czech Republic"
58
+ DE,"Germany"
59
+ DJ,"Djibouti"
60
+ DK,"Denmark"
61
+ DM,"Dominica"
62
+ DO,"Dominican Republic"
63
+ DZ,"Algeria"
64
+ EC,"Ecuador"
65
+ EE,"Estonia"
66
+ EG,"Egypt"
67
+ EH,"Western Sahara"
68
+ ER,"Eritrea"
69
+ ES,"Spain"
70
+ ET,"Ethiopia"
71
+ FI,"Finland"
72
+ FJ,"Fiji"
73
+ FK,"Falkland Islands (Malvinas)"
74
+ FM,"Micronesia, Federated States of"
75
+ FO,"Faroe Islands"
76
+ FR,"France"
77
+ GA,"Gabon"
78
+ GB,"United Kingdom"
79
+ GD,"Grenada"
80
+ GE,"Georgia"
81
+ GF,"French Guiana"
82
+ GG,"Guernsey"
83
+ GH,"Ghana"
84
+ GI,"Gibraltar"
85
+ GL,"Greenland"
86
+ GM,"Gambia"
87
+ GN,"Guinea"
88
+ GP,"Guadeloupe"
89
+ GQ,"Equatorial Guinea"
90
+ GR,"Greece"
91
+ GS,"South Georgia and the South Sandwich Islands"
92
+ GT,"Guatemala"
93
+ GU,"Guam"
94
+ GW,"Guinea-Bissau"
95
+ GY,"Guyana"
96
+ HK,"Hong Kong"
97
+ HM,"Heard Island and McDonald Islands"
98
+ HN,"Honduras"
99
+ HR,"Croatia"
100
+ HT,"Haiti"
101
+ HU,"Hungary"
102
+ ID,"Indonesia"
103
+ IE,"Ireland"
104
+ IL,"Israel"
105
+ IM,"Isle of Man"
106
+ IN,"India"
107
+ IO,"British Indian Ocean Territory"
108
+ IQ,"Iraq"
109
+ IR,"Iran, Islamic Republic of"
110
+ IS,"Iceland"
111
+ IT,"Italy"
112
+ JE,"Jersey"
113
+ JM,"Jamaica"
114
+ JO,"Jordan"
115
+ JP,"Japan"
116
+ KE,"Kenya"
117
+ KG,"Kyrgyzstan"
118
+ KH,"Cambodia"
119
+ KI,"Kiribati"
120
+ KM,"Comoros"
121
+ KN,"Saint Kitts and Nevis"
122
+ KP,"Korea, Democratic People's Republic of"
123
+ KR,"Korea, Republic of"
124
+ KW,"Kuwait"
125
+ KY,"Cayman Islands"
126
+ KZ,"Kazakhstan"
127
+ LA,"Lao People's Democratic Republic"
128
+ LB,"Lebanon"
129
+ LC,"Saint Lucia"
130
+ LI,"Liechtenstein"
131
+ LK,"Sri Lanka"
132
+ LR,"Liberia"
133
+ LS,"Lesotho"
134
+ LT,"Lithuania"
135
+ LU,"Luxembourg"
136
+ LV,"Latvia"
137
+ LY,"Libya"
138
+ MA,"Morocco"
139
+ MC,"Monaco"
140
+ MD,"Moldova, Republic of"
141
+ ME,"Montenegro"
142
+ MF,"Saint Martin (French part)"
143
+ MG,"Madagascar"
144
+ MH,"Marshall Islands"
145
+ MK,"Macedonia, the former Yugoslav Republic of"
146
+ ML,"Mali"
147
+ MM,"Myanmar"
148
+ MN,"Mongolia"
149
+ MO,"Macao"
150
+ MP,"Northern Mariana Islands"
151
+ MQ,"Martinique"
152
+ MR,"Mauritania"
153
+ MS,"Montserrat"
154
+ MT,"Malta"
155
+ MU,"Mauritius"
156
+ MV,"Maldives"
157
+ MW,"Malawi"
158
+ MX,"Mexico"
159
+ MY,"Malaysia"
160
+ MZ,"Mozambique"
161
+ NA,"Namibia"
162
+ NC,"New Caledonia"
163
+ NE,"Niger"
164
+ NF,"Norfolk Island"
165
+ NG,"Nigeria"
166
+ NI,"Nicaragua"
167
+ NL,"Netherlands"
168
+ NO,"Norway"
169
+ NP,"Nepal"
170
+ NR,"Nauru"
171
+ NU,"Niue"
172
+ NZ,"New Zealand"
173
+ OM,"Oman"
174
+ PA,"Panama"
175
+ PE,"Peru"
176
+ PF,"French Polynesia"
177
+ PG,"Papua New Guinea"
178
+ PH,"Philippines"
179
+ PK,"Pakistan"
180
+ PL,"Poland"
181
+ PM,"Saint Pierre and Miquelon"
182
+ PN,"Pitcairn"
183
+ PR,"Puerto Rico"
184
+ PS,"Palestine, State of"
185
+ PT,"Portugal"
186
+ PW,"Palau"
187
+ PY,"Paraguay"
188
+ QA,"Qatar"
189
+ RE,"Réunion"
190
+ RO,"Romania"
191
+ RS,"Serbia"
192
+ RU,"Russian Federation"
193
+ RW,"Rwanda"
194
+ SA,"Saudi Arabia"
195
+ SB,"Solomon Islands"
196
+ SC,"Seychelles"
197
+ SD,"Sudan"
198
+ SE,"Sweden"
199
+ SG,"Singapore"
200
+ SH,"Saint Helena, Ascension and Tristan da Cunha"
201
+ SI,"Slovenia"
202
+ SJ,"Svalbard and Jan Mayen"
203
+ SK,"Slovakia"
204
+ SL,"Sierra Leone"
205
+ SM,"San Marino"
206
+ SN,"Senegal"
207
+ SO,"Somalia"
208
+ SR,"Suriname"
209
+ SS,"South Sudan"
210
+ ST,"Sao Tome and Principe"
211
+ SV,"El Salvador"
212
+ SX,"Sint Maarten (Dutch part)"
213
+ SY,"Syrian Arab Republic"
214
+ SZ,"Swaziland"
215
+ TC,"Turks and Caicos Islands"
216
+ TD,"Chad"
217
+ TF,"French Southern Territories"
218
+ TG,"Togo"
219
+ TH,"Thailand"
220
+ TJ,"Tajikistan"
221
+ TK,"Tokelau"
222
+ TL,"Timor-Leste"
223
+ TM,"Turkmenistan"
224
+ TN,"Tunisia"
225
+ TO,"Tonga"
226
+ TR,"Turkey"
227
+ TT,"Trinidad and Tobago"
228
+ TV,"Tuvalu"
229
+ TW,"Taiwan, Province of China"
230
+ TZ,"Tanzania, United Republic of"
231
+ UA,"Ukraine"
232
+ UG,"Uganda"
233
+ UM,"United States Minor Outlying Islands"
234
+ US,"United States"
235
+ UY,"Uruguay"
236
+ UZ,"Uzbekistan"
237
+ VA,"Holy See (Vatican City State)"
238
+ VC,"Saint Vincent and the Grenadines"
239
+ VE,"Venezuela, Bolivarian Republic of"
240
+ VG,"Virgin Islands, British"
241
+ VI,"Virgin Islands, U.S."
242
+ VN,"Viet Nam"
243
+ VU,"Vanuatu"
244
+ WF,"Wallis and Futuna"
245
+ WS,"Samoa"
246
+ YE,"Yemen"
247
+ YT,"Mayotte"
248
+ ZA,"South Africa"
249
+ ZM,"Zambia"