sprig-reap 0.0.1

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