also_migrate_nj 0.3.6

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.
@@ -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: