gardener 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+