data_seeder 0.0.5 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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"