gardener 1.0.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/README.rdoc +44 -0
- data/lib/gardener.rb +157 -0
- metadata +65 -0
data/README.rdoc
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
=Gardener
|
2
|
+
==A Simple Rails Plugin to help you create seed data
|
3
|
+
Easy transfer of individual records in a Rails app between environments via yaml dumps.
|
4
|
+
|
5
|
+
But you don't need to know that.
|
6
|
+
|
7
|
+
All you care about is
|
8
|
+
|
9
|
+
==Usage
|
10
|
+
Put
|
11
|
+
gem 'gardener'
|
12
|
+
in your gemfile and gardener gets right to work.
|
13
|
+
|
14
|
+
He's there behind the scenes and you can call on him in several ways.
|
15
|
+
|
16
|
+
==Class Methods
|
17
|
+
|
18
|
+
===sow
|
19
|
+
User.sow
|
20
|
+
for example, would render all the users down into a yaml file, which you could then commit into your source control,
|
21
|
+
and deploy to staging or production.
|
22
|
+
|
23
|
+
Once deployed you could write a rake task :P
|
24
|
+
or just go into the rails console :D
|
25
|
+
and call
|
26
|
+
User.reap
|
27
|
+
to pull the records up out of the file and into your database.
|
28
|
+
===reap
|
29
|
+
"[...] whatsoever a man soweth, that shall he also reap" - Galatians 6:7-8
|
30
|
+
For reaping the fruits of your labor.
|
31
|
+
|
32
|
+
==Instance Methods
|
33
|
+
|
34
|
+
===plant_seed
|
35
|
+
User.find(1)
|
36
|
+
User.plant_seed
|
37
|
+
Would put only the one user in a file to be reconstituted later. This is the use case that I wrote this for,
|
38
|
+
I found myself making lots of copy changes to databased content for websites, and needed a simple way to move those things
|
39
|
+
from one environment (development --> staging or staging --> production) to another. I didn't want to copy over entire tables
|
40
|
+
because there were some records that didn't need to come over, so existing tools like Taps http://adam.heroku.com/past/2009/2/11/taps_for_easy_database_transfers/
|
41
|
+
weren't a perfect fit for me.
|
42
|
+
|
43
|
+
|
44
|
+
|
data/lib/gardener.rb
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
module Gardener
|
2
|
+
def self.included(base)
|
3
|
+
base.extend(ClassMethods)
|
4
|
+
end
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
|
8
|
+
attr_accessor :infinite_choice
|
9
|
+
|
10
|
+
|
11
|
+
# Dump every instance of a class (every record in the database for a model) into a file
|
12
|
+
# to be reconstituted later.
|
13
|
+
def sow
|
14
|
+
c = self.to_s.underscore.pluralize
|
15
|
+
dir = File.join [Rails.root, 'db', 'garden']
|
16
|
+
Dir.mkdir(dir) unless File.exists?(dir)
|
17
|
+
|
18
|
+
File.open(File.join([Rails.root, 'db', 'garden', "#{c}.yml"] ), 'w') do |file|
|
19
|
+
self.find_each{ |x| file << x.to_yaml }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
# Take the things that were dumped to a file and put them in the database.
|
25
|
+
def reap
|
26
|
+
c = self.to_s.underscore.pluralize
|
27
|
+
str = ''
|
28
|
+
File.open(File.join([Rails.root, 'db', 'garden', "#{c}.yml"] ), 'r').each_line do |line|
|
29
|
+
if line.match /^---.*/
|
30
|
+
sprout(str)
|
31
|
+
str = ''
|
32
|
+
end
|
33
|
+
str << line
|
34
|
+
end
|
35
|
+
sprout(str) unless str.blank?
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
# Helper function to reconstitute a record from it's yaml representation.
|
40
|
+
def sprout(str)
|
41
|
+
return false if str.blank?
|
42
|
+
# puts str.inspect
|
43
|
+
|
44
|
+
foo = YAML.load(str)
|
45
|
+
return unless foo # YAML.load('') == false
|
46
|
+
bob = self.new(foo.attributes)
|
47
|
+
bob.id = foo.id
|
48
|
+
|
49
|
+
# Grr, have to check to see if anything in the inheritance hierarchy has the id.
|
50
|
+
base_class = self.base_class
|
51
|
+
scott = base_class.find_by_id(bob.id)
|
52
|
+
|
53
|
+
if scott
|
54
|
+
puts "\n\n#{bob.class.name} already exists, differences are"
|
55
|
+
bar = scott.diff(bob)
|
56
|
+
if bar.blank?
|
57
|
+
puts "\tActually, there are no differences, even the ids are the same #{bob.id} == #{scott.id}.\n\tLooks like you're trying to bring in the exact same object that already exists in the db."
|
58
|
+
else
|
59
|
+
pp bar
|
60
|
+
end
|
61
|
+
|
62
|
+
if @infinite_choice
|
63
|
+
res = @infinite_choice
|
64
|
+
else
|
65
|
+
print "\n\nAdd a 'z' to your selection to apply it to everything\nOverwrite (y), do nothing (n), give a new ID (i), or abort (a) ? "
|
66
|
+
res = gets
|
67
|
+
@infinite_choice = res if res.match(/z/i)
|
68
|
+
end
|
69
|
+
|
70
|
+
if res.match(/y/i)
|
71
|
+
scott = bob
|
72
|
+
scott.save
|
73
|
+
elsif res.match(/a/i)
|
74
|
+
raise "User Salted the earth. Nothing will grow here for some time ..."
|
75
|
+
elsif res.match(/i/i)
|
76
|
+
bob.id = nil
|
77
|
+
bob.save
|
78
|
+
else
|
79
|
+
puts "#{bob.class.name} with id #{bob.id} already exists, doing nothing."
|
80
|
+
end
|
81
|
+
else
|
82
|
+
bob.save
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end # End ClassMethods
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
##### Instance Methods #####
|
92
|
+
|
93
|
+
def diff(obj)
|
94
|
+
buff = {}
|
95
|
+
self.attributes.each do |k, v|
|
96
|
+
tmp = obj.send(k) if obj.respond_to?(k)
|
97
|
+
if tmp.eql?(v)
|
98
|
+
# they're the same, do nothing
|
99
|
+
else
|
100
|
+
buff[k] = {:original => v, :new => tmp}
|
101
|
+
end
|
102
|
+
end # end self.attributes.each
|
103
|
+
buff
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
# Called on an particular instance of a class to render it down into a file, from which it can be
|
108
|
+
# _reaped_ later.
|
109
|
+
def plant_seed(options = {})
|
110
|
+
c = self.class.to_s.underscore.pluralize
|
111
|
+
# Code to render down associated items exists, but nothing has been done to pull those objects back out.
|
112
|
+
# Not automatically at least, but of course reaping the correct model will pull them up no problem.
|
113
|
+
|
114
|
+
|
115
|
+
# TODO
|
116
|
+
# need to load the file up and see if the thing i'm trying to add is in it
|
117
|
+
# or just overwrite the whole file every time.
|
118
|
+
# Do something to prevent duplicates from slipping in.
|
119
|
+
dir = File.join [Rails.root, 'db', 'garden']
|
120
|
+
Dir.mkdir(dir) unless File.exists?(dir)
|
121
|
+
|
122
|
+
|
123
|
+
File.open(File.join([Rails.root, 'db', 'garden', "#{c}.yml"] ), 'a') do |file|
|
124
|
+
file << self.to_yaml
|
125
|
+
end
|
126
|
+
|
127
|
+
includes = things_to_include(options)
|
128
|
+
puts includes
|
129
|
+
includes.each do |k, v|
|
130
|
+
tom = self.send(k) if self.respond_to?(k)
|
131
|
+
[*tom].each{|y| y.plant_seed({:include => v})}
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
def things_to_include(options)
|
138
|
+
# [*THING] is so that THING can be an array or a single instance of a class.
|
139
|
+
# .each will blow up if THING is just an instance, not an array, unless we explode and re-array it.
|
140
|
+
return [] unless options[:include]
|
141
|
+
case options[:include]
|
142
|
+
when Hash
|
143
|
+
options[:include].inject({}){|memo, v| memo[v[0]] = v[1] if self.respond_to?(v[0]); memo}
|
144
|
+
else
|
145
|
+
[*options[:include]]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def to_fixture
|
150
|
+
{"#{self.class.to_s.underscore}_#{self.id}" => self.attributes}.to_yaml
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
ActiveRecord::Base.class_eval{ include Gardener }
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gardener
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Bob Larrick
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-02-08 00:00:00 -05:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: A Ruby on Rails Plugin to help you create seed data. Useful when you want to move just a few pieces of data from one environment to another. To my knowledge there is no other gem that will help you move a few records from your development or staging environment to your production environment.
|
22
|
+
email: larrick@gmail.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files:
|
28
|
+
- README.rdoc
|
29
|
+
files:
|
30
|
+
- lib/gardener.rb
|
31
|
+
- README.rdoc
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: https://github.com/deathbob/Gardener
|
34
|
+
licenses: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
version: "0"
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.3.7
|
61
|
+
signing_key:
|
62
|
+
specification_version: 3
|
63
|
+
summary: Simple Seed Data Creation for Ruby on Rails.
|
64
|
+
test_files: []
|
65
|
+
|