seedomatic 0.1.0

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