sprig 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 45e7ad607a25ae6b5ddd621ba63d2dc51d97ecf9
4
- data.tar.gz: b156960667081a75408bab2b2f5363a89b320d35
3
+ metadata.gz: d2748e6392c09851ed00b725700d826a95fd3568
4
+ data.tar.gz: b826aa49873ab82d3a738d03328d444d19e67ff1
5
5
  SHA512:
6
- metadata.gz: 69ab1c4161a19017678b2e03bbd6af6edb62ef498a56cc0d7c8e16b6097e9b72e66890f17605786eaa78bbbc9eb264e9034075728de8275e12f02ff2a28a112c
7
- data.tar.gz: 231648356a91e8f181161a6c9077161d4eb1d2e178ad1e04c96290029f11fdbb9b9a1f7459f774db6ce143cc2a23514d99faa3a8da65a419e347652adde26b1e
6
+ metadata.gz: 007edb3280e9bd30a4ddebe436a3d07e9a7c0d72525dab0e0ea3b22754027f7551fb857838b076411f682a27e3bc3b1a0a322642d1f00f50f5f981cff66c563b
7
+ data.tar.gz: fd2563c0b6bfb9086a396d1c6b914b38c9263084a9056dc0551686393165f69a56d046e5a228de92d54bf0066e18c276a782bf1d57832d7c1ba611b61ba23bb8
data/README.md CHANGED
@@ -147,4 +147,52 @@ Sprig.configure do |c|
147
147
  end
