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.
Files changed (3) hide show
  1. data/README.rdoc +44 -0
  2. data/lib/gardener.rb +157 -0
  3. 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
+