yaml_seeder 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +54 -0
  3. data/Rakefile +23 -0
  4. data/lib/yaml_seeder.rb +179 -0
  5. 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
@@ -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
+