148
148
  ```
149
149
 
150
+ ## Populate Seed Files from Database
151
+
152
+ Don't want to write Sprig seed files from scratch? Well, Sprig can create them for you!
153
+
154
+ Via a rake task:
155
+ ```
156
+ rake db:seed:reap
157
+ ```
158
+ Or from the Rails console:
159
+ ```
160
+ Sprig::Harvest.reap
161
+ ```
162
+
163
+ By default, Sprig will create seed files (currently in `.yaml` only) for every model in your Rails
164
+ application. The seed files will be placed in a folder in `db/seeds` named after the current
165
+ `Rails.env`.
166
+
167
+ If any of the models in your application are using STI, Sprig will create a single seed file named
168
+ after the STI base model. STI sub-type records will all be written to that file.
169
+
170
+ ### Additional Configuration
171
+
172
+ Don't like the defaults when reaping Sprig records? You may specify the environment (`db/seeds`
173
+ target folder) or models (`ActiveRecord::Base.subclasses`-only) you want seed files for.
174
+
175
+ Example (rake task):
176
+ ```
177
+ rake db:seed:reap ENV=integration MODELS=User, Post
178
+ ```
179
+
180
+ Example (Rails console):
181
+ ```
182
+ Sprig::Harvest.reap(env: 'integration', models: [User, Post])
183
+ ```
184
+
185
+ ### Adding to Existing Seed Files (`.yaml` only)
186
+
187
+ Already have some seed files set up? No worries! Sprig will detect existing seed files and append
188
+ to them with the records from your database with no extra work needed. Sprig will automatically
189
+ assign unique `sprig_ids` so you won't have to deal with pesky duplicates.
190
+
191
+ NOTE: Sprig does not account for your application or database validations. If you reap seed files
192
+ from your database multiple times in a row without deleting the previous seed files or sprig
193
+ records, you'll end up with duplicate sprig records (but they'll all have unique `sprig_ids`). This
194
+ may cause validation issues when you seed your database.
195
+
196
+ ## License
197
+
150
198
  This project rocks and uses MIT-LICENSE.
@@ -1,6 +1,7 @@
1
1
  module Sprig
2
2
  autoload :Configuration, 'sprig/configuration'
3
3
  autoload :Planter, 'sprig/planter'
4
+ autoload :TsortableHash, 'sprig/tsortable_hash'
4
5
  autoload :Dependency, 'sprig/dependency'
5
6
  autoload :DependencyCollection, 'sprig/dependency_collection'
6
7
  autoload :DependencySorter, 'sprig/dependency_sorter'
@@ -16,6 +17,8 @@ module Sprig
16
17
  autoload :SprigRecordStore, 'sprig/sprig_record_store'
17
18
  autoload :Data, 'sprig/data'
18
19
  autoload :Seed, 'sprig/seed'
20
+ autoload :Harvest, 'sprig/harvest'
21
+ autoload :Railtie, 'sprig/railtie'
19
22
 
20
23
  class << self
21
24
  def configuration
@@ -54,16 +54,6 @@ module Sprig
54
54
  MissingDependencyError.new(missing_dependency)
55
55
  end
56
56
 
57
- class TsortableHash < Hash
58
- include TSort
59
-
60
- alias tsort_each_node each_key
61
-
62
- def tsort_each_child(node, &block)
63
- fetch(node).each(&block)
64
- end
65
- end
66
-
67
57
  class MissingDependencyError < StandardError
68
58
  def initialize(missing_dependency = nil)
69
59
  super message_for(missing_dependency)
@@ -0,0 +1,33 @@
1
+ module Sprig
2
+ module Harvest
3
+ autoload :Configuration, 'sprig/harvest/configuration'
4
+ autoload :Model, 'sprig/harvest/model'
5
+ autoload :Record, 'sprig/harvest/record'
6
+ autoload :SeedFile, 'sprig/harvest/seed_file'
7
+
8
+ class << self
9
+ def reap(options = {})
10
+ configure do |config|
11
+ config.env = options[:env] || options['ENV']
12
+ config.classes = options[:models] || options['MODELS']
13
+ end
14
+
15
+ Model.all.each { |model| SeedFile.new(model).write }
16
+ end
17
+
18
+ private
19
+
20
+ cattr_reader :configuration
21
+
22
+ delegate :env, :classes, to: :configuration
23
+
24
+ def configuration
25
+ @@configuration ||= Configuration.new
26
+ end
27
+
28
+ def configure
29
+ yield configuration
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,63 @@
1
+ module Sprig
2
+ module Harvest
3
+ class Configuration
4
+ VALID_CLASSES = ActiveRecord::Base.subclasses
5
+
6
+ def env
7
+ @env ||= Rails.env
8
+ end
9
+
10
+ def env=(given_env)
11
+ parse_valid_env_from given_env do |environment|
12
+ @env = environment
13
+ end
14
+ end
15
+
16
+ def classes
17
+ @classes ||= VALID_CLASSES
18
+ end
19
+
20
+ def classes=(given_classes)
21
+ parse_valid_classes_from given_classes do |classes|
22
+ @classes = classes
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def parse_valid_env_from(input)
29
+ return if input.nil?
30
+ environment = input.strip.downcase
31
+ create_seeds_folder(environment)
32
+ yield environment
33
+ end
34
+
35
+ def create_seeds_folder(env)
36
+ folder = Rails.root.join('db', 'seeds', env)
37
+ FileUtils.mkdir_p(folder) unless File.directory? folder
38
+ end
39
+
40
+ def parse_valid_classes_from(input)
41
+ return if input.nil?
42
+
43
+ classes = if input.is_a? String
44
+ input.split(',').map { |klass_string| klass_string.strip.classify.constantize }
45
+ else
46
+ input
47
+ end
48
+
49
+ validate_classes(classes)
50
+
51
+ yield classes
52
+ end
53
+
54
+ def validate_classes(classes)
55
+ classes.each do |klass|
56
+ unless VALID_CLASSES.include? klass
57
+ raise ArgumentError, "Cannot create a seed file for #{klass} because it is not a subclass of ActiveRecord::Base."
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,77 @@
1
+ module Sprig
2
+ module Harvest
3
+ class Model
4
+ def self.all
5
+ @@all ||= begin
6
+ models = Sprig::Harvest.classes.map { |klass| new(klass) }
7
+
8
+ tsorted_classes(models).map do |klass|
9
+ models.find { |model| model.klass == klass }
10
+ end
11
+ end
12
+ end
13
+
14
+ def self.find(klass, id)
15
+ all.find { |model| model.klass == klass }.find(id)
16
+ end
17
+
18
+ attr_reader :klass
19
+ attr_writer :existing_sprig_ids
20
+
21
+ def initialize(klass)
22
+ @klass = klass
23
+ end
24
+
25
+ def attributes
26
+ klass.column_names
27
+ end
28
+
29
+ def dependencies
30
+ @dependencies ||= klass.reflect_on_all_associations(:belongs_to).map do |association|
31
+ association.name.to_s.classify.constantize
32
+ end
33
+ end
34
+
35
+ def existing_sprig_ids
36
+ @existing_sprig_ids ||= []
37
+ end
38
+
39
+ def generate_sprig_id
40
+ existing_sprig_ids.select { |i| i.is_a? Integer }.sort.last + 1
41
+ end
42
+
43
+ def find(id)
44
+ records.find { |record| record.id == id }
45
+ end
46
+
47
+ def to_s
48
+ klass.to_s
49
+ end
50
+
51
+ def to_yaml(options = {})
52
+ namespace = options[:namespace]
53
+ formatted_records = records.map(&:to_hash)
54
+
55
+ yaml = if namespace
56
+ { namespace => formatted_records }.to_yaml
57
+ else
58
+ formatted_records.to_yaml
59
+ end
60
+
61
+ yaml.gsub("---\n", '') # Remove annoying YAML separator
62
+ end
63
+
64
+ def records
65
+ @records ||= klass.all.map { |record| Record.new(record, self) }
66
+ end
67
+
68
+ private
69
+
70
+ def self.tsorted_classes(models)
71
+ models.reduce(TsortableHash.new) do |hash, model|
72
+ hash.merge(model.klass => model.dependencies)
73
+ end.tsort
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,61 @@
1
+ module Sprig
2
+ module Harvest
3
+ class Record
4
+ attr_reader :record, :model
5
+ attr_writer :sprig_id
6
+
7
+ def initialize(record, model)
8
+ @record = record
9
+ @model = model
10
+ end
11
+
12
+ def attributes
13
+ @attributes ||= Array.new.replace(model.attributes).tap do |attrs|
14
+ attrs[0] = 'sprig_id'
15
+ end
16
+ end
17
+
18
+ def to_hash
19
+ attributes.reduce(Hash.new) { |hash, attr| hash.merge(attr => send(attr)) }
20
+ end
21
+
22
+ def sprig_id
23
+ @sprig_id ||= model.existing_sprig_ids.include?(record.id) ? model.generate_sprig_id : record.id
24
+ end
25
+
26
+ private
27
+
28
+ def method_missing(method, *args, &block)
29
+ attr = model.attributes.find { |attr| attr == method.to_s }
30
+
31
+ if attr.nil?
32
+ super
33
+ elsif dependency_finder.match(attr)
34
+ klass = klass_for(attr)
35
+ id = record.send(attr)
36
+ sprig_id = Model.find(klass, id).sprig_id
37
+
38
+ sprig_record(klass, sprig_id)
39
+ else
40
+ record.send(attr)
41
+ end
42
+ end
43
+
44
+ def respond_to_missing?(method, include_private = false)
45
+ model.attributes.include?(method.to_s) || super
46
+ end
47
+
48
+ def dependency_finder
49
+ /_id/
50
+ end
51
+
52
+ def klass_for(attr)
53
+ attr.gsub(dependency_finder, '').classify.constantize
54
+ end
55
+
56
+ def sprig_record(klass, sprig_id)
57
+ "<%= sprig_record(#{klass}, #{sprig_id}).id %>"
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,54 @@
1
+ module Sprig
2
+ module Harvest
3
+ class SeedFile
4
+ DEFAULT_NAMESPACE = 'records'
5
+
6
+ attr_reader :model
7
+
8
+ def initialize(model)
9
+ raise ArgumentError, 'Must initialize with a Sprig::Harvest::Model' unless model.is_a? Model
10
+
11
+ @model = model
12
+ end
13
+
14
+ def path
15
+ Rails.root.join('db', 'seeds', Sprig::Harvest.env, "#{model.to_s.tableize.gsub('/', '_')}.yml")
16
+ end
17
+
18
+ def exists?
19
+ File.exists?(path)
20
+ end
21
+
22
+ def write
23
+ initialize_file do |file, namespace|
24
+ file.write model.to_yaml(:namespace => namespace)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def initialize_file
31
+ existing_file = exists?
32
+ access_type = existing_file ? 'a+' : 'w'
33
+
34
+ File.open(path, access_type) do |file|
35
+ namespace = DEFAULT_NAMESPACE
36
+
37
+ if existing_file
38
+ model.existing_sprig_ids = existing_sprig_ids(file.read)
39
+ namespace = nil
40
+ file.write("\n")
41
+ end
42
+
43
+ yield file, namespace
44
+ end
45
+ end
46
+
47
+ def existing_sprig_ids(yaml)
48
+ YAML.load(yaml).fetch(DEFAULT_NAMESPACE).to_a.map do |record|
49
+ record.fetch('sprig_id')
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,7 @@
1
+ module Sprig
2
+ class Railtie < Rails::Railtie
3
+ rake_tasks do
4
+ load 'tasks/reap.rake'
5
+ end
6
+ end
7
+ end
@@ -35,7 +35,11 @@ module Sprig
35
35
  end
36
36
 
37
37
  def success_log_text
38
- "#{klass.name} with sprig_id #{sprig_id} successfully saved."
38
+ "#{klass.name} with sprig_id #{sprig_id} successfully #{success_log_status_text}."
39
+ end
40
+
41
+ def success_log_status_text
42
+ record.existing? ? "updated" : "saved"
39
43
  end
40
44
 
41
45
  def error_log_text
@@ -11,9 +11,10 @@ module Sprig
11
11
  end
12
12
 
13
13
  def initialize(klass, attributes, orm_record = nil)
14
- @klass = klass
14
+ @klass = klass
15
15
  @attributes = attributes
16
16
  @orm_record = orm_record || klass.new
17
+ @existing = @orm_record.persisted?
17
18
  end
18
19
 
19
20
  def save
@@ -21,6 +22,10 @@ module Sprig
21
22
  orm_record.save
22
23
  end
23
24
 
25
+ def existing?
26
+ @existing
27
+ end
28
+
24
29
  private
25
30
 
26
31
  attr_reader :attributes, :klass
@@ -0,0 +1,11 @@
1
+ module Sprig
2
+ class TsortableHash < Hash
3
+ include TSort
4
+
5
+ alias tsort_each_node each_key
6
+
7
+ def tsort_each_child(node, &block)
8
+ fetch(node).each(&block)
9
+ end
10
+ end
11
+ end
@@ -1,3 +1,3 @@
1
1
  module Sprig
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
@@ -0,0 +1,9 @@
1
+ namespace :db do
2
+ namespace :seed do
3
+ desc 'Create Sprig seed files from database records'
4
+ task :reap => :environment do
5
+ Rails.application.eager_load!
6
+ Sprig::Harvest.reap(ENV)
7
+ end
8
+ end
9
+ end
Binary file
@@ -0,0 +1,7 @@
1
+ records:
2
+ - sprig_id: 10
3
+ post_id: <%= sprig_record(Post, 2).id %>
4
+ body: pork chop sandwiches
5
+ - sprig_id: 20
6
+ post_id: <%= sprig_record(Post, 1).id %>
7
+ body: do you play baseball?
@@ -0,0 +1,9 @@
1
+ records:
2
+ - sprig_id: 1
3
+ title: such post
4
+ content: Once upon a time BOOM POSTED
5
+ published: true
6
+ - sprig_id: 2
7
+ title: very words
8
+ content: Word cannon has been loaded up real good.
9
+ published: true
@@ -0,0 +1,7 @@
1
+ records:
2
+ - sprig_id: 1
3
+ post_id: <%= sprig_record(Post, 1).id %>
4
+ body:
5
+ - sprig_id: 2
6
+ post_id: <%= sprig_record(Post, 2).id %>
7
+ body:
@@ -0,0 +1,6 @@
1
+ - sprig_id: 1
2
+ post_id: <%= sprig_record(Post, 1).id %>
3
+ body:
4
+ - sprig_id: 2
5
+ post_id: <%= sprig_record(Post, 2).id %>
6
+ body:
@@ -0,0 +1,7 @@
1
+ records:
2
+ - sprig_id: 5
3
+ first_name: Bo
4
+ last_name: Janglez
5
+ - sprig_id: 9
6
+ first_name: Jimmy
7
+ last_name: Russel
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sprig::Harvest::Configuration do
4
+ subject { described_class.new }
5
+
6
+ before do
7
+ stub_rails_root
8
+ end
9
+
10
+ describe "#env" do
11
+ context "from a fresh configuration" do
12
+ its(:env) { should == Rails.env }
13
+ end
14
+ end
15
+
16
+ describe "#env=" do
17
+ context "when given nil" do
18
+ it "does not change the env" do
19
+ subject.env = nil
20
+
21
+ subject.env.should_not == nil
22
+ end
23
+ end
24
+
25
+ context "given a non-nil value" do
26
+ let(:input) { ' ShaBOOSH' }
27
+
28
+ it "formats the given value and then sets the environment" do
29
+ subject.env = input
30
+
31
+ subject.env.should == 'shaboosh'
32
+ end
33
+
34
+ context "and the corresponding seeds folder does not yet exist" do
35
+ after do
36
+ FileUtils.remove_dir('./spec/fixtures/db/seeds/shaboosh')
37
+ end
38
+
39
+ it "creates the seeds folder" do
40
+ subject.env = input
41
+
42
+ File.directory?('./spec/fixtures/db/seeds/shaboosh').should == true
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ describe "#classes" do
49
+ context "from a fresh configuration" do
50
+ its(:classes) { should == ActiveRecord::Base.subclasses }
51
+ end
52
+ end
53
+
54
+ describe "#classes=" do
55
+ context "when given nil" do
56
+ it "does not set classes to nil" do
57
+ subject.classes = nil
58
+
59
+ subject.classes.should_not == nil
60
+ end
61
+ end
62
+
63
+ context "when given an array of classes" do
64
+ context "where one or more classes are not subclasses of ActiveRecord::Base" do
65
+ it "raises an error" do
66
+ expect {
67
+ subject.classes = [Comment, Sprig::Harvest::Model]
68
+ }.to raise_error ArgumentError, 'Cannot create a seed file for Sprig::Harvest::Model because it is not a subclass of ActiveRecord::Base.'
69
+ end
70
+ end
71
+
72
+ context "where all classes are subclasses of ActiveRecord::Base" do
73
+ it "sets classes to the given input" do
74
+ subject.classes = [Comment, Post]
75
+
76
+ subject.classes.should == [Comment, Post]
77
+ end
78
+ end
79
+ end
80
+
81
+ context "when given a string" do
82
+ context "where one or more classes are not subclasses of ActiveRecord::Base" do
83
+ it "raises an error" do
84
+ expect {
85
+ subject.classes = 'Sprig::Harvest::Model'
86
+ }.to raise_error ArgumentError, 'Cannot create a seed file for Sprig::Harvest::Model because it is not a subclass of ActiveRecord::Base.'
87
+ end
88
+ end
89
+
90
+ context "where all classes are subclasses of ActiveRecord::Base" do
91
+ it "sets classes to the parsed input" do
92
+ subject.classes = ' comment, post'
93
+
94
+ subject.classes.should == [Comment, Post]
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,120 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sprig::Harvest::Model do
4
+ describe ".all" do
5
+ let(:all_models) do
6
+ [
7
+ described_class.new(Post),
8
+ described_class.new(Comment),
9
+ described_class.new(User)
10
+ ]
11
+ end
12
+
13
+ before do
14
+ Sprig::Harvest.stub(:classes).and_return([Comment, Post, User])
15
+ end
16
+
17
+ it "returns an dependency-sorted array of Sprig::Harvest::Models" do
18
+ described_class.all.all? { |model| model.is_a? Sprig::Harvest::Model }.should == true
19
+ described_class.all.map(&:klass).should == all_models.map(&:klass)
20
+ end
21
+ end
22
+
23
+ describe ".find" do
24
+ let!(:user) { User.create(:first_name => 'Bo', :last_name => 'Janglez') }
25
+ let!(:post1) { Post.create }
26
+ let!(:post2) { Post.create }
27
+ let!(:comment1) { Comment.create(:post => post1) }
28
+ let!(:comment2) { Comment.create(:post => post2) }
29
+
30
+ subject { described_class }
31
+
32
+ it "returns the Sprig::Harvest::Record for the given class and id" do
33
+ subject.find(User, 1).record.should == user
34
+ subject.find(Post, 1).record.should == post1
35
+ subject.find(Post, 2).record.should == post2
36
+ subject.find(Comment, 1).record.should == comment1
37
+ subject.find(Comment, 2).record.should == comment2
38
+ end
39
+ end
40
+
41
+ describe "#attributes" do
42
+ subject { described_class.new(User) }
43
+
44
+ its(:attributes) { should == User.column_names }
45
+ end
46
+
47
+ describe "#dependencies" do
48
+ subject { described_class.new(Comment) }
49
+
50
+ its(:dependencies) { should == [Post] }
51
+ end
52
+
53
+ describe "#find" do
54
+ let!(:post1) { Post.create }
55
+ let!(:post2) { Post.create }
56
+
57
+ subject { described_class.new(Post) }
58
+
59
+ it "returns the Sprig::Harvest::Record with the given id" do
60
+ harvest_record = subject.find(2)
61
+ harvest_record.should be_an_instance_of Sprig::Harvest::Record
62
+ harvest_record.record.should == post2
63
+ end
64
+ end
65
+
66
+ describe "#generate_sprig_id" do
67
+ subject { described_class.new(Comment) }
68
+
69
+ context "when the existing sprig_ids are all integers" do
70
+ before do
71
+ subject.existing_sprig_ids = [5, 20, 8]
72
+ end
73
+
74
+ it "returns an integer-type sprig_id that is not taken" do
75
+ subject.generate_sprig_id.should == 21
76
+ end
77
+ end
78
+
79
+ context "when the existing sprig ids contain non-integer values" do
80
+ before do
81
+ subject.existing_sprig_ids = [1, 5, 'l_2', 'l_10', 'such_sprigs', 10.9]
82
+ end
83
+ it "returns an integer-type sprig_id that is not taken" do
84
+ subject.generate_sprig_id.should == 6
85
+ end
86
+ end
87
+ end
88
+
89
+ describe "#to_s" do
90
+ subject { described_class.new(Comment) }
91
+
92
+ its(:to_s) { should == "Comment" }
93
+ end
94
+
95
+ describe "#to_yaml" do
96
+ let!(:user) { User.create(:first_name => 'Bo', :last_name => 'Janglez') }
97
+ let!(:post1) { Post.create }
98
+ let!(:post2) { Post.create }
99
+ let!(:comment1) { Comment.create(:post => post1) }
100
+ let!(:comment2) { Comment.create(:post => post2) }
101
+
102
+ subject { described_class.new(Comment) }
103
+
104
+ context "when passed a value for the namespace" do
105
+ it "returns the correct yaml" do
106
+ subject.to_yaml(:namespace => 'records').should == yaml_from_file('records_with_namespace.yml')
107
+ end
108
+ end
109
+
110
+ context "when no namespace is given" do
111
+ it "returns the correct yaml" do
112
+ subject.to_yaml.should == yaml_from_file('records_without_namespace.yml')
113
+ end
114
+ end
115
+ end
116
+
117
+ def yaml_from_file(basename)
118
+ File.read('spec/fixtures/yaml/' + basename)
119
+ end
120
+ end
@@ -0,0 +1,70 @@
1
+ require 'spec_helper'
2
+
3
+ class Very; end
4
+
5
+ describe Sprig::Harvest::Record do
6
+ let(:record) { double('ActiveRecord::Base Instance') }
7
+ let(:model) { double('Sprig::Harvest::Model') }
8
+ let(:harvest_record) { double('Sprig::Harvest::Record for class Very', :sprig_id => 5) }
9
+ let(:sprig_record) { "<%= sprig_record(Very, 5).id %>" }
10
+
11
+ subject { described_class.new(record, model) }
12
+
13
+ before do
14
+ attrs = {
15
+ 'id' => 0,
16
+ 'such' => 1,
17
+ 'wow' => 2,
18
+ 'very_id' => 3
19
+ }
20
+
21
+ attrs.each_pair do |attr, val|
22
+ record.stub(attr).and_return(val)
23
+ end
24
+
25
+ model.stub(:attributes).and_return(attrs.keys)
26
+ model.stub(:existing_sprig_ids).and_return([])
27
+
28
+ Sprig::Harvest::Model.stub(:find).and_return(harvest_record)
29
+ end
30
+
31
+ its(:id) { should == 0 }
32
+ its(:such) { should == 1 }
33
+ its(:wow) { should == 2 }
34
+ its(:very_id) { should == sprig_record }
35
+
36
+ describe "#attributes" do
37
+ it "returns an array of attributes from the given model with sprig_id swapped out for id" do
38
+ subject.attributes.should == %w(
39
+ sprig_id
40
+ such
41
+ wow
42
+ very_id
43
+ )
44
+ end
45
+ end
46
+
47
+ describe "#to_hash" do
48
+ it "returns its attributes and their values in a hash" do
49
+ subject.to_hash.should == {
50
+ 'sprig_id' => 0,
51
+ 'such' => 1,
52
+ 'wow' => 2,
53
+ 'very_id' => sprig_record
54
+ }
55
+ end
56
+ end
57
+
58
+ describe "#sprig_id" do
59
+ its(:sprig_id) { should == record.id }
60
+
61
+ context "when an existing seed record has a sprig_id equal to the record's id" do
62
+ before do
63
+ model.stub(:existing_sprig_ids).and_return([record.id])
64
+ model.stub(:generate_sprig_id).and_return(25)
65
+ end
66
+
67
+ its(:sprig_id) { should == 25 }
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,109 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sprig::Harvest::SeedFile do
4
+ let(:model) { Sprig::Harvest::Model.new(Comment) }
5
+
6
+ subject { described_class.new(model) }
7
+
8
+ before do
9
+ stub_rails_root
10
+ Sprig::Harvest.stub(:env).and_return('dreamland')
11
+ end
12
+
13
+ describe "#initialize" do
14
+ context "given a non-Sprig::Harvest::Model" do
15
+ it "raises an error" do
16
+ expect {
17
+ described_class.new(User)
18
+ }.to raise_error ArgumentError, 'Must initialize with a Sprig::Harvest::Model'
19
+ end
20
+ end
21
+ end
22
+
23
+ describe "#path" do
24
+ around do |example|
25
+ setup_seed_folder('./spec/fixtures/db/seeds/dreamland', &example)
26
+ end
27
+
28
+ its(:path) { should == Rails.root.join('db', 'seeds', 'dreamland', 'comments.yml') }
29
+ end
30
+
31
+ describe "#exists?" do
32
+ subject { described_class.new(model) }
33
+
34
+ around do |example|
35
+ setup_seed_folder('./spec/fixtures/db/seeds/dreamland', &example)
36
+ end
37
+
38
+ context "when the seed file already exists" do
39
+ before do
40
+ File.stub(:exists?).with(subject.path).and_return(true)
41
+ end
42
+
43
+ its(:exists?) { should == true }
44
+ end
45
+
46
+ context "when the seed file does not exist" do
47
+ its(:exists?) { should == false }
48
+ end
49
+ end
50
+
51
+ describe "#write" do
52
+ let!(:user) { User.create(:first_name => 'Bo', :last_name => 'Janglez') }
53
+ let!(:post1) { Post.create }
54
+ let!(:post2) { Post.create }
55
+ let!(:comment1) { Comment.create(:post => post1) }
56
+ let!(:comment2) { Comment.create(:post => post2) }
57
+
58
+ around do |example|
59
+ setup_seed_folder('./spec/fixtures/db/seeds/dreamland', &example)
60
+ end
61
+
62
+ context "when the seed file already exists" do
63
+ before do
64
+ yaml = File.read('./spec/fixtures/yaml/comment_seeds.yml')
65
+ File.open(subject.path, 'w') { |file| file.write(yaml) }
66
+ end
67
+
68
+ it "pulls out the existing sprig ids and stores them on the given model" do
69
+ model.should_receive(:existing_sprig_ids=).with([10, 20])
70
+
71
+ subject.write
72
+ end
73
+
74
+ it "grabs the yaml for the given model without a namespace" do
75
+ model.should_receive(:to_yaml).with(:namespace => nil)
76
+
77
+ subject.write
78
+ end
79
+
80
+ it "populates the file" do
81
+ starting_size = File.size(subject.path)
82
+
83
+ subject.write
84
+
85
+ File.size?(subject.path).should > starting_size
86
+ end
87
+ end
88
+
89
+ context "when the seed file does not yet exist" do
90
+ it "does not pass any existing sprig ids to the given model" do
91
+ model.should_not_receive(:existing_sprig_ids=)
92
+
93
+ subject.write
94
+ end
95
+
96
+ it "grabs the yaml for the given model with the 'records' namespace" do
97
+ model.should_receive(:to_yaml).with(:namespace => 'records')
98
+
99
+ subject.write
100
+ end
101
+
102
+ it "populates the file" do
103
+ subject.write
104
+
105
+ File.size?(subject.path).should > 0
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sprig::Harvest do
4
+ describe ".reap" do
5
+ let(:seed_file) { double('Sprig::Harvest::SeedFile', :write => 'such seeds') }
6
+
7
+ before do
8
+ stub_rails_root
9
+ stub_rails_env('dreamland')
10
+ Sprig::Harvest::SeedFile.stub(:new).and_return(seed_file)
11
+ end
12
+
13
+ around do |example|
14
+ setup_seed_folder('./spec/fixtures/db/seeds/dreamland', &example)
15
+ end
16
+
17
+ it "generates a seed file for each class" do
18
+ seed_file.should_receive(:write).exactly(3).times
19
+
20
+ subject.reap
21
+ end
22
+
23
+ context "when passed an environment in the options hash" do
24
+ context "in :env" do
25
+ it "sets the environment" do
26
+ subject.reap(:env => 'integration')
27
+ subject.env.should == 'integration'
28
+ end
29
+ end
30
+
31
+ context "in 'ENV'" do
32
+ it "sets the environment" do
33
+ subject.reap('ENV' => ' Integration')
34
+ subject.env.should == 'integration'
35
+ end
36
+ end
37
+ end
38
+
39
+ context "when passed a set of classes in the options hash" do
40
+ context "in :classes" do
41
+ it "sets the classes" do
42
+ subject.reap(:models => [User, Post])
43
+ subject.classes.should == [User, Post]
44
+ end
45
+ end
46
+
47
+ context "sets the classes" do
48
+ it "passes the value to its configuration" do
49
+ subject.reap('MODELS' => 'User, Post')
50
+ subject.classes.should == [User, Post]
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sprig::Seed::Entry do
4
+ describe ".success_log_text" do
5
+ context "on a new record" do
6
+ it "indicates the record was 'saved'" do
7
+ subject = described_class.new(Post, { title: "Hello World!", content: "Stuff", sprig_id: 1 }, {})
8
+ subject.save_record
9
+
10
+ subject.success_log_text.should == "Post with sprig_id 1 successfully saved."
11
+ end
12
+ end
13
+
14
+ context "on an existing record" do
15
+ let!(:existing) do
16
+ Post.create(
17
+ :title => "Existing title",
18
+ :content => "Existing content",
19
+ :published => false
20
+ )
21
+ end
22
+
23
+ it "indicates the record was 'updated'" do
24
+ subject = described_class.new(Post, { title: "Existing title", content: "Existing content", sprig_id: 1 }, { find_existing_by: [:title] })
25
+ subject.save_record
26
+
27
+ subject.success_log_text.should == "Post with sprig_id 1 successfully updated."
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sprig::Seed::Record do
4
+ describe ".existing?" do
5
+ let!(:existing) do
6
+ Post.create(
7
+ :title => "Existing title",
8
+ :content => "Existing content",
9
+ :published => false
10
+ )
11
+ end
12
+
13
+ it "returns true if the record has already been saved to the database" do
14
+ subject = described_class.new_or_existing(Post, { title: "Existing title" }, { title: "Existing title" })
15
+
16
+ subject.existing?.should == true
17
+ end
18
+
19
+ it "returns false if the record is new" do
20
+ subject = described_class.new_or_existing(Post, { title: "New title" }, { title: "New title" })
21
+
22
+ subject.existing?.should == false
23
+ end
24
+ end
25
+ end
@@ -78,3 +78,12 @@ def load_seeds(*files)
78
78
  `rm ./spec/fixtures/db/seeds/#{env}/#{file}`
