migrator 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Binary file
@@ -0,0 +1,29 @@
1
+ # -*- ruby -*-
2
+
3
+ module Autotest::GnomeNotify
4
+
5
+ # Time notification will be displayed before disappearing automatically
6
+ EXPIRATION_IN_SECONDS = 2
7
+ ERROR_STOCK_ICON = "gtk-dialog-error"
8
+ SUCCESS_STOCK_ICON = "gtk-dialog-info"
9
+
10
+ # Convenience method to send an error notification message
11
+ #
12
+ # [stock_icon] Stock icon name of icon to display
13
+ # [title] Notification message title
14
+ # [message] Core message for the notification
15
+ def self.notify stock_icon, title, message
16
+ options = "-t #{EXPIRATION_IN_SECONDS * 1000} -i #{stock_icon}"
17
+ system "notify-send #{options} '#{title}' '#{message}'"
18
+ end
19
+
20
+ Autotest.add_hook :red do |at|
21
+ notify ERROR_STOCK_ICON, "Tests failed", "#{at.files_to_test.size} tests failed"
22
+ end
23
+
24
+ Autotest.add_hook :green do |at|
25
+ notify SUCCESS_STOCK_ICON, "All tests passed, good job!", ""
26
+ end
27
+
28
+ end
29
+
@@ -0,0 +1,5 @@
1
+ === 1.0.0 / 2009-09-17
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
@@ -0,0 +1,13 @@
1
+ lib/aef/migrator/adapter.rb
2
+ lib/aef/migrator/migrator.rb
3
+ lib/aef/migrator/abstract_adapter.rb
4
+ lib/aef/migrator.rb
5
+ Manifest.txt
6
+ History.txt
7
+ Rakefile
8
+ .autotest
9
+ spec/spec_helper.rb
10
+ spec/mock_adapter.rb
11
+ spec/spec.opts
12
+ spec/migrator_spec.rb
13
+ README.rdoc
@@ -0,0 +1,209 @@
1
+ = Migrator
2
+
3
+ * Project: https://rubyforge.org/projects/migrator/
4
+ * RDoc: http://migrator.rubyforge.org/
5
+ * Github: http://github.com/aef/migrator/
6
+
7
+ == DESCRIPTION:
8
+
9
+ Migrator is a Ruby library for building general purpose versioning systems in
10
+ the style of ActiveRecord's migrations.
11
+
12
+ == FEATURES/PROBLEMS:
13
+
14
+ * Completely written in Ruby
15
+ * Tested and fully working on:
16
+ * Ubuntu Linux 8.10 amd64/x86_64
17
+ * Ruby 1.8.7p72
18
+ * Ruby 1.9.1p129
19
+ * Debian GNU/Linux 4.0 x86
20
+ * Ruby 1.8.6
21
+ * On Windows XP x86
22
+ * Ruby 1.8.6
23
+
24
+ == SYNOPSIS:
25
+
26
+ Load the gem:
27
+
28
+ require 'aef/migrator'
29
+
30
+ Build an adapter:
31
+
32
+ class Adapter
33
+ include Aef::Migrator::Adapter
34
+
35
+ # version() has to reflect the current version. Also version=() must exist
36
+ # to set the current version
37
+ attr_accessor :version,
38
+
39
+ # versions() has to provide a list of all versions in correct order
40
+ attr_accessor :versions
41
+
42
+ def initialize
43
+ self.versions = %w{a b c d e}
44
+ self.version = 'c'
45
+ end
46
+
47
+ # process() has to do the work behind a migration in forward direction. Will
48
+ # be called multiple times for multistep migrations.
49
+ def process(target_version)
50
+ puts "Migrating from #{version} to #{target_version}"
51
+
52
+ self.version = target_version
53
+ end
54
+
55
+ # revert() has to do the work behind a migration in backward direction. Will
56
+ # be called multiple times for multistep migrations.
57
+ def revert(target_version)
58
+ puts "Unmigrating from #{version} to #{target_version}"
59
+
60
+ self.version = target_version
61
+ end
62
+ end
63
+
64
+ Notice that the module Aef::Migrator::Adapter and the class
65
+ Aef::Migrator::AbstractAdapter both provide the basic method definitions for an
66
+ adapter but no functionality. The advantage are better error messages when you
67
+ forget to implement something, but you don't have to use either, as
68
+ Aef::Migrator defines an adapter only by checking for required methods.
69
+
70
+ Now we setup the migrator:
71
+
72
+ migrator = Aef::Migrator.new(Adapter.new)
73
+
74
+ After that we can use the versioning backend provided by the adapter to do
75
+ migrations:
76
+
77
+ migrator.version
78
+ # => "c"
79
+
80
+ migrator.up
81
+ migrator.version
82
+ # => "d"
83
+
84
+ migrator.up.version
85
+ # => "e"
86
+
87
+ migrator.down('b')
88
+ migrator.version
89
+ # => "b"
90
+
91
+ migrator.migrate('e').version
92
+ # => "e"
93
+
94
+ When migrations cannot be done, exceptions of the baseclass Aef::Migrator::Error
95
+ are raised. If there is a problem with the Adapter the exceptions will be of
96
+ Aef::Migrator::AdapterError which is a subclass of Aef::Migrator::Error.
97
+ Exceptions informing about unmatched migration constraints are from the subclass
98
+ Aef::Migrator::MigrationError.
99
+
100
+ We can also check if a migration is possible before running it. This way we
101
+ don't have to deal with exceptions when a migration cannot be done.
102
+
103
+ migrator.migratable?('e')
104
+ # => false
105
+
106
+ migrator.upable?
107
+ # => false
108
+
109
+ migrator.downable?('c')
110
+ # => true
111
+
112
+ See the files in the spec subdirectory for further examples of usage.
113
+
114
+ == REQUIREMENTS:
115
+
116
+ * rubygems
117
+
118
+ === Additional for automated testing
119
+ * hoe (>= 2.3.2)
120
+ * rspec (>= 1.2.8)
121
+
122
+ == INSTALL:
123
+
124
+ On *nix systems you may need to prefix the command with sudo to get root
125
+ privileges.
126
+
127
+ === High security (recommended)
128
+
129
+ There is a high security installation option available through rubygems. It is
130
+ highly recommended over the normal installation, although it may be a bit less
131
+ comfortable. To use the installation method, you will need my public key, which
132
+ I use for cryptographic signatures on all my gems. You can find the public key
133
+ and more detailed verification information in the aef-certificates section of my
134
+ rubyforge project[https://rubyforge.org/frs/?group_id=7890&release_id=31749]
135
+
136
+ Add the key to your rubygems' trusted certificates by the following command:
137
+
138
+ gem cert --add aef.pem
139
+
140
+ Now you can install the gem while automatically verifying it's signature by the
141
+ following command:
142
+
143
+ gem install migrator --ignore-dependencies -P HighSecurity
144
+
145
+ Please notice that you may need other keys for dependent libraries, so you may
146
+ have to install dependencies manually.
147
+
148
+ === Normal (insecure)
149
+
150
+ gem install migrator
151
+
152
+ === Github (also insecure)
153
+
154
+ Alternatively you could install migrator from github which may be a bit more
155
+ up to date. The version may however not be as stable as the normal gem and there
156
+ is no way to install the gem securely. Therefore this is not recommended.
157
+
158
+ gem install aef-migrator --source http://gems.github.com
159
+
160
+ === Automated testing
161
+
162
+ You can test this package through rspec on your system. First find the path
163
+ where the gem was installed to:
164
+
165
+ gem which aef/migrator
166
+
167
+ Go into the root directory of the installed gem and run the following command
168
+ to start the test runner:
169
+
170
+ rake spec
171
+
172
+ If something goes wrong you should be noticed through failing examples.
173
+
174
+ == DEVELOPMENT:
175
+
176
+ This software is developed in the source code management system git hosted
177
+ at github.com. You can download the most recent sourcecode through the following
178
+ command:
179
+
180
+ git clone git://github.com/aef/migrator.git
181
+
182
+ Help on making this software better is always very appreciated. If you want your
183
+ changes to be included in the official release, please send me a patch through
184
+ the project's tracker[https://rubyforge.org/tracker/?group_id=7890] at
185
+ rubyforge.org. You can generate a patch-file by the following command:
186
+
187
+ git diff > patch.diff
188
+
189
+ Please make sure to write tests for your changes and notice that I can't promise
190
+ to include your changes before reviewing them.
191
+
192
+ == LICENSE:
193
+
194
+ Copyright 2009 Alexander E. Fischer <aef@raxys.net>
195
+
196
+ This file is part of Migrator.
197
+
198
+ Migrator is free software: you can redistribute it and/or modify
199
+ it under the terms of the GNU General Public License as published by
200
+ the Free Software Foundation, either version 3 of the License, or
201
+ (at your option) any later version.
202
+
203
+ This program is distributed in the hope that it will be useful,
204
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
205
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
206
+ GNU General Public License for more details.
207
+
208
+ You should have received a copy of the GNU General Public License
209
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ Hoe.spec('migrator') do
7
+ developer('Alexander E. Fischer', 'aef@raxys.net')
8
+
9
+ self.rubyforge_name = 'migrator'
10
+ self.extra_dev_deps = {
11
+ 'rspec' => '>= 1.2.8'
12
+ }
13
+ self.url = 'https://rubyforge.org/projects/migrator/'
14
+ self.readme_file = 'README.rdoc'
15
+ self.extra_rdoc_files = %w{README.rdoc}
16
+ self.spec_extras = {
17
+ :rdoc_options => ['--main', 'README.rdoc', '--inline-source', '--line-numbers', '--title', 'Migrator']
18
+ }
19
+ self.rspec_options = ['--options', 'spec/spec.opts']
20
+ self.remote_rdoc_dir = ''
21
+ end
22
+
23
+ # vim: syntax=Ruby
@@ -0,0 +1,27 @@
1
+ # Copyright 2009 Alexander E. Fischer <aef@raxys.net>
2
+ #
3
+ # This file is part of Migrator.
4
+ #
5
+ # Migrator is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ # Namespace for projects of Alexander E. Fischer <aef@raxys.net>
19
+ #
20
+ # If you want to be able to simply type Example instead of Aef::Example to
21
+ # address classes in this namespace simply write the following before using the
22
+ # classes:
23
+ #
24
+ # include Aef
25
+ module Aef
26
+ autoload :Migrator, 'aef/migrator/migrator'
27
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright 2009 Alexander E. Fischer <aef@raxys.net>
2
+ #
3
+ # This file is part of Migrator.
4
+ #
5
+ # Migrator is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ # This class implements the interface for an adapter required by Aef::Migrator
19
+ # and could be used as an abstract base class. See also: Adapter
20
+ class Aef::Migrator::AbstractAdapter
21
+ include Aef::Migrator::Adapter
22
+
23
+ def initialize
24
+ raise NotImplementedError, 'Abstract class' if self.class == Aef::Migrator::AbstractAdapter
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ # Copyright 2009 Alexander E. Fischer <aef@raxys.net>
2
+ #
3
+ # This file is part of Migrator.
4
+ #
5
+ # Migrator is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ # This module implements the interface for an adapter required by Aef::Migrator.
19
+ # See also: AbstractAdapter.
20
+ module Aef::Migrator::Adapter
21
+ def process(target_version)
22
+ raise NotImplementedError, 'The process method needs to be implemented'
23
+ end
24
+
25
+ def revert(target_version)
26
+ raise NotImplementedError, 'The revert method needs to be implemented'
27
+ end
28
+
29
+ def version
30
+ raise NotImplementedError, 'The version method needs to be implemented'
31
+ end
32
+
33
+ def version=(versions)
34
+ raise NotImplementedError, 'The version= method needs to be implemented'
35
+ end
36
+
37
+ def versions
38
+ raise NotImplementedError, 'The versions method needs to be implemented'
39
+ end
40
+ end
@@ -0,0 +1,170 @@
1
+ # Copyright 2009 Alexander E. Fischer <aef@raxys.net>
2
+ #
3
+ # This file is part of Migrator.
4
+ #
5
+ # Migrator is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ # Class for building general purpose versioning systems in the style of
19
+ # ActiveRecord's migrations. An adapter object is needed for any instance of
20
+ # this class to have any use. See Adapter and AbstractAdapter for the required
21
+ # interface.
22
+ class Aef::Migrator
23
+ VERSION = '1.0.0'
24
+
25
+ # Baseclass for all Migrator specific exceptions
26
+ class Error < RuntimeError; end
27
+
28
+ # Baseclass for exceptions describing adapter errors
29
+ class AdapterError < Error; end
30
+ class AdapterMissingError < AdapterError; end
31
+ class AdapterMethodMissingError < AdapterError; end
32
+ class CurrentVersionInvalidError < AdapterError; end
33
+
34
+ # Baseclass for exceptions describing errors while processing migrations
35
+ class MigrationError < Error; end
36
+ class AlreadyOnTopError < MigrationError; end
37
+ class AlreadyOnBottomError < MigrationError; end
38
+ class TargetVersionInvalidError < MigrationError; end
39
+ class UpMigrationInvalidError < MigrationError; end
40
+ class DownMigrationInvalidError < MigrationError; end
41
+ class MigrationUnneccessaryError < MigrationError; end
42
+
43
+ autoload :Adapter, 'aef/migrator/adapter'
44
+ autoload :AbstractAdapter, 'aef/migrator/abstract_adapter'
45
+
46
+ attr_accessor :adapter
47
+
48
+ def initialize(adapter)
49
+ @adapter = adapter
50
+ end
51
+
52
+ # Checks if a migration is possible
53
+ def migratable?(target_version, direction = nil)
54
+ !!migration_steps(target_version, direction)
55
+ rescue MigrationError
56
+ false
57
+ end
58
+
59
+ # Checks if an up migration is possible
60
+ def upable?(target_version = nil)
61
+ migratable?(target_version, :up)
62
+ end
63
+
64
+ # Checks if a down migration is possible
65
+ def downable?(target_version = nil)
66
+ migratable?(target_version, :down)
67
+ end
68
+
69
+ # Process a migration
70
+ #
71
+ # Raises MigratorError in case of invalid actions
72
+ def migrate(target_version, direction = nil)
73
+ params = migration_steps(target_version, direction)
74
+
75
+ params[:steps].each do |version|
76
+ @adapter.send(params[:action], version)
77
+ end
78
+
79
+ self
80
+ end
81
+
82
+ # Process an up migration
83
+ #
84
+ # Raises MigratorError in case of invalid actions
85
+ def up(target_version = nil)
86
+ migrate(target_version, :up)
87
+ end
88
+
89
+ # Process a down migration
90
+ #
91
+ # Raises MigratorError in case of invalid actions
92
+ def down(target_version = nil)
93
+ migrate(target_version, :down)
94
+ end
95
+
96
+ # Current version
97
+ def version
98
+ @adapter.version
99
+ end
100
+
101
+ # All possible versions in correct order
102
+ def versions
103
+ @adapter.versions
104
+ end
105
+
106
+ protected
107
+
108
+ # Returns a hash with an :action value and a :steps array with all versions
109
+ # to reach the target
110
+ def migration_steps(target_version, direction)
111
+ raise ArgumentError, 'Invalid direction' unless [nil, :up, :down].include?(direction)
112
+
113
+ unless @adapter
114
+ raise AdapterMissingError, 'No adapter set'
115
+ else
116
+ Adapter.instance_methods(false).each do |method|
117
+ raise AdapterMethodMissingError, "Adapter must respond to #{method}" unless @adapter.respond_to?(method)
118
+ end
119
+ end
120
+
121
+ version_list = versions
122
+ current_version = version
123
+
124
+ indices = {:current => version_list.index(current_version)}
125
+
126
+ raise CurrentVersionInvalidError, "Current version not in version list: " +
127
+ "'#{current_version}'" unless indices[:current]
128
+
129
+ # When direction is set and target_version is unset step up/down by one
130
+ unless target_version
131
+ case direction
132
+ when :up
133
+ step_up = indices[:current] + 1
134
+ raise AlreadyOnTopError, 'Already on highest version' unless step_up < version_list.size
135
+ indices[:target] = step_up
136
+ target_version = version_list[step_up]
137
+ when :down
138
+ step_down = indices[:current] - 1
139
+ raise AlreadyOnBottomError, 'Already on lowest version' unless step_down >= 0
140
+ indices[:target] = step_down
141
+ target_version = version_list[step_down]
142
+ else
143
+ raise ArgumentError, 'No target version specified'
144
+ end
145
+ else
146
+ indices[:target] = version_list.index(target_version)
147
+
148
+ raise TargetVersionInvalidError, 'Target version not in version list: ' +
149
+ "'#{target_version}'" unless indices[:target]
150
+ end
151
+
152
+ if indices[:current] < indices[:target]
153
+ raise DownMigrationInvalidError, "Current version '#{current_version}' " +
154
+ "is lower than '#{target_version}'" if direction == :down
155
+
156
+ indices[:current] += 1
157
+
158
+ {:action => :process, :steps => version_list[indices.values.min..indices.values.max]}
159
+ elsif indices[:current] > indices[:target]
160
+ raise UpMigrationInvalidError, "Current version '#{current_version}' " +
161
+ "is higher than '#{target_version}'" if direction == :up
162
+
163
+ indices[:current] -= 1
164
+
165
+ {:action => :revert, :steps => version_list[indices.values.min..indices.values.max].reverse}
166
+ else
167
+ raise MigrationUnneccessaryError, "Current version equals target version: '#{current_version}'"
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,214 @@
1
+ # Copyright 2009 Alexander E. Fischer <aef@raxys.net>
2
+ #
3
+ # This file is part of Migrator.
4
+ #
5
+ # Migrator is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'spec/spec_helper'
19
+
20
+ describe Aef::Migrator do
21
+ before(:all) do
22
+ class BrokenAdapter < described_class::AbstractAdapter
23
+ undef :process
24
+ end
25
+ end
26
+
27
+ before(:each) do
28
+ @adapter = MockAdapter.new
29
+ @adapter.verbose = false
30
+ @migrator = described_class.new(@adapter)
31
+ end
32
+
33
+ it "should complain about invalid direction params" do
34
+ lambda {
35
+ @migrator.migrate('a', :invalid)
36
+ }.should raise_error(ArgumentError)
37
+ end
38
+
39
+ it "should complain when no adapter is set" do
40
+ lambda {
41
+ @migrator.adapter = nil
42
+ @migrator.migrate('a')
43
+ }.should raise_error(described_class::AdapterMissingError)
44
+ end
45
+
46
+ it "should complain about missing adapter methods" do
47
+ lambda {
48
+ @migrator.adapter = BrokenAdapter.new
49
+ @migrator.migrate('a')
50
+ }.should raise_error(described_class::AdapterMethodMissingError)
51
+ end
52
+
53
+ it "should complain about current versions which are not in versions" do
54
+ lambda {
55
+ @adapter.version = 'f'
56
+ @migrator.migrate('a')
57
+ }.should raise_error(described_class::CurrentVersionInvalidError)
58
+ end
59
+
60
+ it "should complain about target versions which are not in versions" do
61
+ lambda {
62
+ @migrator.migrate('invalid')
63
+ }.should raise_error(described_class::TargetVersionInvalidError)
64
+ end
65
+
66
+ it "should complain about migrating to the current version" do
67
+ lambda {
68
+ @migrator.migrate('c')
69
+ }.should raise_error(described_class::MigrationUnneccessaryError)
70
+ end
71
+
72
+ it "should be able to implicitly migrate one version up" do
73
+ lambda {
74
+ @migrator.up
75
+ }.should change{@migrator.version}.from('c').to('d')
76
+ end
77
+
78
+ it "should be able to implicitly migrate one version down" do
79
+ lambda {
80
+ @migrator.down
81
+ }.should change{@migrator.version}.from('c').to('b')
82
+ end
83
+
84
+ it "should be able to explicitly migrate one version up" do
85
+ lambda {
86
+ @migrator.up('d')
87
+ }.should change{@migrator.version}.from('c').to('d')
88
+ end
89
+
90
+ it "should be able to explicitly migrate one version down" do
91
+ lambda {
92
+ @migrator.down('b')
93
+ }.should change{@migrator.version}.from('c').to('b')
94
+ end
95
+
96
+ it "should be able to migrate multiple version up with one call" do
97
+ lambda {
98
+ @migrator.up('e')
99
+ }.should change{@migrator.version}.from('c').to('e')
100
+ end
101
+
102
+ it "should be able to migrate multiple version down with one call" do
103
+ lambda {
104
+ @migrator.down('a')
105
+ }.should change{@migrator.version}.from('c').to('a')
106
+ end
107
+
108
+ it "should prohibit migration in wrong direction when up method is used" do
109
+ lambda {
110
+ @migrator.up('a')
111
+ }.should raise_error(described_class::UpMigrationInvalidError)
112
+ end
113
+
114
+ it "should prohibit migration in wrong direction when down method is used" do
115
+ lambda {
116
+ @migrator.down('e')
117
+ }.should raise_error(described_class::DownMigrationInvalidError)
118
+ end
119
+
120
+ it "should allow up migration with generic migrate method" do
121
+ lambda {
122
+ @migrator.migrate('e')
123
+ }.should change{@migrator.version}.from('c').to('e')
124
+ end
125
+
126
+ it "should allow down migration with generic migrate method" do
127
+ lambda {
128
+ @migrator.migrate('a')
129
+ }.should change{@migrator.version}.from('c').to('a')
130
+ end
131
+
132
+ it "should complain about invalid direction params when migratable? is called" do
133
+ lambda {
134
+ @migrator.migratable?('a', :invalid)
135
+ }.should raise_error(ArgumentError)
136
+ end
137
+
138
+ it "should complain when no adapter is set when migratable? is called" do
139
+ lambda {
140
+ @migrator.adapter = nil
141
+ @migrator.migrate('a')
142
+ }.should raise_error(described_class::AdapterMissingError)
143
+ end
144
+
145
+ it "should complain about missing adapter methods when migratable? is called" do
146
+ lambda {
147
+ @migrator.adapter = BrokenAdapter.new
148
+ @migrator.migratable?('a')
149
+ }.should raise_error(described_class::AdapterMethodMissingError)
150
+ end
151
+
152
+ it "should complain about current versions which are not in versions when migratable? is called" do
153
+ lambda {
154
+ @adapter.version = 'f'
155
+ @migrator.migratable?('a')
156
+ }.should raise_error(described_class::CurrentVersionInvalidError)
157
+ end
158
+
159
+ it "should indicate that a migration to an invalid target version is impossible" do
160
+ @migrator.migratable?('invalid').should be_false
161
+ end
162
+
163
+ it "should indicate that implicitly migrating one version up is possible" do
164
+ @migrator.upable?.should be_true
165
+ end
166
+
167
+ it "should indicate that implicitly migrating one version down is possible" do
168
+ @migrator.downable?.should be_true
169
+ end
170
+
171
+ it "should indicate that migrating one version up is possible" do
172
+ @migrator.upable?('d').should be_true
173
+ end
174
+
175
+ it "should indicate that migrating one version down is possible" do
176
+ @migrator.downable?('b').should be_true
177
+ end
178
+
179
+ it "should indicate that a multi-step migration up is possible" do
180
+ @migrator.upable?('e').should be_true
181
+ end
182
+
183
+ it "should indicate that a multi-step migration down is possible" do
184
+ @migrator.downable?('a').should be_true
185
+ end
186
+
187
+ it "should indicate a wrong direction migration is impossible when upable? method is used" do
188
+ @migrator.upable?('a').should be_false
189
+ end
190
+
191
+ it "should indicate a wrong direction migration is impossible when downable? method is used" do
192
+ @migrator.downable?('e').should be_false
193
+ end
194
+
195
+ it "should indicate that up migration is possible when migratable? method is used" do
196
+ @migrator.migratable?('e').should be_true
197
+ end
198
+
199
+ it "should indicate that down migration is possible when migratable? method is used" do
200
+ @migrator.migratable?('a').should be_true
201
+ end
202
+
203
+ it "should return itself for method changing through method migrate" do
204
+ @migrator.migrate('d').should eql(@migrator)
205
+ end
206
+
207
+ it "should return itself for method changing through method up" do
208
+ @migrator.up.should eql(@migrator)
209
+ end
210
+
211
+ it "should return itself for method changing through method down" do
212
+ @migrator.down.should eql(@migrator)
213
+ end
214
+ end
@@ -0,0 +1,47 @@
1
+ # Copyright 2009 Alexander E. Fischer <aef@raxys.net>
2
+ #
3
+ # This file is part of Migrator.
4
+ #
5
+ # Migrator is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ class MockAdapter < Aef::Migrator::AbstractAdapter
19
+ attr_accessor :version, :versions_hash, :verbose
20
+
21
+ def initialize
22
+ @versions_hash = {
23
+ 'a' => 'a.version',
24
+ 'b' => 'b.version',
25
+ 'c' => 'c.version',
26
+ 'd' => 'd.version',
27
+ 'e' => 'e.version'
28
+ }
29
+ self.version = 'c'
30
+ end
31
+
32
+ def process(target_version)
33
+ puts "Migrating from #{version} to #{target_version} (#{versions_hash[target_version]})" if @verbose
34
+
35
+ self.version = target_version
36
+ end
37
+
38
+ def revert(target_version)
39
+ puts "Unmigrating from #{version} to #{target_version} (#{versions_hash[version]})" if @verbose
40
+
41
+ self.version = target_version
42
+ end
43
+
44
+ def versions
45
+ versions_hash.keys.sort
46
+ end
47
+ end
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,25 @@
1
+ # Copyright 2009 Alexander E. Fischer <aef@raxys.net>
2
+ #
3
+ # This file is part of Migrator.
4
+ #
5
+ # Migrator is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ $LOAD_PATH.unshift('lib')
19
+
20
+ require 'aef/migrator'
21
+ require 'spec/mock_adapter'
22
+
23
+ Spec::Runner.configure do |config|
24
+
25
+ end
metadata ADDED
@@ -0,0 +1,116 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: migrator
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Alexander E. Fischer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDKDCCAhCgAwIBAgIBADANBgkqhkiG9w0BAQUFADA6MQwwCgYDVQQDDANhZWYx
14
+ FTATBgoJkiaJk/IsZAEZFgVyYXh5czETMBEGCgmSJomT8ixkARkWA25ldDAeFw0w
15
+ OTAyMjUyMDM5MDhaFw0xMDAyMjUyMDM5MDhaMDoxDDAKBgNVBAMMA2FlZjEVMBMG
16
+ CgmSJomT8ixkARkWBXJheHlzMRMwEQYKCZImiZPyLGQBGRYDbmV0MIIBIjANBgkq
17
+ hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoYtj0qad5/MpbdttITzBH0h1SNe6eO7R
18
+ 7qVeqNYu6qDQAQ0rYc0JhubJCWYrZEJorHEBhUFU6cdQgQOs78wiJaDgkeU7YfXB
19
+ q2l125kJ8aHkA1ukrK2/DRzp2AHEmzxHIYpXV5/63h+NWjCP+uKvTELYsotS2MKt
20
+ 3d43E0QajsPZu2ZuNFwkroqeue872gMHUldGOVy5WtSd9ajw2xI/CociY6746dL+
21
+ pYriV3QaYtR/ezeaLpKBLsc5T1UQ07t7Xs7mI281tdmRvpLdP5dQhjzInfio0CJv
22
+ 1Pf5bZUjGG0K9RW2Gb/tGPSYEETiLMubjH61OwBooXKiWR5cs4/1BQIDAQABozkw
23
+ NzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQUSYvjhG2EWnR5kx5l
24
+ DAewXCkJOVEwDQYJKoZIhvcNAQEFBQADggEBAB2ryDbU4bQtnunKv/AXq4CuO3LS
25
+ kik9Xhye8E/5dTcsgitCZJXAqx0rHcK0u2EHnjA5CDcdF5JB7XgSvRrQkFWoW/9K
26
+ lCB4ih+sB2AI2IUiYBeoCGctXdBQ020prqop/oTQEudzFk/gyQ686lp06HdLRt+O
27
+ HoQjTIab8vmfgIubjPdIRzokMfHbelvhLi+mQfWVghRhs2jpEfdXbL0w5nNw+trp
28
+ rO70Dw59hduDUOpgpxew+PLbs4vP1tb1QKPG+39C+PZtosbbf1fai0hqYV1txMCx
29
+ 55akF+N8NbO6tpVDy6TMagqa10LfEpiQH6dvDHe/xdAqYOCrXKpmqzwu2PI=
30
+ -----END CERTIFICATE-----
31
+
32
+ date: 2009-09-17 00:00:00 +02:00
33
+ default_executable:
34
+ dependencies:
35
+ - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.2.8
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: hoe
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 2.3.2
54
+ version:
55
+ description: |-
56
+ Migrator is a Ruby library for building general purpose versioning systems in
57
+ the style of ActiveRecord's migrations.
58
+ email:
59
+ - aef@raxys.net
60
+ executables: []
61
+
62
+ extensions: []
63
+
64
+ extra_rdoc_files:
65
+ - Manifest.txt
66
+ - History.txt
67
+ - README.rdoc
68
+ files:
69
+ - lib/aef/migrator/adapter.rb
70
+ - lib/aef/migrator/migrator.rb
71
+ - lib/aef/migrator/abstract_adapter.rb
72
+ - lib/aef/migrator.rb
73
+ - Manifest.txt
74
+ - History.txt
75
+ - Rakefile
76
+ - .autotest
77
+ - spec/spec_helper.rb
78
+ - spec/mock_adapter.rb
79
+ - spec/spec.opts
80
+ - spec/migrator_spec.rb
81
+ - README.rdoc
82
+ has_rdoc: true
83
+ homepage: https://rubyforge.org/projects/migrator/
84
+ licenses: []
85
+
86
+ post_install_message:
87
+ rdoc_options:
88
+ - --main
89
+ - README.rdoc
90
+ - --inline-source
91
+ - --line-numbers
92
+ - --title
93
+ - Migrator
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: "0"
101
+ version:
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: "0"
107
+ version:
108
+ requirements: []
109
+
110
+ rubyforge_project: migrator
111
+ rubygems_version: 1.3.5
112
+ signing_key:
113
+ specification_version: 3
114
+ summary: Migrator is a Ruby library for building general purpose versioning systems in the style of ActiveRecord's migrations.
115
+ test_files: []
116
+
Binary file