seedomatic 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in seedomatic.gemspec
4
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,47 @@
1
+
2
+
3
+ module SeedOMatic
4
+ module Runner
5
+ extend self
6
+
7
+ def run (opts = {})
8
+ results = {}
9
+
10
+ files_to_import(opts).each do |file|
11
+ file_info = load_file(file)
12
+
13
+ if should_import?(opts, file_info)
14
+ results[file_info[:model_name]] = Seeder.new(file_info).import
15
+ end
16
+ end
17
+
18
+ results
19
+ end
20
+
21
+ protected
22
+
23
+ def should_import?(import_options, file_info)
24
+ (!import_options[:tagged_with] || ([*import_options[:tagged_with]] - [*file_info[:tags]]).empty?) &&
25
+ (!import_options[:not_tagged_with] || ([*import_options[:not_tagged_with]] & [*file_info[:tags]]).empty?)
26
+ end
27
+
28
+ def files_to_import(options)
29
+ if options[:file]
30
+ [options[:file]]
31
+ else
32
+ dir = options[:dir] || "config/seeds"
33
+ Dir.open(dir).map{|f| "#{dir}/#{f}"}.select{|file| File.file? file}
34
+ end
35
+ end
36
+
37
+ def load_file(file)
38
+ data = YAML.load_file(file)
39
+ {
40
+ :model_name => data.keys.first,
41
+ :match_on => data.first[1]['match_on'],
42
+ :items => data.first[1]['items']
43
+ }
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,48 @@
1
+ module SeedOMatic
2
+ class Seeder
3
+
4
+ attr_accessor :model_name, :items, :match_on
5
+
6
+ def initialize(data)
7
+ @model_name = data[:model_name]
8
+ @items = data[:items]
9
+ @match_on = [*data[:match_on]]
10
+ end
11
+
12
+ def import
13
+ new_records = 0
14
+ updated_records = 0
15
+
16
+ items.each do |i|
17
+ model = model_class.send(create_method, *create_args(i))
18
+
19
+ if model.new_record?
20
+ new_records += 1
21
+ else
22
+ updated_records += 1
23
+ end
24
+
25
+ model.attributes = i
26
+ model.save!
27
+ end
28
+
29
+ { :count => items.length, :new => new_records, :updated => updated_records}
30
+ end
31
+
32
+ protected
33
+
34
+ def create_method
35
+ match_on.empty? ? 'new' : "find_or_initialize_by_#{match_on.join('_and_')}"
36
+ end
37
+
38
+ def create_args(item)
39
+ match_on.map{|m| item[m] }
40
+ end
41
+
42
+ def model_class
43
+ return model_name if model_name.is_a? Class
44
+ model_name.to_s.classify.constantize
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ module Seedomatic
2
+ VERSION = "0.1.0"
3
+ end
data/lib/seedomatic.rb ADDED
@@ -0,0 +1,11 @@
1
+ require "seedomatic/version"
2
+
3
+ require 'yaml'
4
+ require 'active_support/core_ext'
5
+
6
+ module SeedOMatic
7
+ autoload :Seeder, 'seedomatic/seeder'
8
+ autoload :Runner, 'seedomatic/runner'
9
+
10
+ extend Runner
11
+ end
data/readme.markdown ADDED
@@ -0,0 +1,2 @@
1
+ # Seed-O-Matic
2
+ *Run repeatable seeds across a variety of environments*
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "seedomatic/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "seedomatic"
7
+ s.version = Seedomatic::VERSION
8
+ s.authors = ["Ryan Brunner"]
9
+ s.email = ["ryan@ryanbrunner.com"]
10
+ s.homepage = "http://github.com/ryanbrunner/seedomatic"
11
+ s.summary = %q{Seed-O-Matic makes seeding easier.}
12
+ s.description = %q{Create repeatable seed fixtures that you can continually use and deploy to multiple environments and tenants.}
13
+
14
+ s.rubyforge_project = "seedomatic"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ s.add_development_dependency "rspec", '~> 2.9.0'
23
+ s.add_runtime_dependency "active_support"
24
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ describe SeedOMatic do
4
+ let!(:mock_seeder) { mock(SeedOMatic::Seeder).as_null_object }
5
+
6
+ describe "run" do
7
+ subject { described_class.run opts }
8
+
9
+ context "specified file" do
10
+ let(:opts) { { :file => 'spec/support/single_model.yml' } }
11
+
12
+ specify {
13
+ SeedOMatic::Seeder.should_receive(:new).with(hash_including(:model_name => 'model_name',
14
+ :items => ['name' => 'Name 1', 'code' => 'code_1'])).and_return(mock_seeder)
15
+ subject
16
+ }
17
+ end
18
+
19
+ context "specified directory" do
20
+ let(:opts) { { :dir => 'spec/support/seed_directory' } }
21
+
22
+ specify {
23
+ SeedOMatic::Seeder.should_receive(:new).with(hash_including(:model_name => 'dir1')).and_return(mock_seeder)
24
+ SeedOMatic::Seeder.should_receive(:new).with(hash_including(:model_name => 'dir2')).and_return(mock_seeder)
25
+
26
+ subject
27
+ }
28
+ end
29
+
30
+ context "no options (assumed config / seeds directory)" do
31
+
32
+ end
33
+ end
34
+
35
+ describe "should_import?" do
36
+ subject { SeedOMatic.send(:should_import?, run_options, file_info)}
37
+
38
+ describe "tagged_with" do
39
+ let(:run_options) { { :tagged_with => 'tag1'}}
40
+
41
+ context "tag exists" do
42
+ let(:file_info) { {:tags => ['tag1', 'tag2']}}
43
+ it { should be_true }
44
+ end
45
+ context "tag does not exist" do
46
+ let(:file_info) { {:tags => ['tag3', 'tag2']}}
47
+ it { should be_false }
48
+ end
49
+ context "multiple tags" do
50
+ let(:run_options) { { :tagged_with => ['tag1', 'tag2'] }}
51
+ context "all match" do
52
+ let(:file_info) { {:tags => ['tag1', 'tag2', 'tag3']}}
53
+ it { should be_true }
54
+ end
55
+ context "some match" do
56
+ let(:file_info) { {:tags => ['tag4', 'tag2', 'tag3']}}
57
+ it { should be_false}
58
+ end
59
+ end
60
+ end
61
+ describe "not_tagged_with" do
62
+ let(:run_options) { { :not_tagged_with => 'tag1'}}
63
+ context "tag exists" do
64
+ let(:file_info) { {:tags => ['tag1', 'tag2']}}
65
+ it { should be_false }
66
+ end
67
+ context "tag does not exist" do
68
+ let(:file_info) { {:tags => ['tag3']}}
69
+ it { should be_true }
70
+ end
71
+ context "no tags" do
72
+ let(:file_info) { {:tags => []}}
73
+ it { should be_true }
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,120 @@
1
+ require 'spec_helper'
2
+
3
+ describe SeedOMatic::Seeder do
4
+ let!(:mock_model) { mock(MyModel).as_null_object }
5
+
6
+ let(:seeder) { described_class.new(data) }
7
+ let(:data) { { :model_name => model_name, :items => items, :match_on => match_on } }
8
+ let(:model_name) { "MyModel" }
9
+ let(:items) {
10
+ [{'name' => 'foo', 'code' => 'uniquecode', 'code_category' => 'more_unique'} ]
11
+ }
12
+ let(:match_on) { nil }
13
+
14
+ describe "import" do
15
+ subject { seeder.import }
16
+
17
+ describe "creating records" do
18
+ context "single item" do
19
+ let(:items) { [{'name' => 'foo'}] }
20
+ specify {
21
+ MyModel.should_receive(:new).and_return(mock_model)
22
+ subject
23
+ }
24
+ end
25
+
26
+ context "multiple items" do
27
+ let(:items) { [{'name' => 'foo'}, {'name' => 'bar'} ] }
28
+ specify {
29
+ MyModel.should_receive(:new).twice.and_return(mock_model)
30
+ subject
31
+ }
32
+ it "should set fields properly" do
33
+ subject
34
+ MyModel[0].name.should == 'foo'
35
+ MyModel[1].name.should == 'bar'
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "checking uniqueness on a specified field" do
41
+ context "single field" do
42
+ let(:match_on) { 'code' }
43
+
44
+ specify {
45
+ MyModel.should_receive(:find_or_initialize_by_code).with('uniquecode').and_return(MyModel.new)
46
+ subject
47
+ }
48
+ end
49
+ context "multiple fields" do
50
+ let(:match_on) { ['code', 'code_category'] }
51
+
52
+ specify {
53
+ MyModel.should_receive(:find_or_initialize_by_code_and_code_category).with('uniquecode', 'more_unique').and_return(MyModel.new)
54
+ subject
55
+ }
56
+ end
57
+ end
58
+ end
59
+
60
+ describe "create_method" do
61
+ subject { seeder.send(:create_method) }
62
+
63
+ context "no matching fields" do
64
+ let(:match_on) { nil }
65
+ it { should == 'new' }
66
+ end
67
+
68
+ context "one matching field" do
69
+ let(:match_on) { 'code' }
70
+ it { should == 'find_or_initialize_by_code' }
71
+ end
72
+
73
+ context "multiple matching fields" do
74
+ let(:match_on) { ['code', 'code_category'] }
75
+ it { should == 'find_or_initialize_by_code_and_code_category' }
76
+ end
77
+ end
78
+
79
+ describe "create_args" do
80
+ subject { seeder.send(:create_args, {'code' => 1, 'code_category' => 2}) }
81
+
82
+ context "no matching fields" do
83
+ let(:match_on) { nil }
84
+ it { should == [] }
85
+ end
86
+
87
+ context "one matching field" do
88
+ let(:match_on) { 'code' }
89
+ it { should == [1] }
90
+ end
91
+
92
+ context "multiple matching fields" do
93
+ let(:match_on) { ['code', 'code_category'] }
94
+ it { should == [1,2] }
95
+ end
96
+
97
+ context "order sensitivity" do
98
+ let(:match_on) { ['code_category', 'code'] }
99
+ it { should == [2,1] }
100
+ end
101
+ end
102
+
103
+ describe "model class" do
104
+ subject { seeder.send(:model_class) }
105
+
106
+ ["MyModel", MyModel, :my_model, 'my_model'].each do |name|
107
+ describe name do
108
+ let(:model_name) { name }
109
+ it { should == MyModel }
110
+ end
111
+ end
112
+
113
+ ["Blah", "blah", :not_a_model].each do |name|
114
+ describe name do
115
+ let(:model_name) { name }
116
+ specify { expect { subject }.to raise_error }
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,3 @@
1
+ require 'seedomatic'
2
+
3
+ require 'support/my_model.rb'
@@ -0,0 +1,39 @@
1
+ class MyModel
2
+ attr_accessor :name, :new_record
3
+
4
+ @@models = []
5
+
6
+ def initialize(params = {})
7
+ self.name = params['name']
8
+ self.new_record = true
9
+ end
10
+
11
+ def self.create(params = {})
12
+ @@models << m = new(params)
13
+ m.new_record = false
14
+ m
15
+ end
16
+
17
+ def attributes=(attr)
18
+ self.name = attr['name']
19
+ end
20
+
21
+ def save!
22
+ @@models << self
23
+ new_record = false
24
+ self
25
+ end
26
+
27
+ def new_record?
28
+ @new_record
29
+ end
30
+
31
+ def self.[] (index)
32
+ @@models[index]
33
+ end
34
+
35
+ def self.models
36
+ @@models
37
+ end
38
+
39
+ end
@@ -0,0 +1,4 @@
1
+ dir1:
2
+ items:
3
+ - name: Name 1
4
+ code: code_1
@@ -0,0 +1,4 @@
1
+ dir2:
2
+ items:
3
+ - name: Name 1
4
+ code: code_1
@@ -0,0 +1,4 @@
1
+ model_name:
2
+ items:
3
+ - name: Name 1
4
+ code: code_1
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: seedomatic
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Ryan Brunner
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-23 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &70246141530860 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.9.0
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70246141530860
25
+ - !ruby/object:Gem::Dependency
26
+ name: active_support
27
+ requirement: &70246141530440 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70246141530440
36
+ description: Create repeatable seed fixtures that you can continually use and deploy
37
+ to multiple environments and tenants.
38
+ email:
39
+ - ryan@ryanbrunner.com
40
+ executables: []
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - .gitignore
45
+ - .rspec
46
+ - Gemfile
47
+ - Rakefile
48
+ - lib/seedomatic.rb
49
+ - lib/seedomatic/runner.rb
50
+ - lib/seedomatic/seeder.rb
51
+ - lib/seedomatic/version.rb
52
+ - readme.markdown
53
+ - seedomatic.gemspec
54
+ - spec/lib/seed_o_matic_spec.rb
55
+ - spec/lib/seeder_spec.rb
56
+ - spec/spec_helper.rb
57
+ - spec/support/my_model.rb
58
+ - spec/support/seed_directory/dir1.yml
59
+ - spec/support/seed_directory/dir2.yml
60
+ - spec/support/single_model.yml
61
+ homepage: http://github.com/ryanbrunner/seedomatic
62
+ licenses: []
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project: seedomatic
81
+ rubygems_version: 1.8.15
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: Seed-O-Matic makes seeding easier.
85
+ test_files:
86
+ - spec/lib/seed_o_matic_spec.rb
87
+ - spec/lib/seeder_spec.rb
88
+ - spec/spec_helper.rb
89
+ - spec/support/my_model.rb
90
+ - spec/support/seed_directory/dir1.yml
91
+ - spec/support/seed_directory/dir2.yml
92
+ - spec/support/single_model.yml