79
79
  end
80
80
  end
81
+
82
+ # Create and remove seed folder around a spec
83
+ def setup_seed_folder(path)
84
+ FileUtils.mkdir_p(path)
85
+
86
+ yield
87
+
88
+ FileUtils.remove_dir(path)
89
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sprig
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lawson Kurtz
@@ -9,118 +9,118 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-05-14 00:00:00.000000000 Z
12
+ date: 2014-06-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - "~>"
18
+ - - ~>
19
19
  - !ruby/object:Gem::Version
20
20
  version: '3.1'
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - "~>"
25
+ - - ~>
26
26
  - !ruby/object:Gem::Version
27
27
  version: '3.1'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: sqlite3
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - "~>"
32
+ - - ~>
33
33
  - !ruby/object:Gem::Version
34
34
  version: 1.3.8
35
35
  type: :development
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - "~>"
39
+ - - ~>
40
40
  - !ruby/object:Gem::Version
41
41
  version: 1.3.8
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: rspec
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - "~>"
46
+ - - ~>
47
47
  - !ruby/object:Gem::Version
48
48
  version: 2.14.0
49
49
  type: :development
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - "~>"
53
+ - - ~>
54
54
  - !ruby/object:Gem::Version
55
55
  version: 2.14.0
56
56
  - !ruby/object:Gem::Dependency
