sprig-reap 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d9274dc514b03b7804de43aba385e8cc68d954af
4
+ data.tar.gz: f9c7b62a38c72b9745ef5a982b7ae26fc43ced61
5
+ SHA512:
6
+ metadata.gz: d0f68d527c8ae07b07a1fb7b6e3f2874343f3b62f4f340383a2dd90c354914d13a821ce2898c6cc364cf8b3b7b4e805b208104465198498cb5e3ee97b750ef6c
7
+ data.tar.gz: 50f0b95641ecf1de92a336f302b6bd33657e7f7f15db17527ef888aaf7fd28f031a8d63ca60bbea01ae37fbf8eb7a3f33c2e1eb319bc454f1ba589fdfbe8a6a1
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2014 Viget
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.md ADDED
@@ -0,0 +1,51 @@
1
+ # Sprig::Reap
2
+
3
+ Automatic capture and output of your application's data state to Sprig-formatted seed files.
4
+
5
+ ## Populate Seed Files from Database
6
+
7
+ Don't want to write Sprig seed files from scratch? Well, Sprig::Reap can create them for you!
8
+
9
+ Via a rake task:
10
+ ```
11
+ rake db:seed:reap
12
+ ```
13
+ Or from the Rails console:
14
+ ```
15
+ Sprig::Reap.reap
16
+ ```
17
+
18
+ By default, Sprig::Reap will create seed files (currently in `.yaml` only) for every model in your Rails
19
+ application. The seed files will be placed in a folder in `db/seeds` named after the current
20
+ `Rails.env`.
21
+
22
+ If any of the models in your application are using STI, Sprig::Reap will create a single seed file named
23
+ after the STI base model. STI sub-type records will all be written to that file.
24
+
25
+ ### Additional Configuration
26
+
27
+ Don't like the defaults when reaping Sprig::Reap records? You may specify the environment (`db/seeds`
28
+ target folder) or models (`ActiveRecord::Base.subclasses`-only) you want seed files for.
29
+
30
+ ```
31
+ # Rake Task
32
+ rake db:seed:reap ENV=integration MODELS=User,Post
33
+
34
+ # Rails Console
35
+ Sprig::Reap.reap(env: 'integration', models: [User, Post])
36
+ ```
37
+
38
+ ### Adding to Existing Seed Files (`.yaml` only)
39
+
40
+ Already have some seed files set up? No worries! Sprig::Reap will detect existing seed files and append
41
+ to them with the records from your database with no extra work needed. Sprig::Reap will automatically
42
+ assign unique `sprig_ids` so you won't have to deal with pesky duplicates.
43
+
44
+ NOTE: Sprig::Reap does not account for your application or database validations. If you reap seed files
45
+ from your database multiple times in a row without deleting the previous seed files or sprig
46
+ records, you'll end up with duplicate sprig records (but they'll all have unique `sprig_ids`). This
47
+ may cause validation issues when you seed your database.
48
+
49
+ ## License
50
+
51
+ This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new(:spec)
4
+
5
+ task :default => :spec
@@ -0,0 +1,61 @@
1
+ module Sprig::Reap
2
+ class Configuration
3
+ VALID_CLASSES = ActiveRecord::Base.subclasses
4
+
5
+ def env
6
+ @env ||= Rails.env
7
+ end
8
+
9
+ def env=(given_env)
10
+ parse_valid_env_from given_env do |environment|
11
+ @env = environment
12
+ end
13
+ end
14
+
15
+ def classes
16
+ @classes ||= VALID_CLASSES
17
+ end
18
+
19
+ def classes=(given_classes)
20
+ parse_valid_classes_from given_classes do |classes|
21
+ @classes = classes
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def parse_valid_env_from(input)
28
+ return if input.nil?
29
+ environment = input.strip.downcase
30
+ create_seeds_folder(environment)
31
+ yield environment
32
+ end
33
+
34
+ def create_seeds_folder(env)
35
+ folder = Rails.root.join('db', 'seeds', env)
36
+ FileUtils.mkdir_p(folder) unless File.directory? folder
37
+ end
38
+
39
+ def parse_valid_classes_from(input)
40
+ return if input.nil?
41
+
42
+ classes = if input.is_a? String
43
+ input.split(',').map { |klass_string| klass_string.strip.classify.constantize }
44
+ else
45
+ input
46
+ end
47
+
48
+ validate_classes(classes)
49
+
50
+ yield classes
51
+ end
52
+
53
+ def validate_classes(classes)
54
+ classes.each do |klass|
55
+ unless VALID_CLASSES.include? klass
56
+ raise ArgumentError, "Cannot create a seed file for #{klass} because it is not a subclass of ActiveRecord::Base."
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,75 @@
1
+ module Sprig::Reap
2
+ class Model
3
+ def self.all
4
+ @@all ||= begin
5
+ models = Sprig::Reap.classes.map { |klass| new(klass) }
6
+
7
+ tsorted_classes(models).map do |klass|
8
+ models.find { |model| model.klass == klass }
9
+ end
10
+ end
11
+ end
12
+
13
+ def self.find(klass, id)
14
+ all.find { |model| model.klass == klass }.find(id)
15
+ end
16
+
17
+ attr_reader :klass
18
+ attr_writer :existing_sprig_ids
19
+
20
+ def initialize(klass)
21
+ @klass = klass
22
+ end
23
+
24
+ def attributes
25
+ klass.column_names
26
+ end
27
+
28
+ def dependencies
29
+ @dependencies ||= klass.reflect_on_all_associations(:belongs_to).map do |association|
30
+ association.name.to_s.classify.constantize
31
+ end
32
+ end
33
+
34
+ def existing_sprig_ids
35
+ @existing_sprig_ids ||= []
36
+ end
37
+
38
+ def generate_sprig_id
39
+ existing_sprig_ids.select { |i| i.is_a? Integer }.sort.last + 1
40
+ end
41
+
42
+ def find(id)
43
+ records.find { |record| record.id == id }
44
+ end
45
+
46
+ def to_s
47
+ klass.to_s
48
+ end
49
+
50
+ def to_yaml(options = {})
51
+ namespace = options[:namespace]
52
+ formatted_records = records.map(&:to_hash)
53
+
54
+ yaml = if namespace
55
+ { namespace => formatted_records }.to_yaml
56
+ else
57
+ formatted_records.to_yaml
58
+ end
59
+
60
+ yaml.gsub("---\n", '') # Remove annoying YAML separator
61
+ end
62
+
63
+ def records
64
+ @records ||= klass.all.map { |record| Record.new(record, self) }
65
+ end
66
+
67
+ private
68
+
69
+ def self.tsorted_classes(models)
70
+ models.reduce(TsortableHash.new) do |hash, model|
71
+ hash.merge(model.klass => model.dependencies)
72
+ end.tsort
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,59 @@
1
+ module Sprig::Reap
2
+ class Record
3
+ attr_reader :record, :model
4
+ attr_writer :sprig_id
5
+
6
+ def initialize(record, model)
7
+ @record = record
8
+ @model = model
9
+ end
10
+
11
+ def attributes
12
+ @attributes ||= Array.new.replace(model.attributes).tap do |attrs|
13
+ attrs[0] = 'sprig_id'
14
+ end
15
+ end
16
+
17
+ def to_hash
18
+ attributes.reduce(Hash.new) { |hash, attr| hash.merge(attr => send(attr)) }
19
+ end
20
+
21
+ def sprig_id
22
+ @sprig_id ||= model.existing_sprig_ids.include?(record.id) ? model.generate_sprig_id : record.id
23
+ end
24
+
25
+ private
26
+
27
+ def method_missing(method, *args, &block)
28
+ attr = model.attributes.find { |attr| attr == method.to_s }
29
+
30
+ if attr.nil?
31
+ super
32
+ elsif dependency_finder.match(attr)
33
+ klass = klass_for(attr)
34
+ id = record.send(attr)
35
+ sprig_id = Model.find(klass, id).sprig_id
36
+
37
+ sprig_record(klass, sprig_id)
38
+ else
39
+ record.send(attr)
40
+ end
41
+ end
42
+
43
+ def respond_to_missing?(method, include_private = false)
44
+ model.attributes.include?(method.to_s) || super
45
+ end
46
+
47
+ def dependency_finder
48
+ /_id/
49
+ end
50
+
51
+ def klass_for(attr)
52
+ attr.gsub(dependency_finder, '').classify.constantize
53
+ end
54
+
55
+ def sprig_record(klass, sprig_id)
56
+ "<%= sprig_record(#{klass}, #{sprig_id}).id %>"
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,52 @@
1
+ module Sprig::Reap
2
+ class SeedFile
3
+ DEFAULT_NAMESPACE = 'records'
4
+
5
+ attr_reader :model
6
+
7
+ def initialize(model)
8
+ raise ArgumentError, 'Must initialize with a Sprig::Reap::Model' unless model.is_a? Model
9
+
10
+ @model = model
11
+ end
12
+
13
+ def path
14
+ Rails.root.join('db', 'seeds', Sprig::Reap.env, "#{model.to_s.tableize.gsub('/', '_')}.yml")
15
+ end
16
+
17
+ def exists?
18
+ File.exists?(path)
19
+ end
20
+
21
+ def write
22
+ initialize_file do |file, namespace|
23
+ file.write model.to_yaml(:namespace => namespace)
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def initialize_file
30
+ existing_file = exists?
31
+ access_type = existing_file ? 'a+' : 'w'
32
+
33
+ File.open(path, access_type) do |file|
34
+ namespace = DEFAULT_NAMESPACE
35
+
36
+ if existing_file
37
+ model.existing_sprig_ids = existing_sprig_ids(file.read)
38
+ namespace = nil
39
+ file.write("\n")
40
+ end
41
+
42
+ yield file, namespace
43
+ end
44
+ end
45
+
46
+ def existing_sprig_ids(yaml)
47
+ YAML.load(yaml).fetch(DEFAULT_NAMESPACE).to_a.map do |record|
48
+ record.fetch('sprig_id')
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,11 @@
1
+ module Sprig::Reap
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
@@ -0,0 +1,5 @@
1
+ module Sprig
2
+ module Reap
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
data/lib/sprig/reap.rb ADDED
@@ -0,0 +1,35 @@
1
+ require "sprig/reap/version"
2
+
3
+ module Sprig::Reap
4
+ autoload :TsortableHash, 'sprig/reap/tsortable_hash'
5
+ autoload :Railtie, 'sprig/reap/railtie'
6
+ autoload :Configuration, 'sprig/reap/configuration'
7
+ autoload :Model, 'sprig/reap/model'
8
+ autoload :Record, 'sprig/reap/record'
9
+ autoload :SeedFile, 'sprig/reap/seed_file'
10
+
11
+ class << self
12
+ def reap(options = {})
13
+ configure do |config|
14
+ config.env = options[:env] || options['ENV']
15
+ config.classes = options[:models] || options['MODELS']
16
+ end
17
+
18
+ Model.all.each { |model| SeedFile.new(model).write }
19
+ end
20
+
21
+ private
22
+
23
+ cattr_reader :configuration
24
+
25
+ delegate :env, :classes, to: :configuration
26
+
27
+ def configuration
28
+ @@configuration ||= Configuration.new
29
+ end
30
+
31
+ def configure
32
+ yield configuration
33
+ end
34
+ end
35
+ 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::Reap.reap(ENV)
7
+ end
8
+ end
9
+ end
Binary file
@@ -0,0 +1,5 @@
1
+ class Comment < ActiveRecord::Base
2
+ belongs_to :post
3
+
4
+ validates :post, :presence => true
5
+ end
@@ -0,0 +1,2 @@
1
+ class Post < ActiveRecord::Base
2
+ end
@@ -0,0 +1,3 @@
1
+ class User < ActiveRecord::Base
2
+ validates :first_name, :last_name, :presence => true
3
+ end
@@ -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::Reap::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::Reap::Model]
68
+ }.to raise_error ArgumentError, 'Cannot create a seed file for Sprig::Reap::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::Reap::Model'
86
+ }.to raise_error ArgumentError, 'Cannot create a seed file for Sprig::Reap::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::Reap::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::Reap.stub(:classes).and_return([Comment, Post, User])
15
+ end
16
+
17
+ it "returns an dependency-sorted array of Sprig::Reap::Models" do
18
+ described_class.all.all? { |model| model.is_a? Sprig::Reap::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::Reap::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::Reap::Record with the given id" do
60
+ reap_record = subject.find(2)
61
+ reap_record.should be_an_instance_of Sprig::Reap::Record
62
+ reap_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::Reap::Record do
6
+ let(:record) { double('ActiveRecord::Base Instance') }
7
+ let(:model) { double('Sprig::Reap::Model') }
8
+ let(:reap_record) { double('Sprig::Reap::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::Reap::Model.stub(:find).and_return(reap_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::Reap::SeedFile do
4
+ let(:model) { Sprig::Reap::Model.new(Comment) }
5
+
6
+ subject { described_class.new(model) }
7
+
8
+ before do
9
+ stub_rails_root
10
+ Sprig::Reap.stub(:env).and_return('dreamland')
11
+ end
12
+
13
+ describe "#initialize" do
14
+ context "given a non-Sprig::Reap::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::Reap::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::Reap do
4
+ describe ".reap" do
5
+ let(:seed_file) { double('Sprig::Reap::SeedFile', :write => 'such seeds') }
6
+
7
+ before do
8
+ stub_rails_root
9
+ stub_rails_env
10
+ Sprig::Reap::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 => 'dreamland')
27
+ subject.env.should == 'dreamland'
28
+ end
29
+ end
30
+
31
+ context "in 'ENV'" do
32
+ it "sets the environment" do
33
+ subject.reap('ENV' => ' Dreamland')
34
+ subject.env.should == 'dreamland'
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,46 @@
1
+ ENV["RAILS_ENV"] ||= 'test'
2
+
3
+ require "rails"
4
+ require "active_record"
5
+ require "database_cleaner"
6
+ require "pry"
7
+ require "generator_spec"
8
+
9
+ require "sprig/reap"
10
+
11
+ %w(
12
+ /fixtures/models/*rb
13
+ /support/**/*.rb
14
+ ).each do |file_set|
15
+ Dir[File.dirname(__FILE__) + file_set].each { |file| require file }
16
+ end
17
+
18
+ RSpec.configure do |config|
19
+ config.include RailsStubs
20
+ config.include FileSetup
21
+
22
+ config.before(:suite) do
23
+ DatabaseCleaner.strategy = :transaction
24
+ DatabaseCleaner.clean_with(:truncation)
25
+ end
26
+
27
+ config.before(:each) do
28
+ DatabaseCleaner.start
29
+ end
30
+
31
+ config.after(:each) do
32
+ DatabaseCleaner.clean
33
+ end
34
+ end
35
+
36
+ # Database
37
+ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => "spec/db/activerecord.db")
38
+
39
+ User.connection.execute "DROP TABLE IF EXISTS users;"
40
+ User.connection.execute "CREATE TABLE users (id INTEGER PRIMARY KEY , first_name VARCHAR(255), last_name VARCHAR(255), type VARCHAR(255));"
41
+
42
+ Post.connection.execute "DROP TABLE IF EXISTS posts;"
43
+ Post.connection.execute "CREATE TABLE posts (id INTEGER PRIMARY KEY , title VARCHAR(255), content VARCHAR(255), published BOOLEAN , user_id INTEGER);"
44
+
45
+ Comment.connection.execute "DROP TABLE IF EXISTS comments;"
46
+ Comment.connection.execute "CREATE TABLE comments (id INTEGER PRIMARY KEY , post_id INTEGER, body VARCHAR(255));"
@@ -0,0 +1,10 @@
1
+ module FileSetup
2
+ # Create and remove seed folder around a spec
3
+ def setup_seed_folder(path)
4
+ FileUtils.mkdir_p(path)
5
+
6
+ yield
7
+
8
+ FileUtils.remove_dir(path)
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module RailsStubs
2
+ # Setup fake `Rails.root`
3
+ def stub_rails_root(path='./spec/fixtures')
4
+ Rails.stub(:root).and_return(Pathname.new(path))
5
+ end
6
+
7
+ # Setup fake `Rails.env`
8
+ def stub_rails_env(env='development')
9
+ Rails.stub(:env).and_return(env)
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sprig-reap
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Stenberg
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '3.1'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '3.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sqlite3
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.3.8
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 1.3.8
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 2.14.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 2.14.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: database_cleaner
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 1.2.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: 1.2.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: generator_spec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Sprig-Reap is a gem that allows you to output your application's data
98
+ state to seed files.
99
+ email:
100
+ - ryan.stenberg@viget.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - lib/sprig/reap/configuration.rb
106
+ - lib/sprig/reap/model.rb
107
+ - lib/sprig/reap/record.rb
108
+ - lib/sprig/reap/seed_file.rb
109
+ - lib/sprig/reap/tsortable_hash.rb
110
+ - lib/sprig/reap/version.rb
111
+ - lib/sprig/reap.rb
112
+ - lib/tasks/reap.rake
113
+ - MIT-LICENSE
114
+ - Rakefile
115
+ - README.md
116
+ - spec/db/activerecord.db
117
+ - spec/fixtures/models/comment.rb
118
+ - spec/fixtures/models/post.rb
119
+ - spec/fixtures/models/user.rb
120
+ - spec/fixtures/yaml/comment_seeds.yml
121
+ - spec/fixtures/yaml/post_seeds.yml
122
+ - spec/fixtures/yaml/records_with_namespace.yml
123
+ - spec/fixtures/yaml/records_without_namespace.yml
124
+ - spec/fixtures/yaml/user_seeds.yml
125
+ - spec/lib/sprig/reap/configuration_spec.rb
126
+ - spec/lib/sprig/reap/model_spec.rb
127
+ - spec/lib/sprig/reap/record_spec.rb
128
+ - spec/lib/sprig/reap/seed_file_spec.rb
129
+ - spec/lib/sprig/reap_spec.rb
130
+ - spec/spec_helper.rb
131
+ - spec/support/file_setup.rb
132
+ - spec/support/rails_stubs.rb
133
+ homepage: http://www.github.com/vigetlabs/sprig-reap
134
+ licenses:
135
+ - MIT
136
+ metadata: {}
137
+ post_install_message:
138
+ rdoc_options: []
139
+ require_paths:
140
+ - lib
141
+ required_ruby_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - '>='
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ requirements: []
152
+ rubyforge_project:
153
+ rubygems_version: 2.0.3
154
+ signing_key:
155
+ specification_version: 4
156
+ summary: Automatic seed file generation for Rails apps using Sprig.
157
+ test_files:
158
+ - spec/db/activerecord.db
159
+ - spec/fixtures/models/comment.rb
160
+ - spec/fixtures/models/post.rb
161
+ - spec/fixtures/models/user.rb
162
+ - spec/fixtures/yaml/comment_seeds.yml
163
+ - spec/fixtures/yaml/post_seeds.yml
164
+ - spec/fixtures/yaml/records_with_namespace.yml
165
+ - spec/fixtures/yaml/records_without_namespace.yml
166
+ - spec/fixtures/yaml/user_seeds.yml
167
+ - spec/lib/sprig/reap/configuration_spec.rb
168
+ - spec/lib/sprig/reap/model_spec.rb
169
+ - spec/lib/sprig/reap/record_spec.rb
170
+ - spec/lib/sprig/reap/seed_file_spec.rb
171
+ - spec/lib/sprig/reap_spec.rb
172
+ - spec/spec_helper.rb
173
+ - spec/support/file_setup.rb
174
+ - spec/support/rails_stubs.rb