yaml_seeder 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +54 -0
- data/Rakefile +23 -0
- data/lib/yaml_seeder.rb +179 -0
- metadata +59 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Paul Fedory
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
= YamlSeeder
|
2
|
+
Seeds your ActiveRecord models from Foxy Fixture-like YAML files
|
3
|
+
|
4
|
+
== YAML seed files
|
5
|
+
YamlSeeder works upon seed files which are very similar to fixtures - the foxy-fixtures introduced in Rails 2.0. For example, consider a Company model and an Employee model, where an employee belongs to a company:
|
6
|
+
|
7
|
+
=== companies.yml
|
8
|
+
dunder:
|
9
|
+
name: Dunder Mifflin
|
10
|
+
|
11
|
+
=== employees.yml
|
12
|
+
michael:
|
13
|
+
name: Michael Scott
|
14
|
+
company: dunder
|
15
|
+
|
16
|
+
It's a good idea to put these seed files in their own directory, say "db/seeds".
|
17
|
+
|
18
|
+
For more information, google "foxy fixtures" or see http://ryandaigle.com/articles/2007/10/26/what-s-new-in-edge-rails-fixtures-just-got-a-whole-lot-easier
|
19
|
+
|
20
|
+
== Installation
|
21
|
+
|
22
|
+
gem install yaml_seeder
|
23
|
+
|
24
|
+
== Usage
|
25
|
+
|
26
|
+
Use YamlSeeder to seed your Rails database. If you're using Rails 2.3.4 or later, add the following to your "db/seeds.rb" file (don't forget to require 'yaml_seeder'!)
|
27
|
+
|
28
|
+
===db/seeds.rb
|
29
|
+
|
30
|
+
require 'yaml_seeder'
|
31
|
+
Dir.glob(RAILS_ROOT + '/db/seeds/*.yml').each do |file|
|
32
|
+
YamlSeeder.seed('db/seeds', File.basename(file, '.*'))
|
33
|
+
end
|
34
|
+
|
35
|
+
Alternatively, or if you're using an earlier version of Rails, you can create a rake task (eg. called "db:yaml_seed"):
|
36
|
+
|
37
|
+
===lib/tasks/seed.rake
|
38
|
+
|
39
|
+
require 'yaml_seeder'
|
40
|
+
namespace :db do
|
41
|
+
desc "Load seed files (from db/seeds) into the current environment's database."
|
42
|
+
task :yaml_seed => :environment do
|
43
|
+
Dir.glob(RAILS_ROOT + '/db/seeds/*.yml').each do |file|
|
44
|
+
YamlSeeder.seed('db/seeds', File.basename(file, '.*'))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
== Notes
|
50
|
+
* If ID's are not specified in the YAML seed files, then they will be assigned by the normal creation of saving an ActiveRecord (ie. the next ID available).
|
51
|
+
* Currently, YamlSeeder only supports belong-to associations.
|
52
|
+
|
53
|
+
|
54
|
+
Copyright (c) 2010 Paul Fedory, released under the MIT license
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the yaml_seeder plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.libs << 'test'
|
12
|
+
t.pattern = 'test/**/*_test.rb'
|
13
|
+
t.verbose = true
|
14
|
+
end
|
15
|
+
|
16
|
+
desc 'Generate documentation for the yaml_seeder plugin.'
|
17
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
18
|
+
rdoc.rdoc_dir = 'rdoc'
|
19
|
+
rdoc.title = 'YamlSeeder'
|
20
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
21
|
+
rdoc.rdoc_files.include('README')
|
22
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
23
|
+
end
|
data/lib/yaml_seeder.rb
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
# YamlSeeder
|
2
|
+
require 'yaml'
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
class YamlSeeder < Hash
|
6
|
+
DEFAULT_FILTER_RE = /\.ya?ml$/
|
7
|
+
|
8
|
+
@@record_cache = Hash.new
|
9
|
+
@@yaml_cache = Hash.new
|
10
|
+
@@seedfile_directory = ""
|
11
|
+
|
12
|
+
# The main entry point of YamlSeeder
|
13
|
+
# * seedfile_directory: the directory containing the YAML seed files (eg. db/seeds)
|
14
|
+
# * table_names: an array of strings containing the names of the models you wish to seed
|
15
|
+
def self.seed(seedfile_directory, table_names, class_names = {})
|
16
|
+
@@seedfile_directory = seedfile_directory
|
17
|
+
table_names = [table_names].flatten.map { |n| n.to_s }
|
18
|
+
|
19
|
+
# deletes the table name from the fetching list if it's cached already:
|
20
|
+
table_names_to_fetch = table_names.reject { |table_name| model_is_cached?(table_name) }
|
21
|
+
|
22
|
+
unless table_names_to_fetch.empty?
|
23
|
+
yaml_rows_map = {}
|
24
|
+
|
25
|
+
yaml_rows = table_names_to_fetch.map do |table_name|
|
26
|
+
yaml_rows_map[table_name] = YamlSeeder.new(File.split(table_name.to_s).last, class_names[table_name.to_sym], File.join(seedfile_directory, table_name.to_s))
|
27
|
+
end
|
28
|
+
|
29
|
+
@@yaml_cache.update(yaml_rows_map)
|
30
|
+
|
31
|
+
yaml_rows.each do |row|
|
32
|
+
row.insert_records
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def initialize(table_name, class_name, seedfile_path, file_filter = DEFAULT_FILTER_RE)
|
39
|
+
@table_name, @seedfile_path, @file_filter = table_name, seedfile_path, file_filter
|
40
|
+
@name = table_name # preserve seed base name
|
41
|
+
|
42
|
+
@class_name = class_name ||
|
43
|
+
(ActiveRecord::Base.pluralize_table_names ? @table_name.singularize.camelize : @table_name.camelize)
|
44
|
+
@table_name = "#{ActiveRecord::Base.table_name_prefix}#{@table_name}#{ActiveRecord::Base.table_name_suffix}"
|
45
|
+
@table_name = class_name.table_name if class_name.respond_to?(:table_name)
|
46
|
+
|
47
|
+
read_yaml_seed_files
|
48
|
+
end
|
49
|
+
|
50
|
+
def insert_records
|
51
|
+
each do |label, row|
|
52
|
+
|
53
|
+
if model_class && model_class < ActiveRecord::Base
|
54
|
+
|
55
|
+
# If STI is used, find the correct subclass for association reflection
|
56
|
+
reflection_class =
|
57
|
+
if row.include?(inheritance_column_name)
|
58
|
+
row[inheritance_column_name].constantize rescue model_class
|
59
|
+
else
|
60
|
+
model_class
|
61
|
+
end
|
62
|
+
|
63
|
+
reflection_class.reflect_on_all_associations.each do |association|
|
64
|
+
case association.macro
|
65
|
+
when :belongs_to
|
66
|
+
|
67
|
+
# if there's a belong-to association, find the id of the foreign key in the loaded associations.
|
68
|
+
# if it's not in the loaded associations, then load it. get it's id, and set the foreign key to it.
|
69
|
+
|
70
|
+
# Do not replace association name with association foreign key if they are named the same
|
71
|
+
fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
|
72
|
+
|
73
|
+
if association.name.to_s != fk_name && value = row.delete(association.name.to_s)
|
74
|
+
if association.options[:polymorphic]
|
75
|
+
if value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
|
76
|
+
target_type = $1
|
77
|
+
target_type_name = (association.options[:foreign_type] || "#{association.name}_type").to_s
|
78
|
+
|
79
|
+
# support polymorphic belongs_to as "label (Type)"
|
80
|
+
row[target_type_name] = target_type
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
if @@record_cache.has_key?(association.name.to_s.pluralize)
|
85
|
+
# load the appropriate association
|
86
|
+
assoc_records = @@record_cache[association.name.to_s.pluralize]
|
87
|
+
row[fk_name] = assoc_records[value].id
|
88
|
+
else
|
89
|
+
# they aren't loaded yet, so do the recursive thing, loading it.
|
90
|
+
YamlSeeder.seed(@@seedfile_directory, association.name.to_s.pluralize)
|
91
|
+
|
92
|
+
# the record cache will now contain what we need
|
93
|
+
assoc_records = @@record_cache[association.name.to_s.pluralize]
|
94
|
+
row[fk_name] = assoc_records[value].id
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
@myobject = model_class.create (row)
|
102
|
+
records_in_table = @@record_cache.has_key?(@table_name) ? @@record_cache[@table_name] : Hash.new
|
103
|
+
records_in_table[label] = @myobject
|
104
|
+
@@record_cache[@table_name] = records_in_table
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
def self.model_is_cached?(table_name)
|
111
|
+
@@record_cache.has_key?(table_name)
|
112
|
+
end
|
113
|
+
|
114
|
+
def read_yaml_seed_files
|
115
|
+
yaml_string = ""
|
116
|
+
Dir["#{@seedfile_path}/**/*.yml"].select { |f| test(?f, f) }.each do |subseed_path|
|
117
|
+
yaml_string << IO.read(subseed_path)
|
118
|
+
end
|
119
|
+
yaml_string << IO.read(yaml_file_path)
|
120
|
+
|
121
|
+
if yaml = parse_yaml_string(yaml_string)
|
122
|
+
# If the file is an ordered map, extract its children.
|
123
|
+
yaml_value =
|
124
|
+
if yaml.respond_to?(:type_id) && yaml.respond_to?(:value)
|
125
|
+
yaml.value
|
126
|
+
else
|
127
|
+
[yaml]
|
128
|
+
end
|
129
|
+
|
130
|
+
yaml_value.each do |seed|
|
131
|
+
raise YamlSeeder::FormatError, "Bad data for #{@class_name} seed named #{seed}" unless seed.respond_to?(:each)
|
132
|
+
seed.each do |name, data|
|
133
|
+
unless data
|
134
|
+
raise YamlSeeder::FormatError, "Bad data for #{@class_name} seed named #{name} (nil)"
|
135
|
+
end
|
136
|
+
|
137
|
+
self[name] = data
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
class YamlSeederError < StandardError #:nodoc:
|
144
|
+
end
|
145
|
+
|
146
|
+
class FormatError < YamlSeederError #:nodoc:
|
147
|
+
end
|
148
|
+
|
149
|
+
def parse_yaml_string(seed_content)
|
150
|
+
YAML::load(erb_render(seed_content))
|
151
|
+
rescue => error
|
152
|
+
raise YamlSeeder::FormatError, "a YAML error occurred parsing #{yaml_file_path}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}"
|
153
|
+
end
|
154
|
+
|
155
|
+
def yaml_file_path
|
156
|
+
"#{@seedfile_path}.yml"
|
157
|
+
end
|
158
|
+
|
159
|
+
def inheritance_column_name
|
160
|
+
@inheritance_column_name ||= model_class && model_class.inheritance_column
|
161
|
+
end
|
162
|
+
|
163
|
+
def erb_render(seed_content)
|
164
|
+
ERB.new(seed_content).result
|
165
|
+
end
|
166
|
+
|
167
|
+
def model_class
|
168
|
+
unless defined?(@model_class)
|
169
|
+
@model_class =
|
170
|
+
if @class_name.nil? || @class_name.is_a?(Class)
|
171
|
+
@class_name
|
172
|
+
else
|
173
|
+
@class_name.constantize rescue nil
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
@model_class
|
178
|
+
end
|
179
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: yaml_seeder
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paul Fedory
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-01-21 00:00:00 +00:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Seeds your ActiveRecord models from YAML files, when the YAML files are formatted like test fixtures.
|
17
|
+
email:
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- MIT-LICENSE
|
24
|
+
- README.rdoc
|
25
|
+
files:
|
26
|
+
- lib/yaml_seeder.rb
|
27
|
+
- MIT-LICENSE
|
28
|
+
- Rakefile
|
29
|
+
- README.rdoc
|
30
|
+
has_rdoc: true
|
31
|
+
homepage: http://github.com/paulfedory/yaml_seeder
|
32
|
+
licenses: []
|
33
|
+
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
requirements: []
|
52
|
+
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 1.3.5
|
55
|
+
signing_key:
|
56
|
+
specification_version: 3
|
57
|
+
summary: Seeds your ActiveRecord models from YAML files
|
58
|
+
test_files: []
|
59
|
+
|