57
57
  name: database_cleaner
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - "~>"
60
+ - - ~>
61
61
  - !ruby/object:Gem::Version
62
62
  version: 1.2.0
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - "~>"
67
+ - - ~>
68
68
  - !ruby/object:Gem::Version
69
69
  version: 1.2.0
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: webmock
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
- - - "~>"
74
+ - - ~>
75
75
  - !ruby/object:Gem::Version
76
76
  version: 1.15.0
77
77
  type: :development
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
- - - "~>"
81
+ - - ~>
82
82
  - !ruby/object:Gem::Version
83
83
  version: 1.15.0
84
84
  - !ruby/object:Gem::Dependency
85
85
  name: vcr
86
86
  requirement: !ruby/object:Gem::Requirement
87
87
  requirements:
88
- - - "~>"
88
+ - - ~>
89
89
  - !ruby/object:Gem::Version
90
90
  version: 2.8.0
91
91
  type: :development
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
- - - "~>"
95
+ - - ~>
96
96
  - !ruby/object:Gem::Version
97
97
  version: 2.8.0
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: pry
100
100
  requirement: !ruby/object:Gem::Requirement
101
101
  requirements:
102
- - - ">="
102
+ - - '>='
103
103
  - !ruby/object:Gem::Version
104
104
  version: '0'
