also_migrate_nj 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ .DS_Store
2
+ *.gem
3
+ coverage
4
+ pkg
5
+ spec/config/database.yml
6
+ spec/log
7
+ tmp
data/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2010
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,50 @@
1
+ AlsoMigrate
2
+ ===========
3
+
4
+ Migrate multiple tables with similar schema at once.
5
+
6
+ Requirements
7
+ ------------
8
+
9
+ <pre>
10
+ gem install also_migrate
11
+ </pre>
12
+
13
+ Configure
14
+ ---------
15
+
16
+ <pre>
17
+ AlsoMigrate.configuration = [
18
+ {
19
+ :source => 'articles',
20
+ :destination => 'article_archives',
21
+ :add => [
22
+ # Parameters to ActiveRecord::ConnectionAdapters::SchemaStatements#add_column
23
+ [ 'deleted_at', :datetime, {} ]
24
+ ],
25
+ :subtract => 'restored_at',
26
+ :ignore => 'deleted_at',
27
+ :indexes => 'id'
28
+ },
29
+ {
30
+ :source => 'users',
31
+ :destination => [ 'banned_users', 'deleted_users' ]
32
+ }
33
+ ]
34
+ </pre>
35
+
36
+ Options:
37
+
38
+ * <code>source</code> Database schema source table
39
+ * <code>destination</code> Database schema destination table (can also be an array of tables)
40
+ * <code>add</code> Create columns that the original table doesn't have (defaults to none)
41
+ * <code>subtract</code> Exclude columns from the original table (defaults to none)
42
+ * <code>ignore</code> Ignore migrations that apply to certain columns (defaults to none)
43
+ * <code>indexes</code> Only index certain columns (duplicates all indexes by default)
44
+
45
+ That's it!
46
+ ----------
47
+
48
+ Next time you migrate, <code>article_archives</code> is created if it doesn't exist.
49
+
50
+ Any new migration applied to <code>articles</code> is automatically applied to <code>article_archives</code>.
@@ -0,0 +1,90 @@
1
+ require File.dirname(__FILE__) + '/lib/also_migrate/gems'
2
+
3
+ AlsoMigrate::Gems.activate %w(rake rspec)
4
+
5
+ require 'rake'
6
+ require 'spec/rake/spectask'
7
+
8
+ def gemspec
9
+ @gemspec ||= begin
10
+ file = File.expand_path('../also_migrate.gemspec', __FILE__)
11
+ eval(File.read(file), binding, file)
12
+ end
13
+ end
14
+
15
+ if defined?(Spec::Rake::SpecTask)
16
+ desc "Run specs"
17
+ Spec::Rake::SpecTask.new do |t|
18
+ t.spec_files = FileList['spec/**/*_spec.rb']
19
+ t.spec_opts = %w(-fs --color)
20
+ t.warning = true
21
+ end
22
+ task :spec
23
+ task :default => :spec
24
+ end
25
+
26
+ desc "Build gem(s)"
27
+ task :gem do
28
+ old_gemset = ENV['GEMSET']
29
+ root = File.expand_path('../', __FILE__)
30
+ pkg = "#{root}/pkg"
31
+ system "rm -Rf #{pkg}"
32
+ AlsoMigrate::Gems.gemset_names.each do |gemset|
33
+ ENV['GEMSET'] = gemset.to_s
34
+ system "cd #{root} && gem build also_migrate.gemspec"
35
+ system "mkdir -p #{pkg} && mv *.gem pkg"
36
+ end
37
+ ENV['GEMSET'] = old_gemset
38
+ end
39
+
40
+ namespace :gem do
41
+ desc "Install gem(s)"
42
+ task :install do
43
+ Rake::Task['gem'].invoke
44
+ Dir["#{File.dirname(__FILE__)}/pkg/*.gem"].each do |pkg|
45
+ system "gem install #{pkg} --no-ri --no-rdoc"
46
+ end
47
+ end
48
+
49
+ desc "Push gem(s)"
50
+ task :push do
51
+ Rake::Task['gem'].invoke
52
+ Dir["#{File.dirname(__FILE__)}/pkg/*.gem"].each do |pkg|
53
+ system "gem push #{pkg}"
54
+ end
55
+ end
56
+ end
57
+
58
+ namespace :gems do
59
+ desc "Install gem dependencies (DEV=0 DOCS=0 GEMSPEC=default SUDO=0)"
60
+ task :install do
61
+ dev = ENV['DEV'] == '1'
62
+ docs = ENV['DOCS'] == '1' ? '' : '--no-ri --no-rdoc'
63
+ gemset = ENV['GEMSET']
64
+ sudo = ENV['SUDO'] == '1' ? 'sudo' : ''
65
+
66
+ AlsoMigrate::Gems.gemset = gemset if gemset
67
+
68
+ if dev
69
+ gems = AlsoMigrate::Gems.gemspec.development_dependencies
70
+ else
71
+ gems = AlsoMigrate::Gems.gemspec.dependencies
72
+ end
73
+
74
+ gems.each do |name|
75
+ name = name.to_s
76
+ version = AlsoMigrate::Gems.versions[name]
77
+ if Gem.source_index.find_name(name, version).empty?
78
+ version = version ? "-v #{version}" : ''
79
+ system "#{sudo} gem install #{name} #{version} #{docs}"
80
+ else
81
+ puts "already installed: #{name} #{version}"
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ desc "Validate the gemspec"
88
+ task :gemspec do
89
+ gemspec.validate
90
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+ root = File.expand_path('../', __FILE__)
3
+ lib = "#{root}/lib"
4
+ $:.unshift lib unless $:.include?(lib)
5
+
6
+ require 'also_migrate/gems'
7
+ AlsoMigrate::Gems.gemset ||= ENV['GEMSET'] || :default
8
+
9
+ Gem::Specification.new do |s|
10
+ AlsoMigrate::Gems.gemspec.hash.each do |key, value|
11
+ if key == 'name' && AlsoMigrate::Gems.gemset != :default
12
+ s.name = "#{value}-#{AlsoMigrate::Gems.gemset}"
13
+ elsif key == 'summary' && AlsoMigrate::Gems.gemset == :solo
14
+ s.summary = value + " (no dependencies)"
15
+ elsif !%w(dependencies development_dependencies).include?(key)
16
+ s.send "#{key}=", value
17
+ end
18
+ end
19
+
20
+ AlsoMigrate::Gems.dependencies.each do |g|
21
+ s.add_dependency g.to_s, AlsoMigrate::Gems.versions[g]
22
+ end
23
+
24
+ AlsoMigrate::Gems.development_dependencies.each do |g|
25
+ s.add_development_dependency g.to_s, AlsoMigrate::Gems.versions[g]
26
+ end
27
+
28
+ s.executables = `cd #{root} && git ls-files -- {bin}/*`.split("\n").collect { |f| File.basename(f) }
29
+ s.files = `cd #{root} && git ls-files`.split("\n")
30
+ s.require_paths = %w(lib)
31
+ s.test_files = `cd #{root} && git ls-files -- {features,test,spec}/*`.split("\n")
32
+ end
@@ -0,0 +1,4 @@
1
+ also_migrate:
2
+ active_wrapper: "=0.4.4"
3
+ rake: ">=0.8.7"
4
+ rspec: "~>1.0"
@@ -0,0 +1,12 @@
1
+ name: also_migrate_nj
2
+ version: 0.3.6
3
+ authors:
4
+ - Winton Welsh
5
+ email: james@njtechnologies.co.uk
6
+ homepage: https://github.com/jamesharker/also_migrate
7
+ summary: Migrate multiple tables with similar schema at once.
8
+ description: Migrate multiple tables with similar schema at once.
9
+ dependencies: null
10
+ development_dependencies:
11
+ - rake
12
+ - rspec
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/rails/init"
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/also_migrate/gems'
2
+
3
+ $:.unshift File.dirname(__FILE__)
4
+
5
+ require 'also_migrate/migration'
6
+ require 'also_migrate/migrator'
7
+
8
+ module AlsoMigrate
9
+ class <<self
10
+ attr_accessor :configuration
11
+ end
12
+ end
13
+
14
+ ActiveRecord::Migrator.send(:include, AlsoMigrate::Migrator)
15
+ ActiveRecord::Migration.send(:include, AlsoMigrate::Migration)
@@ -0,0 +1,154 @@
1
+ unless defined?(AlsoMigrate::Gems)
2
+
3
+ require 'yaml'
4
+
5
+ module AlsoMigrate
6
+ module Gems
7
+ class <<self
8
+
9
+ attr_accessor :config
10
+ attr_reader :gemset, :gemsets, :versions
11
+
12
+ class SimpleStruct
13
+ attr_reader :hash
14
+
15
+ def initialize(hash)
16
+ @hash = hash
17
+ @hash.each do |key, value|
18
+ self.class.send(:define_method, key) { @hash[key] }
19
+ self.class.send(:define_method, "#{key}=") { |v| @hash[key] = v }
20
+ end
21
+ end
22
+ end
23
+
24
+ Gems.config = SimpleStruct.new(
25
+ :gemsets => [ "#{File.expand_path('../../../', __FILE__)}/config/gemsets.yml" ],
26
+ :gemspec => "#{File.expand_path('../../../', __FILE__)}/config/gemspec.yml",
27
+ :warn => true
28
+ )
29
+
30
+ def activate(*gems)
31
+ begin
32
+ require 'rubygems' unless defined?(::Gem)
33
+ rescue LoadError
34
+ puts "rubygems library could not be required" if @config.warn
35
+ end
36
+
37
+ self.gemset ||= gemset_from_loaded_specs
38
+
39
+ gems.flatten.collect(&:to_sym).each do |name|
40
+ version = @versions[name]
41
+ vendor = File.expand_path("../../../vendor/#{name}/lib", __FILE__)
42
+ if File.exists?(vendor)
43
+ $:.unshift vendor
44
+ elsif defined?(gem)
45
+ gem name.to_s, version
46
+ else
47
+ puts "#{name} #{"(#{version})" if version} failed to activate" if @config.warn
48
+ end
49
+ end
50
+ end
51
+
52
+ def dependencies
53
+ dependency_filter(@gemspec.dependencies, @gemset)
54
+ end
55
+
56
+ def development_dependencies
57
+ dependency_filter(@gemspec.development_dependencies, @gemset)
58
+ end
59
+
60
+ def gemset=(gemset)
61
+ if gemset
62
+ @gemset = gemset.to_sym
63
+
64
+ @gemsets = @config.gemsets.reverse.collect { |config|
65
+ if config.is_a?(::String)
66
+ YAML::load(File.read(config)) rescue {}
67
+ elsif config.is_a?(::Hash)
68
+ config
69
+ end
70
+ }.inject({}) do |hash, config|
71
+ deep_merge(hash, symbolize_keys(config))
72
+ end
73
+
74
+ @versions = (@gemsets[gemspec.name.to_sym] || {}).inject({}) do |hash, (key, value)|
75
+ if !value.is_a?(::Hash) && value
76
+ hash[key] = value
77
+ elsif key == @gemset
78
+ (value || {}).each { |k, v| hash[k] = v }
79
+ end
80
+ hash
81
+ end
82
+ else
83
+ @gemset = nil
84
+ @gemsets = nil
85
+ @versions = nil
86
+ end
87
+ end
88
+
89
+ def gemset_names
90
+ (
91
+ [ :default ] +
92
+ @gemsets[gemspec.name.to_sym].inject([]) { |array, (key, value)|
93
+ array.push(key) if value.is_a?(::Hash) || value.nil?
94
+ array
95
+ }
96
+ ).uniq
97
+ end
98
+
99
+ def gemspec(reload=false)
100
+ if @gemspec && !reload
101
+ @gemspec
102
+ else
103
+ data = YAML::load(File.read(@config.gemspec)) rescue {}
104
+ @gemspec = SimpleStruct.new(data)
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ def deep_merge(first, second)
111
+ merger = lambda do |key, v1, v2|
112
+ Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2
113
+ end
114
+ first.merge(second, &merger)
115
+ end
116
+
117
+ def dependency_filter(dependencies, match)
118
+ (dependencies || []).inject([]) { |array, value|
119
+ if value.is_a?(::Hash)
120
+ array += value[match.to_s] if value[match.to_s]
121
+ else
122
+ array << value
123
+ end
124
+ array
125
+ }.uniq.collect(&:to_sym)
126
+ end
127
+
128
+ def gemset_from_loaded_specs
129
+ if defined?(Gem)
130
+ Gem.loaded_specs.each do |name, spec|
131
+ if name == gemspec.name
132
+ return :default
133
+ elsif name[0..gemspec.name.length] == "#{gemspec.name}-"
134
+ return name[gemspec.name.length+1..-1].to_sym
135
+ end
136
+ end
137
+ :default
138
+ else
139
+ :none
140
+ end
141
+ end
142
+
143
+ def symbolize_keys(hash)
144
+ return {} unless hash.is_a?(::Hash)
145
+ hash.inject({}) do |options, (key, value)|
146
+ value = symbolize_keys(value) if value.is_a?(::Hash)
147
+ options[(key.to_sym rescue key) || key] = value
148
+ options
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,66 @@
1
+ module AlsoMigrate
2
+ module Migration
3
+
4
+ def self.included(base)
5
+ unless base.respond_to?(:method_missing_with_also_migrate)
6
+ base.extend ClassMethods
7
+ base.class_eval do
8
+ class <<self
9
+ alias_method :method_missing_without_also_migrate, :method_missing
10
+ alias_method :method_missing, :method_missing_with_also_migrate
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+
18
+ def method_missing_with_also_migrate(method, *arguments, &block)
19
+ args = Marshal.load(Marshal.dump(arguments))
20
+ return_value = method_missing_without_also_migrate(method, *arguments, &block)
21
+
22
+ supported = [
23
+ :add_column, :add_index, :add_timestamps, :change_column,
24
+ :change_column_default, :change_table, :create_table,
25
+ :drop_table, :remove_column, :remove_columns,
26
+ :remove_timestamps, :rename_column, :rename_table
27
+ ]
28
+
29
+ if !args.empty? && supported.include?(method)
30
+ connection = ActiveRecord::Base.connection
31
+ table_name = ActiveRecord::Migrator.proper_table_name(args[0])
32
+
33
+ # Find models
34
+ (::AlsoMigrate.configuration || []).each do |config|
35
+ next unless config[:source].to_s == table_name
36
+
37
+ # Don't change ignored columns
38
+ [ config[:ignore] ].flatten.compact.each do |column|
39
+ next if args.include?(column) || args.include?(column.intern)
40
+ end
41
+
42
+ # Run migration
43
+ if method == :create_table
44
+ ActiveRecord::Migrator::AlsoMigrate.create_tables(config)
45
+ elsif method == :add_index && !config[:indexes].nil?
46
+ next
47
+ else
48
+ [ config[:destination] ].flatten.compact.each do |table|
49
+ if connection.table_exists?(table)
50
+ args[0] = table
51
+ begin
52
+ connection.send(method, *args, &block)
53
+ rescue Exception => e
54
+ puts "(also_migrate warning) #{e.message}"
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ return return_value
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,99 @@
1
+ module AlsoMigrate
2
+ module Migrator
3
+
4
+ def self.included(base)
5
+ unless base.included_modules.include?(InstanceMethods)
6
+ base.send :include, InstanceMethods
7
+ base.class_eval do
8
+ alias_method :migrate_without_also_migrate, :migrate
9
+ alias_method :migrate, :migrate_with_also_migrate
10
+ end
11
+ end
12
+ end
13
+
14
+ module InstanceMethods
15
+
16
+ def migrate_with_also_migrate
17
+ (::AlsoMigrate.configuration || []).each do |config|
18
+ AlsoMigrate.create_tables(config)
19
+ end
20
+ rescue Exception => e
21
+ puts "AlsoMigrate error: #{e.message}"
22
+ puts e.backtrace.join("\n")
23
+ ensure
24
+ migrate_without_also_migrate
25
+ end
26
+
27
+ module AlsoMigrate
28
+ class <<self
29
+
30
+ def connection
31
+ ActiveRecord::Base.connection
32
+ end
33
+
34
+ def create_tables(config)
35
+ [ config[:destination] ].flatten.compact.each do |new_table|
36
+ if !connection.table_exists?(new_table) && connection.table_exists?(config[:source])
37
+ columns = connection.columns(config[:source]).collect(&:name)
38
+ columns -= [ config[:subtract] ].flatten.compact.collect(&:to_s)
39
+ columns.collect! { |col| connection.quote_column_name(col) }
40
+ if config[:indexes]
41
+ engine =
42
+ if connection.class.to_s.include?('Mysql')
43
+ 'ENGINE=' + connection.select_one(<<-SQL)['Engine']
44
+ SHOW TABLE STATUS
45
+ WHERE Name = '#{config[:source]}'
46
+ SQL
47
+ end
48
+ connection.execute(<<-SQL)
49
+ CREATE TABLE #{new_table} #{engine}
50
+ AS SELECT #{columns.join(',')}
51
+ FROM #{config[:source]}
52
+ WHERE false;
53
+ SQL
54
+ [ config[:indexes] ].flatten.compact.each do |column|
55
+ connection.add_index(new_table, column)
56
+ end
57
+ else
58
+ if connection.class.to_s.include?('SQLite')
59
+ col_string = connection.columns(config[:source]).collect {|c|
60
+ "#{c.name} #{c.sql_type}"
61
+ }.join(', ')
62
+ connection.execute(<<-SQL)
63
+ CREATE TABLE #{new_table}
64
+ (#{col_string})
65
+ SQL
66
+ else
67
+ connection.execute(<<-SQL)
68
+ CREATE TABLE #{new_table}
69
+ (LIKE) #{config[:source]};
70
+ SQL
71
+ end
72
+ end
73
+ end
74
+ if connection.table_exists?(new_table)
75
+ if config[:add] || config[:subtract]
76
+ columns = connection.columns(new_table).collect(&:name)
77
+ end
78
+ if config[:add]
79
+ config[:add].each do |column|
80
+ unless columns.include?(column[0])
81
+ connection.add_column(*([ new_table ] + column))
82
+ end
83
+ end
84
+ end
85
+ if config[:subtract]
86
+ [ config[:subtract] ].flatten.compact.each do |column|
87
+ if columns.include?(column)
88
+ connection.remove_column(new_table, column)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/also_migrate')
@@ -0,0 +1,13 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/also_migrate/gems')
2
+
3
+ AlsoMigrate::Gems.activate(:active_wrapper)
4
+
5
+ require 'active_wrapper/tasks'
6
+
7
+ #begin
8
+ ActiveWrapper::Tasks.new(
9
+ :base => File.dirname(__FILE__),
10
+ :env => ENV['ENV'] || 'test'
11
+ )
12
+ # rescue Exception
13
+ # end
@@ -0,0 +1,249 @@
1
+ require 'spec_helper'
2
+
3
+ describe AlsoMigrate::Gems do
4
+
5
+ before(:each) do
6
+ @old_config = AlsoMigrate::Gems.config
7
+
8
+ AlsoMigrate::Gems.config.gemspec = "#{$root}/spec/fixtures/gemspec.yml"
9
+ AlsoMigrate::Gems.config.gemsets = [
10
+ "#{$root}/spec/fixtures/gemsets.yml"
11
+ ]
12
+ AlsoMigrate::Gems.config.warn = true
13
+
14
+ AlsoMigrate::Gems.gemspec true
15
+ AlsoMigrate::Gems.gemset = nil
16
+ end
17
+
18
+ after(:each) do
19
+ AlsoMigrate::Gems.config = @old_config
20
+ end
21
+
22
+ describe :activate do
23
+ it "should activate gems" do
24
+ AlsoMigrate::Gems.stub!(:gem)
25
+ AlsoMigrate::Gems.should_receive(:gem).with('rspec', '=1.3.1')
26
+ AlsoMigrate::Gems.should_receive(:gem).with('rake', '=0.8.7')
27
+ AlsoMigrate::Gems.activate :rspec, 'rake'
28
+ end
29
+ end
30
+
31
+ describe :gemset= do
32
+ before(:each) do
33
+ AlsoMigrate::Gems.config.gemsets = [
34
+ {
35
+ :name => {
36
+ :rake => '>0.8.6',
37
+ :default => {
38
+ :externals => '=1.0.2'
39
+ }
40
+ }
41
+ },
42
+ "#{$root}/spec/fixtures/gemsets.yml"
43
+ ]
44
+ end
45
+
46
+ describe :default do
47
+ before(:each) do
48
+ AlsoMigrate::Gems.gemset = :default
49
+ end
50
+
51
+ it "should set @gemset" do
52
+ AlsoMigrate::Gems.gemset.should == :default
53
+ end
54
+
55
+ it "should set @gemsets" do
56
+ AlsoMigrate::Gems.gemsets.should == {
57
+ :name => {
58
+ :rake => ">0.8.6",
59
+ :default => {
60
+ :externals => '=1.0.2',
61
+ :mysql => "=2.8.1",
62
+ :rspec => "=1.3.1"
63
+ },
64
+ :rspec2 => {
65
+ :mysql2 => "=0.2.6",
66
+ :rspec => "=2.3.0"
67
+ },
68
+ :solo => nil
69
+ }
70
+ }
71
+ end
72
+
73
+ it "should set Gems.versions" do
74
+ AlsoMigrate::Gems.versions.should == {
75
+ :externals => "=1.0.2",
76
+ :mysql => "=2.8.1",
77
+ :rake => ">0.8.6",
78
+ :rspec => "=1.3.1"
79
+ }
80
+ end
81
+
82
+ it "should return proper values for Gems.dependencies" do
83
+ AlsoMigrate::Gems.dependencies.should == [ :rake, :mysql ]
84
+ AlsoMigrate::Gems.development_dependencies.should == []
85
+ end
86
+
87
+ it "should return proper values for Gems.gemset_names" do
88
+ AlsoMigrate::Gems.gemset_names.should == [ :default, :rspec2, :solo ]
89
+ end
90
+ end
91
+
92
+ describe :rspec2 do
93
+ before(:each) do
94
+ AlsoMigrate::Gems.gemset = "rspec2"
95
+ end
96
+
97
+ it "should set @gemset" do
98
+ AlsoMigrate::Gems.gemset.should == :rspec2
99
+ end
100
+
101
+ it "should set @gemsets" do
102
+ AlsoMigrate::Gems.gemsets.should == {
103
+ :name => {
104
+ :rake => ">0.8.6",
105
+ :default => {
106
+ :externals => '=1.0.2',
107
+ :mysql => "=2.8.1",
108
+ :rspec => "=1.3.1"
109
+ },
110
+ :rspec2 => {
111
+ :mysql2=>"=0.2.6",
112
+ :rspec => "=2.3.0"
113
+ },
114
+ :solo => nil
115
+ }
116
+ }
117
+ end
118
+
119
+ it "should set Gems.versions" do
120
+ AlsoMigrate::Gems.versions.should == {
121
+ :mysql2 => "=0.2.6",
122
+ :rake => ">0.8.6",
123
+ :rspec => "=2.3.0"
124
+ }
125
+ end
126
+
127
+ it "should return proper values for Gems.dependencies" do
128
+ AlsoMigrate::Gems.dependencies.should == [ :rake, :mysql2 ]
129
+ AlsoMigrate::Gems.development_dependencies.should == []
130
+ end
131
+
132
+ it "should return proper values for Gems.gemset_names" do
133
+ AlsoMigrate::Gems.gemset_names.should == [ :default, :rspec2, :solo ]
134
+ end
135
+ end
136
+
137
+ describe :solo do
138
+ before(:each) do
139
+ AlsoMigrate::Gems.gemset = :solo
140
+ end
141
+
142
+ it "should set @gemset" do
143
+ AlsoMigrate::Gems.gemset.should == :solo
144
+ end
145
+
146
+ it "should set @gemsets" do
147
+ AlsoMigrate::Gems.gemsets.should == {
148
+ :name => {
149
+ :rake => ">0.8.6",
150
+ :default => {
151
+ :externals => '=1.0.2',
152
+ :mysql => "=2.8.1",
153
+ :rspec => "=1.3.1"
154
+ },
155
+ :rspec2 => {
156
+ :mysql2=>"=0.2.6",
157
+ :rspec => "=2.3.0"
158
+ },
159
+ :solo => nil
160
+ }
161
+ }
162
+ end
163
+
164
+ it "should set Gems.versions" do
165
+ AlsoMigrate::Gems.versions.should == {:rake=>">0.8.6"}
166
+ end
167
+
168
+ it "should return proper values for Gems.dependencies" do
169
+ AlsoMigrate::Gems.dependencies.should == [:rake]
170
+ AlsoMigrate::Gems.development_dependencies.should == []
171
+ end
172
+
173
+ it "should return proper values for Gems.gemset_names" do
174
+ AlsoMigrate::Gems.gemset_names.should == [ :default, :rspec2, :solo ]
175
+ end
176
+ end
177
+
178
+ describe :nil do
179
+ before(:each) do
180
+ AlsoMigrate::Gems.gemset = nil
181
+ end
182
+
183
+ it "should set everything to nil" do
184
+ AlsoMigrate::Gems.gemset.should == nil
185
+ AlsoMigrate::Gems.gemsets.should == nil
186
+ AlsoMigrate::Gems.versions.should == nil
187
+ end
188
+ end
189
+ end
190
+
191
+ describe :gemset_from_loaded_specs do
192
+ before(:each) do
193
+ Gem.stub!(:loaded_specs)
194
+ end
195
+
196
+ it "should return the correct gemset for name gem" do
197
+ Gem.should_receive(:loaded_specs).and_return({ "name" => nil })
198
+ AlsoMigrate::Gems.send(:gemset_from_loaded_specs).should == :default
199
+ end
200
+
201
+ it "should return the correct gemset for name-rspec gem" do
202
+ Gem.should_receive(:loaded_specs).and_return({ "name-rspec2" => nil })
203
+ AlsoMigrate::Gems.send(:gemset_from_loaded_specs).should == :rspec2
204
+ end
205
+ end
206
+
207
+ describe :reload_gemspec do
208
+ it "should populate @gemspec" do
209
+ AlsoMigrate::Gems.gemspec.hash.should == {
210
+ "name" => "name",
211
+ "version" => "0.1.0",
212
+ "authors" => ["Author"],
213
+ "email" => "email@email.com",
214
+ "homepage" => "http://github.com/author/name",
215
+ "summary" => "Summary",
216
+ "description" => "Description",
217
+ "dependencies" => [
218
+ "rake",
219
+ { "default" => [ "mysql" ] },
220
+ { "rspec2" => [ "mysql2" ] }
221
+ ],
222
+ "development_dependencies" => nil
223
+ }
224
+ end
225
+
226
+ it "should create methods from keys of @gemspec" do
227
+ AlsoMigrate::Gems.gemspec.name.should == "name"
228
+ AlsoMigrate::Gems.gemspec.version.should == "0.1.0"
229
+ AlsoMigrate::Gems.gemspec.authors.should == ["Author"]
230
+ AlsoMigrate::Gems.gemspec.email.should == "email@email.com"
231
+ AlsoMigrate::Gems.gemspec.homepage.should == "http://github.com/author/name"
232
+ AlsoMigrate::Gems.gemspec.summary.should == "Summary"
233
+ AlsoMigrate::Gems.gemspec.description.should == "Description"
234
+ AlsoMigrate::Gems.gemspec.dependencies.should == [
235
+ "rake",
236
+ { "default" => ["mysql"] },
237
+ { "rspec2" => [ "mysql2" ] }
238
+ ]
239
+ AlsoMigrate::Gems.gemspec.development_dependencies.should == nil
240
+ end
241
+
242
+ it "should produce a valid gemspec" do
243
+ AlsoMigrate::Gems.gemset = :default
244
+ gemspec = File.expand_path("../../../also_migrate.gemspec", __FILE__)
245
+ gemspec = eval(File.read(gemspec), binding, gemspec)
246
+ gemspec.validate.should == true
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,183 @@
1
+ require "spec_helper"
2
+
3
+ describe AlsoMigrate do
4
+
5
+ [ "table doesn't exist yet", "table already exists" ].each do |description|
6
+ describe description do
7
+ describe 'with all options' do
8
+
9
+ before(:each) do
10
+ reset_fixture
11
+
12
+ if description == "table doesn't exist yet"
13
+ AlsoMigrate.configuration << {
14
+ :source => :articles,
15
+ :destination => :article_archives,
16
+ :add => [
17
+ [ 'deleted_at', :datetime ]
18
+ ],
19
+ :subtract => 'restored_at',
20
+ :ignore => 'body',
21
+ :indexes => 'id'
22
+ }
23
+ end
24
+
25
+ $db.migrate(1)
26
+ $db.migrate(0)
27
+ $db.migrate(1)
28
+
29
+ if description == "table already exists"
30
+ AlsoMigrate.configuration << {
31
+ :source => :articles,
32
+ :destination => :article_archives,
33
+ :add => [
34
+ [ 'deleted_at', :datetime ]
35
+ ],
36
+ :subtract => %w(restored_at),
37
+ :ignore => %w(body),
38
+ :indexes => %w(id)
39
+ }
40
+ $db.migrate(1)
41
+ end
42
+ end
43
+
44
+ it "should create the add column" do
45
+ (columns('article_archives') - columns('articles')).should == [ 'deleted_at' ]
46
+ end
47
+
48
+ it "should not create the subtract column" do
49
+ (columns('articles') - columns('article_archives')).should == [ 'restored_at' ]
50
+ end
51
+
52
+ it 'should migrate both tables up' do
53
+ migrate_with_state(2)
54
+ (@new_article_columns - @old_article_columns).should == [ 'permalink' ]
55
+ (@new_archive_columns - @old_archive_columns).should == [ 'permalink' ]
56
+ end
57
+
58
+ it 'should migrate both tables down' do
59
+ $db.migrate(2)
60
+ migrate_with_state(1)
61
+ (@old_article_columns - @new_article_columns).should == [ 'permalink' ]
62
+ (@old_archive_columns - @new_archive_columns).should == [ 'permalink' ]
63
+ end
64
+
65
+ it "should ignore the body column" do
66
+ (columns('article_archives') - columns('articles')).should == [ 'deleted_at' ]
67
+ connection.remove_column(:articles, :body)
68
+ (columns('article_archives') - columns('articles')).should == [ 'body', 'deleted_at' ]
69
+ end
70
+
71
+ it "should only add an index for id" do
72
+ indexed_columns('articles').should == [ 'id', 'read' ]
73
+ indexed_columns('article_archives').should == [ 'id' ]
74
+ end
75
+ end
76
+
77
+ describe 'with no index option' do
78
+
79
+ before(:each) do
80
+ reset_fixture
81
+
82
+ if description == "table doesn't exist yet"
83
+ AlsoMigrate.configuration << {
84
+ :source => :articles,
85
+ :destination => :article_archives
86
+ }
87
+ end
88
+
89
+ $db.migrate(0)
90
+ $db.migrate(1)
91
+
92
+ if description == "table already exists"
93
+ AlsoMigrate.configuration << {
94
+ :source => :articles,
95
+ :destination => :article_archives
96
+ }
97
+ $db.migrate(1)
98
+ end
99
+ end
100
+
101
+ it "should add all indexes" do
102
+ indexed_columns('articles').should == [ 'id', 'read' ]
103
+ indexed_columns('article_archives').should == [ 'id', 'read' ]
104
+ end
105
+ end
106
+
107
+ describe "with other table" do
108
+
109
+ before(:each) do
110
+ reset_fixture
111
+
112
+ if description == "table doesn't exist yet"
113
+ AlsoMigrate.configuration << {
114
+ :source => :articles,
115
+ :destination => :article_archives
116
+ }
117
+ AlsoMigrate.configuration << {
118
+ :source => :comments,
119
+ :destination => :comment_archives
120
+ }
121
+ end
122
+
123
+ $db.migrate(0)
124
+ $db.migrate(1)
125
+ $db.migrate(2)
126
+ $db.migrate(3)
127
+
128
+ if description == "table already exists"
129
+ AlsoMigrate.configuration << {
130
+ :source => :articles,
131
+ :destination => :article_archives
132
+ }
133
+ AlsoMigrate.configuration << {
134
+ :source => :comments,
135
+ :destination => :comment_archives
136
+ }
137
+ $db.migrate(3)
138
+ end
139
+ end
140
+
141
+ it "should not affect other table" do
142
+ columns('articles').should == columns('article_archives')
143
+ columns('comments').should == columns('comment_archives')
144
+ columns('articles').should == ["id", "title", "body", "read", "restored_at", "permalink"]
145
+ columns('comments').should == ["id", "header", "description"]
146
+ end
147
+ end
148
+
149
+ if description == "table already exists"
150
+ describe 'with add and subtract option' do
151
+
152
+ before(:each) do
153
+ reset_fixture
154
+
155
+ AlsoMigrate.configuration << {
156
+ :source => :articles,
157
+ :destination => :article_archives
158
+ }
159
+
160
+ $db.migrate(0)
161
+ $db.migrate(1)
162
+
163
+ AlsoMigrate.configuration = []
164
+ AlsoMigrate.configuration << {
165
+ :source => :articles,
166
+ :destination => :article_archives,
167
+ :add => [
168
+ [ 'deleted_at', :datetime ]
169
+ ],
170
+ :subtract => 'restored_at'
171
+ }
172
+ end
173
+
174
+ it "should add and remove fields" do
175
+ columns('article_archives').should == %w(id title body read restored_at)
176
+ $db.migrate(1)
177
+ columns('article_archives').should == %w(id title body read deleted_at)
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,6 @@
1
+ test:
2
+ adapter: mysql
3
+ database: also_migrate
4
+ username: root
5
+ password:
6
+ host: localhost
@@ -0,0 +1,15 @@
1
+ class CreateArticles < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :articles do |t|
4
+ t.string :title
5
+ t.string :body
6
+ t.boolean :read
7
+ t.datetime :restored_at
8
+ end
9
+ add_index :articles, :read
10
+ end
11
+
12
+ def self.down
13
+ drop_table :articles
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ class AddPermalink < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :articles, :permalink, :string
4
+ end
5
+
6
+ def self.down
7
+ remove_column :articles, :permalink
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ class CreateComments < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :comments do |t|
4
+ t.string :header
5
+ t.string :description
6
+ end
7
+ end
8
+
9
+ def self.down
10
+ drop_table :comments
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ name:
2
+ rake: =0.8.7
3
+ default:
4
+ mysql: =2.8.1
5
+ rspec: =1.3.1
6
+ rspec2:
7
+ mysql2: =0.2.6
8
+ rspec: =2.3.0
9
+ solo: null
@@ -0,0 +1,15 @@
1
+ name: name
2
+ version: 0.1.0
3
+ authors:
4
+ - Author
5
+ email: email@email.com
6
+ homepage: http://github.com/author/name
7
+ summary: Summary
8
+ description: Description
9
+ dependencies:
10
+ - rake
11
+ - default:
12
+ - mysql
13
+ - rspec2:
14
+ - mysql2
15
+ development_dependencies: null
@@ -0,0 +1,94 @@
1
+ require 'pp'
2
+
3
+ $root = File.expand_path('../../', __FILE__)
4
+ require "#{$root}/lib/also_migrate/gems"
5
+
6
+ AlsoMigrate::Gems.activate :active_wrapper, :rspec
7
+
8
+ require 'active_wrapper'
9
+
10
+ require "#{$root}/lib/also_migrate"
11
+ require 'pp'
12
+
13
+ Spec::Runner.configure do |config|
14
+ end
15
+
16
+ $db, $log, $mail = ActiveWrapper.setup(
17
+ :base => File.dirname(__FILE__),
18
+ :env => 'test'
19
+ )
20
+ $db.establish_connection
21
+
22
+ def columns(table)
23
+ connection.columns(table).collect(&:name)
24
+ end
25
+
26
+ def connection
27
+ ActiveRecord::Base.connection
28
+ end
29
+
30
+ # For use with rspec textmate bundle
31
+ def debug(object)
32
+ puts "<pre>"
33
+ puts object.pretty_inspect.gsub('<', '&lt;').gsub('>', '&gt;')
34
+ puts "</pre>"
35
+ end
36
+
37
+ def indexed_columns(table_name)
38
+ # MySQL
39
+ if connection.class.to_s.include?('Mysql')
40
+ index_query = "SHOW INDEX FROM #{table_name}"
41
+ connection.select_all(index_query).collect do |r|
42
+ r["Column_name"]
43
+ end
44
+ # PostgreSQL
45
+ # http://stackoverflow.com/questions/2204058/show-which-columns-an-index-is-on-in-postgresql/2213199
46
+ elsif connection.class.to_s.include?('PostgreSQL')
47
+ index_query = <<-SQL
48
+ select
49
+ t.relname as table_name,
50
+ i.relname as index_name,
51
+ a.attname as column_name
52
+ from
53
+ pg_class t,
54
+ pg_class i,
55
+ pg_index ix,
56
+ pg_attribute a
57
+ where
58
+ t.oid = ix.indrelid
59
+ and i.oid = ix.indexrelid
60
+ and a.attrelid = t.oid
61
+ and a.attnum = ANY(ix.indkey)
62
+ and t.relkind = 'r'
63
+ and t.relname = '#{table_name}'
64
+ order by
65
+ t.relname,
66
+ i.relname
67
+ SQL
68
+ connection.select_all(index_query).collect do |r|
69
+ r["column_name"]
70
+ end
71
+ else
72
+ raise 'AlsoMigrate does not support this database adapter'
73
+ end
74
+ end
75
+
76
+ def migrate_with_state(version)
77
+ @old_article_columns = columns("articles")
78
+ @old_archive_columns = columns("article_archives")
79
+ $db.migrate(version)
80
+ @new_article_columns = columns("articles")
81
+ @new_archive_columns = columns("article_archives")
82
+ end
83
+
84
+ def reset_fixture
85
+ AlsoMigrate.configuration = []
86
+
87
+ if connection.table_exists?('article_archives')
88
+ connection.execute('DROP TABLE article_archives')
89
+ end
90
+
91
+ if connection.table_exists?('comment_archives')
92
+ connection.execute('DROP TABLE comment_archives')
93
+ end
94
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: also_migrate_nj
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.6
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Winton Welsh
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Migrate multiple tables with similar schema at once.
47
+ email: james@njtechnologies.co.uk
48
+ executables: []
49
+ extensions: []
50
+ extra_rdoc_files: []
51
+ files:
52
+ - .gitignore
53
+ - LICENSE
54
+ - README.md
55
+ - Rakefile
56
+ - also_migrate.gemspec
57
+ - config/gemsets.yml
58
+ - config/gemspec.yml
59
+ - init.rb
60
+ - lib/also_migrate.rb
61
+ - lib/also_migrate/gems.rb
62
+ - lib/also_migrate/migration.rb
63
+ - lib/also_migrate/migrator.rb
64
+ - rails/init.rb
65
+ - spec/Rakefile
66
+ - spec/also_migrate/gems_spec.rb
67
+ - spec/also_migrate_spec.rb
68
+ - spec/config/database.yml.example
69
+ - spec/db/migrate/001_create_articles.rb
70
+ - spec/db/migrate/002_add_permalink.rb
71
+ - spec/db/migrate/003_create_comments.rb
72
+ - spec/fixtures/gemsets.yml
73
+ - spec/fixtures/gemspec.yml
74
+ - spec/spec_helper.rb
75
+ homepage: https://github.com/jamesharker/also_migrate
76
+ licenses: []
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ! '>='
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 1.8.24
96
+ signing_key:
97
+ specification_version: 3
98
+ summary: Migrate multiple tables with similar schema at once.
99
+ test_files:
100
+ - spec/Rakefile
101
+ - spec/also_migrate/gems_spec.rb
102
+ - spec/also_migrate_spec.rb
103
+ - spec/config/database.yml.example
104
+ - spec/db/migrate/001_create_articles.rb
105
+ - spec/db/migrate/002_add_permalink.rb
106
+ - spec/db/migrate/003_create_comments.rb
107
+ - spec/fixtures/gemsets.yml
108
+ - spec/fixtures/gemspec.yml
109
+ - spec/spec_helper.rb
110
+ has_rdoc: