merb_seed 0.1.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.
- data/LICENSE +20 -0
- data/README +102 -0
- data/Rakefile +54 -0
- data/lib/merb_seed.rb +19 -0
- data/lib/merb_seed/merbtasks.rb +24 -0
- data/lib/merb_seed/orm/ar_ext.rb +1 -0
- data/lib/merb_seed/orm/dm_ext.rb +27 -0
- data/lib/merb_seed/orm/sequel_ext.rb +1 -0
- data/lib/merb_seed/seeder.rb +87 -0
- data/spec/fixtures/dm_models.rb +17 -0
- data/spec/merb_seed_spec.rb +63 -0
- data/spec/spec_helper.rb +6 -0
- metadata +77 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Michael Bleigh, released under the MIT license
|
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
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
merb_seed
|
2
|
+
=======
|
3
|
+
|
4
|
+
merb_seed is an attempt to once and for all solve the problem of inserting and
|
5
|
+
maintaining seed data in a database. It uses a variety of techniques gathered
|
6
|
+
from various places around the web and combines them to create what is
|
7
|
+
hopefully the most robust seed data system around.
|
8
|
+
|
9
|
+
|
10
|
+
Support
|
11
|
+
=======
|
12
|
+
|
13
|
+
merb_seed 0.1 currently only supports datamapper. ActiveRecord and Sequel support
|
14
|
+
|
15
|
+
|
16
|
+
Usage
|
17
|
+
=======
|
18
|
+
|
19
|
+
rake db:seed
|
20
|
+
|
21
|
+
|
22
|
+
Setting up Seed Data
|
23
|
+
=======
|
24
|
+
Seed data is taken from the schema/data directory. Simply make descriptive .rb
|
25
|
+
files in that directory (they can be named anything, but users.rb for the User
|
26
|
+
model seed data makes sense, etc.). These scripts will be run whenever the
|
27
|
+
db:seed rake task is called. You can put arbitrary Ruby code in these files,
|
28
|
+
but remember that it will be executed every time the rake task is called, so
|
29
|
+
it needs to be runnable multiple times on the same database.
|
30
|
+
|
31
|
+
You can also have environment-specific seed data placed in
|
32
|
+
schema/data/ENVIRONMENT that will only be loaded if that is the current
|
33
|
+
environment.
|
34
|
+
|
35
|
+
Let's say we want to populate a few default users. In schema/data/users.rb we
|
36
|
+
write the following code:
|
37
|
+
|
38
|
+
User.seed(:login, :email) do |s|
|
39
|
+
s.login = "bob"
|
40
|
+
s.email = "bob@bobson.com"
|
41
|
+
s.first_name = "Bob"
|
42
|
+
s.last_name = "Bobson"
|
43
|
+
end
|
44
|
+
|
45
|
+
User.seed(:login, :email) do |s|
|
46
|
+
s.login = "bob"
|
47
|
+
s.email = "bob@stevenson.com"
|
48
|
+
s.first_name = "Bob"
|
49
|
+
s.last_name = "Stevenson"
|
50
|
+
end
|
51
|
+
|
52
|
+
That's all you have to do! You will now have two users created in the system
|
53
|
+
and you can change their first and last names in the users.rb file and it will
|
54
|
+
be updated as such.
|
55
|
+
|
56
|
+
The arguments passed to the <ActiveRecord>.seed method are the constraining
|
57
|
+
attributes: these must remain unchanged between db:seed calls to avoid data
|
58
|
+
duplication. By default, seed data will constrain to the id like so:
|
59
|
+
|
60
|
+
Category.seed do |s|
|
61
|
+
s.id = 1
|
62
|
+
s.name = "Buttons"
|
63
|
+
end
|
64
|
+
|
65
|
+
Category.seed do |s|
|
66
|
+
s.id = 2
|
67
|
+
s.name = "Bobbins"
|
68
|
+
s.parent_id = 1
|
69
|
+
end
|
70
|
+
|
71
|
+
Note that any constraints that are passed in must be present in the subsequent
|
72
|
+
seed data setting.
|
73
|
+
|
74
|
+
|
75
|
+
Callbacks
|
76
|
+
=======
|
77
|
+
|
78
|
+
Seed data can also define callbacks that will run after the record is created
|
79
|
+
|
80
|
+
Category.seed do |s|
|
81
|
+
s.id = 2
|
82
|
+
s.name = "Bobbins"
|
83
|
+
s.parent_id = 1
|
84
|
+
|
85
|
+
# run code after creation (record is the newly created model)
|
86
|
+
s.after_seed do |record|
|
87
|
+
record.enable!
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
Source Code
|
92
|
+
=======
|
93
|
+
|
94
|
+
Need a change? Help out by forking and doing a pull request. I'll merge in any new features or bug fixes that you make.
|
95
|
+
http://github.com/merbjedi/merb_seed
|
96
|
+
|
97
|
+
|
98
|
+
Seed Fu
|
99
|
+
=======
|
100
|
+
merb_seed is a port of seed-fu to Merb
|
101
|
+
|
102
|
+
http://github.com/mbleigh/seed-fu
|
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
|
4
|
+
require 'merb-core'
|
5
|
+
require 'merb-core/tasks/merb'
|
6
|
+
|
7
|
+
GEM_NAME = "merb_seed"
|
8
|
+
GEM_VERSION = "0.1.0"
|
9
|
+
AUTHOR = "Jacques Crocker"
|
10
|
+
EMAIL = "merbjedi@gmil.com"
|
11
|
+
HOMEPAGE = "http://merbjedi.com/"
|
12
|
+
SUMMARY = "Merb plugin that provides RAKE tasks to easily initialize seed data in your database"
|
13
|
+
|
14
|
+
spec = Gem::Specification.new do |s|
|
15
|
+
s.rubyforge_project = 'merb'
|
16
|
+
s.name = GEM_NAME
|
17
|
+
s.version = GEM_VERSION
|
18
|
+
s.platform = Gem::Platform::RUBY
|
19
|
+
s.has_rdoc = true
|
20
|
+
s.extra_rdoc_files = ["README", "LICENSE"]
|
21
|
+
s.summary = SUMMARY
|
22
|
+
s.description = s.summary
|
23
|
+
s.author = AUTHOR
|
24
|
+
s.email = EMAIL
|
25
|
+
s.homepage = HOMEPAGE
|
26
|
+
|
27
|
+
# todo: allow merb_seed to support activerecord and sequel
|
28
|
+
s.add_dependency('merb_datamapper', '>= 1.0.8')
|
29
|
+
|
30
|
+
s.require_path = 'lib'
|
31
|
+
s.files = %w(LICENSE README Rakefile) + Dir.glob("{lib,spec}/**/*")
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
36
|
+
pkg.gem_spec = spec
|
37
|
+
end
|
38
|
+
|
39
|
+
desc "install the plugin as a gem"
|
40
|
+
task :install do
|
41
|
+
Merb::RakeHelper.install(GEM_NAME, :version => GEM_VERSION)
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "Uninstall the gem"
|
45
|
+
task :uninstall do
|
46
|
+
Merb::RakeHelper.uninstall(GEM_NAME, :version => GEM_VERSION)
|
47
|
+
end
|
48
|
+
|
49
|
+
desc "Create a gemspec file"
|
50
|
+
task :gemspec do
|
51
|
+
File.open("#{GEM_NAME}.gemspec", "w") do |file|
|
52
|
+
file.puts spec.to_ruby
|
53
|
+
end
|
54
|
+
end
|
data/lib/merb_seed.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# make sure we're running inside Merb
|
2
|
+
if defined?(Merb::Plugins)
|
3
|
+
|
4
|
+
# Merb gives you a Merb::Plugins.config hash...feel free to put your stuff in your piece of it
|
5
|
+
Merb::Plugins.config[:merb_seed] = {
|
6
|
+
:seed_path => "schema/data"
|
7
|
+
}
|
8
|
+
|
9
|
+
Merb::BootLoader.before_app_loads do
|
10
|
+
# require code that must be loaded before the application
|
11
|
+
end
|
12
|
+
|
13
|
+
Merb::BootLoader.after_app_loads do
|
14
|
+
# code that can be required after the application loads
|
15
|
+
end
|
16
|
+
|
17
|
+
Merb::Plugins.add_rakefiles "merb_seed/merbtasks"
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
namespace :db do
|
2
|
+
desc "Loads seed data from schema/data for the current environment."
|
3
|
+
task :seed => :merb_env do
|
4
|
+
require File.join( File.dirname(__FILE__), "seeder")
|
5
|
+
|
6
|
+
# load ruby seed files
|
7
|
+
seed_path = ENV["SEED_PATH"] ? ENV["SEED_PATH"] : (Merb::Plugins.config[:merb_seed][:seed_path] || "schema/data")
|
8
|
+
Dir[File.join(Merb.root, seed_path, '*.rb')].sort.each { |seed|
|
9
|
+
puts "\n== Seeding from #{File.split(seed).last} " + ("=" * (60 - (17 + File.split(seed).last.length)))
|
10
|
+
load seed
|
11
|
+
puts "=" * 60 + "\n"
|
12
|
+
}
|
13
|
+
|
14
|
+
# load environment specific seed files
|
15
|
+
Dir[File.join(Merb.root, seed_path, Merb.env, '*.rb')].sort.each { |seed|
|
16
|
+
puts "\n== [#{Merb.env}] Seeding from #{File.split(seed).last} " + ("=" * (60 - (20 + File.split(seed).last.length + Merb.env.length)))
|
17
|
+
load seed
|
18
|
+
puts "=" * 60 + "\n"
|
19
|
+
}
|
20
|
+
|
21
|
+
# load seed files from yml
|
22
|
+
# TODO
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# TODO
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'datamapper'
|
2
|
+
|
3
|
+
module DataMapper::Model
|
4
|
+
# Creates a single record of seed data for use
|
5
|
+
# with the db:seed rake task.
|
6
|
+
#
|
7
|
+
# === Parameters
|
8
|
+
# constraints :: Immutable reference attributes. Defaults to :id
|
9
|
+
def seed(*constraints, &block)
|
10
|
+
MerbSeed::Seeder.plant(self, *constraints, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def seed_many(*constraints)
|
14
|
+
seeds = constraints.pop
|
15
|
+
seeds.each do |seed_data|
|
16
|
+
seed(*constraints) do |s|
|
17
|
+
seed_data.each_pair do |k,v|
|
18
|
+
s.send "#{k}=", v
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def column_names
|
25
|
+
properties.map{|i| i.field }
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
# TODO
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), "orm", "dm_ext")
|
2
|
+
|
3
|
+
module MerbSeed
|
4
|
+
class Seeder
|
5
|
+
def self.plant(model_class, *constraints, &block)
|
6
|
+
constraints = [:id] if constraints.empty?
|
7
|
+
seed = Seeder.new(model_class)
|
8
|
+
|
9
|
+
options = constraints.last if (constraints.last.is_a? Hash)
|
10
|
+
constraints.delete_at(*constraints.length-1) if (constraints.last.is_a? Hash)
|
11
|
+
|
12
|
+
insert_only = constraints.last.is_a? TrueClass
|
13
|
+
constraints.delete_at(*constraints.length-1) if (constraints.last.is_a? TrueClass or constraints.last.is_a? FalseClass)
|
14
|
+
seed.set_constraints(*constraints)
|
15
|
+
yield seed
|
16
|
+
seed.plant!({:insert_only => insert_only}.merge(options||{}))
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(model_class)
|
20
|
+
@model_class = model_class
|
21
|
+
@constraints = [:id]
|
22
|
+
@data = {}
|
23
|
+
end
|
24
|
+
|
25
|
+
def set_constraints(*constraints)
|
26
|
+
raise "You must set at least one constraint." if constraints.empty?
|
27
|
+
@constraints = []
|
28
|
+
constraints.each do |constraint|
|
29
|
+
raise "Your constraint `#{constraint}` is not a column in #{@model_class}. Valid columns are `#{@model_class.column_names.join("`, `")}`." unless @model_class.column_names.include?(constraint.to_s)
|
30
|
+
@constraints << constraint.to_sym
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def set_attribute(name, value)
|
35
|
+
@data[name.to_sym] = value
|
36
|
+
end
|
37
|
+
|
38
|
+
def after_seed(&block)
|
39
|
+
if block
|
40
|
+
@after_seed_block = block
|
41
|
+
else
|
42
|
+
@after_seed_block
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def plant!(options)
|
47
|
+
insert_only = options[:insert_only].nil? ? false : options[:insert_only]
|
48
|
+
|
49
|
+
record = get
|
50
|
+
return if !record.new_record? and insert_only
|
51
|
+
@data.each do |k, v|
|
52
|
+
record.send("#{k}=", v)
|
53
|
+
end
|
54
|
+
record.save || raise("Validation Failed. Use :validate => false in order to skip this:\n#{record.errors.inspect}")
|
55
|
+
puts " - #{@model_class} #{condition_hash.inspect}"
|
56
|
+
|
57
|
+
# fire off after_seed event
|
58
|
+
self.after_seed.call(record) if self.after_seed
|
59
|
+
|
60
|
+
record
|
61
|
+
end
|
62
|
+
|
63
|
+
def method_missing(method_name, *args) #:nodoc:
|
64
|
+
if (match = method_name.to_s.match(/(.*)=$/)) && args.size == 1
|
65
|
+
set_attribute(match[1], args.first)
|
66
|
+
else
|
67
|
+
super
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
|
73
|
+
def get
|
74
|
+
records = @model_class.all(:conditions => condition_hash)
|
75
|
+
raise "Given constraints yielded multiple records." unless records.size < 2
|
76
|
+
if records.any?
|
77
|
+
return records.first
|
78
|
+
else
|
79
|
+
return @model_class.new
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def condition_hash
|
84
|
+
@data.reject{|a,v| !@constraints.include?(a)}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'datamapper'
|
2
|
+
|
3
|
+
# setup repository
|
4
|
+
DataMapper.setup(:default, "sqlite3::memory:")
|
5
|
+
|
6
|
+
# setup models
|
7
|
+
class User
|
8
|
+
include DataMapper::Resource
|
9
|
+
|
10
|
+
property :id, Serial
|
11
|
+
property :login, String
|
12
|
+
property :first_name, String
|
13
|
+
property :last_name, String
|
14
|
+
property :title, String
|
15
|
+
end
|
16
|
+
|
17
|
+
User.auto_migrate!
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.join( File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe "merb_seed" do
|
4
|
+
|
5
|
+
describe "datamapper support" do
|
6
|
+
before(:each) do
|
7
|
+
load File.join( File.dirname(__FILE__), "fixtures", "dm_models.rb")
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should create a model if one doesn't exist" do
|
11
|
+
User.seed(:id) do |s|
|
12
|
+
s.id = 1
|
13
|
+
s.login = "bob"
|
14
|
+
s.first_name = "Bob"
|
15
|
+
s.last_name = "Bobson"
|
16
|
+
s.title = "Peon"
|
17
|
+
end
|
18
|
+
|
19
|
+
bob = User.get(1)
|
20
|
+
bob.first_name.should == "Bob"
|
21
|
+
bob.last_name.should == "Bobson"
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should be able to handle multiple constraints" do
|
25
|
+
User.seed(:title, :login) do |s|
|
26
|
+
s.login = "bob"
|
27
|
+
s.title = "Peon"
|
28
|
+
s.first_name = "Bob"
|
29
|
+
end
|
30
|
+
|
31
|
+
User.count.should == 1
|
32
|
+
|
33
|
+
User.seed(:title, :login) do |s|
|
34
|
+
s.login = "frank"
|
35
|
+
s.title = "Peon"
|
36
|
+
s.first_name = "Frank"
|
37
|
+
end
|
38
|
+
|
39
|
+
User.count.should == 2
|
40
|
+
|
41
|
+
User.first(:first_name => "Bob").first_name.should == "Bob"
|
42
|
+
User.seed(:title, :login) do |s|
|
43
|
+
s.login = "bob"
|
44
|
+
s.title = "Peon"
|
45
|
+
s.first_name = "Steve"
|
46
|
+
end
|
47
|
+
User.first(:first_name => "Steve").first_name.should == "Steve"
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should be able to create models from an array of seed attributes" do
|
51
|
+
User.seed_many(:title, :login, [
|
52
|
+
{:login => "bob", :title => "Peon", :first_name => "Steve"},
|
53
|
+
{:login => "frank", :title => "Peasant", :first_name => "Francis"},
|
54
|
+
{:login => "harry", :title => "Noble", :first_name => "Harry"}
|
55
|
+
])
|
56
|
+
|
57
|
+
User.first(:login => "bob").first_name.should == "Steve"
|
58
|
+
User.first(:login => "frank").first_name.should == "Francis"
|
59
|
+
User.first(:login => "harry").first_name.should == "Harry"
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: merb_seed
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jacques Crocker
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-02-15 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: merb_datamapper
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.0.8
|
24
|
+
version:
|
25
|
+
description: Merb plugin that provides RAKE tasks to easily initialize seed data in your database
|
26
|
+
email: merbjedi@gmil.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README
|
33
|
+
- LICENSE
|
34
|
+
files:
|
35
|
+
- LICENSE
|
36
|
+
- README
|
37
|
+
- Rakefile
|
38
|
+
- lib/merb_seed
|
39
|
+
- lib/merb_seed/merbtasks.rb
|
40
|
+
- lib/merb_seed/orm
|
41
|
+
- lib/merb_seed/orm/ar_ext.rb
|
42
|
+
- lib/merb_seed/orm/dm_ext.rb
|
43
|
+
- lib/merb_seed/orm/sequel_ext.rb
|
44
|
+
- lib/merb_seed/seeder.rb
|
45
|
+
- lib/merb_seed.rb
|
46
|
+
- spec/fixtures
|
47
|
+
- spec/fixtures/dm_models.rb
|
48
|
+
- spec/merb_seed_spec.rb
|
49
|
+
- spec/spec_helper.rb
|
50
|
+
has_rdoc: true
|
51
|
+
homepage: http://merbjedi.com/
|
52
|
+
post_install_message:
|
53
|
+
rdoc_options: []
|
54
|
+
|
55
|
+
require_paths:
|
56
|
+
- lib
|
57
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "0"
|
68
|
+
version:
|
69
|
+
requirements: []
|
70
|
+
|
71
|
+
rubyforge_project: merb
|
72
|
+
rubygems_version: 1.3.1
|
73
|
+
signing_key:
|
74
|
+
specification_version: 2
|
75
|
+
summary: Merb plugin that provides RAKE tasks to easily initialize seed data in your database
|
76
|
+
test_files: []
|
77
|
+
|