105
105
  type: :development
106
106
  prerelease: false
107
107
  version_requirements: !ruby/object:Gem::Requirement
108
108
  requirements:
109
- - - ">="
109
+ - - '>='
110
110
  - !ruby/object:Gem::Version
111
111
  version: '0'
112
112
  - !ruby/object:Gem::Dependency
113
113
  name: generator_spec
114
114
  requirement: !ruby/object:Gem::Requirement
115
115
  requirements:
116
- - - ">="
116
+ - - '>='
117
117
  - !ruby/object:Gem::Version
118
118
  version: '0'
119
119
  type: :development
120
120
  prerelease: false
121
121
  version_requirements: !ruby/object:Gem::Requirement
122
122
  requirements:
123
- - - ">="
123
+ - - '>='
124
124
  - !ruby/object:Gem::Version
125
125
  version: '0'
126
126
  description: Sprig is a library for managing interconnected, environment-specific
@@ -144,6 +144,11 @@ files:
144
144
  - lib/sprig/dependency_sorter.rb
145
145
  - lib/sprig/directive.rb
146
146
  - lib/sprig/directive_list.rb
147
+ - lib/sprig/harvest.rb
148
+ - lib/sprig/harvest/configuration.rb
149
+ - lib/sprig/harvest/model.rb
150
+ - lib/sprig/harvest/record.rb
151
+ - lib/sprig/harvest/seed_file.rb
147
152
  - lib/sprig/helpers.rb
