data_seeder 0.0.1
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 +7 -0
- data/README.md +256 -0
- data/Rakefile +34 -0
- data/app/models/data_seeder/seed_file.rb +34 -0
- data/db/migrate/20150306195118_create_data_seeder_seed_files.rb +9 -0
- data/lib/data_seeder.rb +68 -0
- data/lib/data_seeder/config.rb +41 -0
- data/lib/data_seeder/engine.rb +5 -0
- data/lib/data_seeder/loader.rb +122 -0
- data/lib/data_seeder/loader/csv.rb +15 -0
- data/lib/data_seeder/loader/json.rb +20 -0
- data/lib/data_seeder/loader/txt.rb +23 -0
- data/lib/data_seeder/loader/yaml.rb +23 -0
- data/lib/data_seeder/logger.rb +15 -0
- data/lib/data_seeder/version.rb +3 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/models/app.rb +3 -0
- data/test/dummy/app/models/app_error.rb +3 -0
- data/test/dummy/app/models/app_error_data_seeder.rb +52 -0
- data/test/dummy/app/models/country.rb +14 -0
- data/test/dummy/app/models/state.rb +2 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +26 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +12 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/db/migrate/20150313022149_create_countries.rb +8 -0
- data/test/dummy/db/migrate/20150313022228_create_states.rb +8 -0
- data/test/dummy/db/migrate/20150313172634_create_apps.rb +7 -0
- data/test/dummy/db/migrate/20150313172719_create_app_errors.rb +10 -0
- data/test/dummy/db/schema.rb +45 -0
- data/test/dummy/db/seed.test/bar.err +3 -0
- data/test/dummy/db/seed.test/countries.txt +249 -0
- data/test/dummy/db/seed.test/foo.err +3 -0
- data/test/dummy/db/seed.test/states.csv +51 -0
- data/test/dummy/db/seed.test/states.json +153 -0
- data/test/dummy/db/seed.test/states.txt +51 -0
- data/test/dummy/db/seed.test/states.yml +101 -0
- data/test/dummy/db/seed.test/zulu.err +2 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +39 -0
- data/test/dummy/log/test.log +68768 -0
- data/test/models/data_seeder_test.rb +147 -0
- data/test/test_helper.rb +12 -0
- metadata +159 -0
@@ -0,0 +1,122 @@
|
|
1
|
+
module DataSeeder
|
2
|
+
module Loader
|
3
|
+
attr_accessor :file_config, :key_attribute
|
4
|
+
attr_reader :path, :path_minus_ext
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
@only = options[:only]
|
8
|
+
@except = options[:except]
|
9
|
+
if options.has_key?(:purge)
|
10
|
+
@purge = options[:purge]
|
11
|
+
else
|
12
|
+
@purge = true
|
13
|
+
end
|
14
|
+
@old_keys = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def config
|
18
|
+
DataSeeder.config
|
19
|
+
end
|
20
|
+
|
21
|
+
def logger
|
22
|
+
DataSeeder.logger
|
23
|
+
end
|
24
|
+
|
25
|
+
def klass
|
26
|
+
# This should always translate to a class except for custom loaders
|
27
|
+
@path_minus_ext.classify.constantize rescue nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def process(path)
|
31
|
+
@path = path
|
32
|
+
dot_index = @path.rindex('.')
|
33
|
+
@path_minus_ext = @path[0, dot_index]
|
34
|
+
@file_config = {}
|
35
|
+
File.open(@path, 'r') do |fin|
|
36
|
+
load_file_config(fin)
|
37
|
+
setup
|
38
|
+
load(fin)
|
39
|
+
teardown
|
40
|
+
end
|
41
|
+
call_file_method(:teardown)
|
42
|
+
end
|
43
|
+
|
44
|
+
def setup
|
45
|
+
@key_attribute = self.file_config[:key_attribute] || :id
|
46
|
+
@old_keys = self.klass.all.pluck(@key_attribute).map(&:to_s) if @purge
|
47
|
+
logger.info { "Loading #{@path}" }
|
48
|
+
call_file_method(:setup)
|
49
|
+
end
|
50
|
+
|
51
|
+
def teardown
|
52
|
+
@old_keys.each do |key|
|
53
|
+
if model = self.klass.find_by(@key_attribute => key)
|
54
|
+
logger.info { " Destroying #{model_info(model)}"}
|
55
|
+
model.destroy
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# The information displayed when creating, updating, or destroying a model.
|
61
|
+
# The changes argument will be the model.changes on an update.
|
62
|
+
def model_info(model, changes=nil)
|
63
|
+
if changes
|
64
|
+
attr = @file_config[:update_display_method] || @key_attribute
|
65
|
+
"#{model.send(attr)}: #{changes.inspect}"
|
66
|
+
else
|
67
|
+
model.inspect
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def load_file_config(fin)
|
72
|
+
config_line = fin.readline
|
73
|
+
if match = config_line.match(/^\s*#\s*config:(.*)/)
|
74
|
+
@file_config = eval(match[1])
|
75
|
+
else
|
76
|
+
fin.seek(0)
|
77
|
+
if self.klass && self.klass.respond_to?(:data_seeder_config)
|
78
|
+
@file_config = self.klass.data_seeder_config
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def load(fin)
|
84
|
+
throw 'Must override load'
|
85
|
+
end
|
86
|
+
|
87
|
+
def save(attr)
|
88
|
+
key = attr[@key_attribute.to_s] || attr[@key_attribute.to_sym]
|
89
|
+
raise "No #{@key_attribute} in #{attr.inspect}" unless key
|
90
|
+
@old_keys.delete(key.to_s)
|
91
|
+
model = self.klass.find_or_initialize_by(@key_attribute => key)
|
92
|
+
model.attributes = attr
|
93
|
+
save_model(model)
|
94
|
+
end
|
95
|
+
|
96
|
+
def save_model(model)
|
97
|
+
if model.new_record?
|
98
|
+
logger.info { " Saving #{model_info(model)}" }
|
99
|
+
else
|
100
|
+
changes = model.changes
|
101
|
+
return if changes.empty?
|
102
|
+
logger.info { " Updating #{model_info(model, changes)}" }
|
103
|
+
end
|
104
|
+
model.save!
|
105
|
+
end
|
106
|
+
|
107
|
+
def call_file_method(name, *args)
|
108
|
+
if method = @file_config[name]
|
109
|
+
return method.call(*args)
|
110
|
+
else
|
111
|
+
class_method = "data_seeder_#{name}"
|
112
|
+
return self.klass.send(class_method, *args) if @klass.respond_to?(class_method)
|
113
|
+
end
|
114
|
+
return nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
require 'data_seeder/loader/csv'
|
120
|
+
require 'data_seeder/loader/json'
|
121
|
+
require 'data_seeder/loader/yaml'
|
122
|
+
require 'data_seeder/loader/txt'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module DataSeeder
|
4
|
+
module Loader
|
5
|
+
class JSON
|
6
|
+
include Loader
|
7
|
+
def load(io)
|
8
|
+
json = ::JSON.parse(io.read)
|
9
|
+
if json.kind_of?(Hash)
|
10
|
+
json.each do |key, attr|
|
11
|
+
attr[self.key_attribute] = key if self.key_attribute
|
12
|
+
save(attr)
|
13
|
+
end
|
14
|
+
else
|
15
|
+
Array(json).each { |attr| save(attr) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module DataSeeder
|
2
|
+
module Loader
|
3
|
+
class Txt
|
4
|
+
include Loader
|
5
|
+
|
6
|
+
def load(io)
|
7
|
+
if method = self.file_config[:line]
|
8
|
+
io.each_line do |line|
|
9
|
+
next if line.blank? || line.match(/^\s*#/)
|
10
|
+
save(method.call(line))
|
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
|
+
else
|
18
|
+
raise "No line method defined for #{self.klass.name}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module DataSeeder
|
4
|
+
module Loader
|
5
|
+
class YAML
|
6
|
+
include Loader
|
7
|
+
|
8
|
+
def load(io)
|
9
|
+
yaml = ::YAML.load(io.read)
|
10
|
+
if yaml.kind_of?(Hash)
|
11
|
+
yaml.each do |key, attr|
|
12
|
+
attr[self.key_attribute] = key if self.key_attribute
|
13
|
+
save(attr)
|
14
|
+
end
|
15
|
+
elsif yaml.kind_of?(Array)
|
16
|
+
yaml.each { |attr| save(attr) }
|
17
|
+
else
|
18
|
+
raise "Don't know how to interpret #{self.path}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module DataSeeder
|
2
|
+
class Logger < ::Logger
|
3
|
+
attr_accessor :verbose
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
super($stdout)
|
7
|
+
@verbose = true
|
8
|
+
self.formatter = ->(severity, datetime, progname, msg) { "#{msg}\n" }
|
9
|
+
end
|
10
|
+
|
11
|
+
def info(arg='', &block)
|
12
|
+
super if @verbose
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/test/dummy/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'data_seeder'
|
2
|
+
|
3
|
+
class AppErrorDataSeeder
|
4
|
+
include ::DataSeeder::Loader
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@app = App.find_or_initialize_by(name: self.path_minus_ext)
|
8
|
+
@existing_errors = {}
|
9
|
+
if @app.new_record?
|
10
|
+
logger.info "Loading errors for new App: #{@app.name}"
|
11
|
+
@app.save!
|
12
|
+
else
|
13
|
+
logger.info "Loading errors for existing App: #{@app.name}"
|
14
|
+
@app.app_errors.each do |app_error|
|
15
|
+
@existing_errors[app_error.code] = app_error
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def teardown
|
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
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def load(io)
|
31
|
+
io.each_line do |line|
|
32
|
+
line.strip!
|
33
|
+
next if line.blank? || line[0] == ?#
|
34
|
+
space_i = line.index(' ')
|
35
|
+
raise "Invalid line: #{line}" unless space_i
|
36
|
+
code = line[0,space_i].strip
|
37
|
+
message = line[space_i+1..-1].strip
|
38
|
+
app_error = @existing_errors[code]
|
39
|
+
if app_error
|
40
|
+
@existing_errors.delete(code)
|
41
|
+
app_error.message = message
|
42
|
+
unless app_error.changes.empty?
|
43
|
+
logger.info { " Changing #{code}: #{app_error.changes}" }
|
44
|
+
app_error.save!
|
45
|
+
end
|
46
|
+
else
|
47
|
+
logger.info { " Creating #{code}: #{message}" }
|
48
|
+
@app.app_errors.create!(code: code, message: message)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/test/dummy/bin/rake
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path('../boot', __FILE__)
|
2
|
+
|
3
|
+
require 'rails/all'
|
4
|
+
|
5
|
+
Bundler.require(*Rails.groups)
|
6
|
+
require "data_seeder"
|
7
|
+
|
8
|
+
module Dummy
|
9
|
+
class Application < Rails::Application
|
10
|
+
# Settings in config/environments/* take precedence over those specified here.
|
11
|
+
# Application configuration should go into files in config/initializers
|
12
|
+
# -- all .rb files in that directory are automatically loaded.
|
13
|
+
|
14
|
+
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
15
|
+
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
16
|
+
# config.time_zone = 'Central Time (US & Canada)'
|
17
|
+
|
18
|
+
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
19
|
+
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
20
|
+
# config.i18n.default_locale = :de
|
21
|
+
|
22
|
+
config.generators do |g|
|
23
|
+
g.test_framework :mini_test, :spec => true, :fixture => false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
Rails.application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb.
|
3
|
+
|
4
|
+
# In the development environment your application's code is reloaded on
|
5
|
+
# every request. This slows down response time but is perfect for development
|
6
|
+
# since you don't have to restart the web server when you make code changes.
|
7
|
+
config.cache_classes = false
|
8
|
+
|
9
|
+
# Do not eager load code on boot.
|
10
|
+
config.eager_load = false
|
11
|
+
|
12
|
+
# Show full error reports and disable caching.
|
13
|
+
config.consider_all_requests_local = true
|
14
|
+
config.action_controller.perform_caching = false
|
15
|
+
|
16
|
+
# Don't care if the mailer can't send.
|
17
|
+
config.action_mailer.raise_delivery_errors = false
|
18
|
+
|
19
|
+
# Print deprecation notices to the Rails logger.
|
20
|
+
config.active_support.deprecation = :log
|
21
|
+
|
22
|
+
# Raise an error on page load if there are pending migrations.
|
23
|
+
config.active_record.migration_error = :page_load
|
24
|
+
|
25
|
+
# Debug mode disables concatenation and preprocessing of assets.
|
26
|
+
# This option may cause significant delays in view rendering with a large
|
27
|
+
# number of complex assets.
|
28
|
+
config.assets.debug = true
|
29
|
+
|
30
|
+
# Adds additional error checking when serving assets at runtime.
|
31
|
+
# Checks for improperly declared sprockets dependencies.
|
32
|
+
# Raises helpful error messages.
|
33
|
+
config.assets.raise_runtime_errors = true
|
34
|
+
|
35
|
+
# Raises error for missing translations
|
36
|
+
# config.action_view.raise_on_missing_translations = true
|
37
|
+
end
|