148
153
  - lib/sprig/logging.rb
149
154
  - lib/sprig/null_record.rb
@@ -155,6 +160,7 @@ files:
155
160
  - lib/sprig/parser/yml.rb
156
161
  - lib/sprig/planter.rb
157
162
  - lib/sprig/process_notifier.rb
163
+ - lib/sprig/railtie.rb
158
164
  - lib/sprig/seed.rb
159
165
  - lib/sprig/seed/attribute.rb
160
166
  - lib/sprig/seed/attribute_collection.rb
@@ -163,7 +169,9 @@ files:
163
169
  - lib/sprig/seed/record.rb
164
170
  - lib/sprig/source.rb
165
171
  - lib/sprig/sprig_record_store.rb
172
+ - lib/sprig/tsortable_hash.rb
166
173
  - lib/sprig/version.rb
174
+ - lib/tasks/reap.rake
167
175
  - spec/db/activerecord.db
168
176
  - spec/feature/configurations_spec.rb
169
177
  - spec/fixtures/cassettes/google_spreadsheet_json_posts.yml
@@ -184,12 +192,24 @@ files:
184
192
  - spec/fixtures/seeds/test/posts_find_existing_by_single.yml
185
193
  - spec/fixtures/seeds/test/posts_missing_dependency.yml
186
194
  - spec/fixtures/seeds/test/posts_missing_record.yml
195
+ - spec/fixtures/yaml/comment_seeds.yml
196
+ - spec/fixtures/yaml/post_seeds.yml
197
+ - spec/fixtures/yaml/records_with_namespace.yml
198
+ - spec/fixtures/yaml/records_without_namespace.yml
199
+ - spec/fixtures/yaml/user_seeds.yml
187
200
  - spec/lib/generators/sprig/install_generator_spec.rb
188
201
  - spec/lib/sprig/configuration_spec.rb
189
202
  - spec/lib/sprig/directive_list_spec.rb
190
203
  - spec/lib/sprig/directive_spec.rb
204
+ - spec/lib/sprig/harvest/configuration_spec.rb
205
+ - spec/lib/sprig/harvest/model_spec.rb
206
+ - spec/lib/sprig/harvest/record_spec.rb
207
+ - spec/lib/sprig/harvest/seed_file_spec.rb
208
+ - spec/lib/sprig/harvest_spec.rb
191
209
  - spec/lib/sprig/null_record_spec.rb
192
210
  - spec/lib/sprig/process_notifier_spec.rb
211
+ - spec/lib/sprig/seed/entry_spec.rb
212
+ - spec/lib/sprig/seed/record_spec.rb
193
213
  - spec/lib/sprig_spec.rb
194
214
  - spec/spec_helper.rb
195
215
  - spec/sprig_spec.rb
@@ -206,17 +226,17 @@ require_paths:
206
226
  - lib
207
227
  required_ruby_version: !ruby/object:Gem::Requirement
208
228
  requirements:
209
- - - ">="
229
+ - - '>='
210
230
  - !ruby/object:Gem::Version
211
231
  version: '0'
212
232
  required_rubygems_version: !ruby/object:Gem::Requirement
213
233
  requirements:
214
- - - ">="
234
+ - - '>='
215
235
  - !ruby/object:Gem::Version
216
236
  version: '0'
217
237
  requirements: []
218
238
  rubyforge_project:
219
- rubygems_version: 2.2.2
239
+ rubygems_version: 2.2.1
220
240
  signing_key:
221
241
  specification_version: 4
222
242
  summary: Relational, environment-specific seeding for Rails apps.
@@ -241,15 +261,28 @@ test_files:
241
261
  - spec/fixtures/seeds/test/posts_find_existing_by_single.yml
242
262
  - spec/fixtures/seeds/test/posts_missing_dependency.yml
243
263
  - spec/fixtures/seeds/test/posts_missing_record.yml
264
+ - spec/fixtures/yaml/comment_seeds.yml
265
+ - spec/fixtures/yaml/post_seeds.yml
266
+ - spec/fixtures/yaml/records_with_namespace.yml
267
+ - spec/fixtures/yaml/records_without_namespace.yml
268
+ - spec/fixtures/yaml/user_seeds.yml
244
269
  - spec/lib/generators/sprig/install_generator_spec.rb
245
270
  - spec/lib/sprig/configuration_spec.rb
246
271
  - spec/lib/sprig/directive_list_spec.rb
247
272
  - spec/lib/sprig/directive_spec.rb
273
+ - spec/lib/sprig/harvest/configuration_spec.rb
274
+ - spec/lib/sprig/harvest/model_spec.rb
275
+ - spec/lib/sprig/harvest/record_spec.rb
276
+ - spec/lib/sprig/harvest/seed_file_spec.rb
277
+ - spec/lib/sprig/harvest_spec.rb
248
278
  - spec/lib/sprig/null_record_spec.rb
249
279
  - spec/lib/sprig/process_notifier_spec.rb
280
+ - spec/lib/sprig/seed/entry_spec.rb
281
+ - spec/lib/sprig/seed/record_spec.rb
250
282
  - spec/lib/sprig_spec.rb
251
283
  - spec/spec_helper.rb
252
284
  - spec/sprig_spec.rb
253
285
  - spec/support/helpers/colored_text.rb
254
286
  - spec/support/helpers/logger_mock.rb
255
287
  - spec/support/shared_examples/a_logging_entity.rb
288
+ has_rdoc: