migratrix 0.8.2 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -45,19 +45,40 @@ module Migratrix
45
45
  # TODO: THIS IS HUGE DUPLICATION, REFACTOR REFACTOR REFACTOR
46
46
 
47
47
  # extraction crap
48
- def self.set_extraction(extraction_name, class_name, options={})
49
- extractions[extraction_name] = Migratrix.extraction(class_name, extraction_name, options)
48
+ # set_extraction :nickname, :registered_name, options_hash
49
+ # set_extraction :nickname, :registered_name # options = {}
50
+ # set_extraction :registered_name, options_hash # nickname = :default
51
+ # set_extraction :registered_name # nickname = :default, options={}
52
+ def self.set_extraction(nickname, registered_name=nil, options=nil)
53
+ # barf, seriously these args need some detangler.
54
+ if registered_name.nil?
55
+ nickname, registered_name, options = :default, nickname, {}
56
+ elsif options.nil?
57
+ if registered_name.is_a?(Hash)
58
+ nickname, registered_name, options = :default, nickname, registered_name
59
+ else
60
+ nickname, registered_name, options = nickname, registered_name, {}
61
+ end
62
+ end
63
+ extractions[nickname] = Migratrix.extraction(nickname, registered_name, options)
50
64
  end
51
65
 
52
- def self.extend_extraction(extraction_name, options={})
53
- migration = ancestors.detect {|k| k.respond_to?(:extractions) && k.extractions[extraction_name]}
54
- raise ExtractionNotDefined.new("Could not extend extractar '%s'; no parent Migration defines it" % extraction_name) unless migration
55
- extraction = migration.extractions[extraction_name]
56
- extractions[extraction_name] = extraction.class.new(extraction_name, extraction.options.merge(options))
66
+ def self.extend_extraction(nickname, options={})
67
+ migration = ancestors.detect {|k| k.respond_to?(:extractions) && k.extractions[nickname]}
68
+ raise ExtractionNotDefined.new("Could not extend extraction '%s'; no parent Migration defines it" % nickname) unless migration
69
+ extraction = migration.extractions[nickname]
70
+ extractions[nickname] = extraction.class.new(nickname, extraction.options.merge(options))
57
71
  end
58
72
 
59
73
  def self.extractions
60
74
  @extractions ||= {}
75
+ ancestry = ancestors.select {|klass| klass != self && klass.respond_to?(:extractions) }.reverse
76
+ # take oldest ancestor and merge extractions forward
77
+ ext = {}
78
+ ancestry.each do |ancestor|
79
+ ext = ext.merge(ancestor.extractions || {})
80
+ end
81
+ @extractions = ext.merge(@extractions)
61
82
  end
62
83
 
63
84
  def extractions
@@ -65,8 +86,22 @@ module Migratrix
65
86
  end
66
87
 
67
88
  # transform crap
68
- def self.set_transform(name, type, options={})
69
- transforms[name] = Migratrix.transform(name, type, options)
89
+ # set_transform :nickname, :registered_name, options_hash
90
+ # set_transform :nickname, :registered_name # options = {}
91
+ # set_transform :registered_name, options_hash # nickname = :default
92
+ # set_transform :registered_name # nickname = :default, options={}
93
+ def self.set_transform(nickname, registered_name=nil, options=nil)
94
+ # barf, seriously these args need some detangler.
95
+ if registered_name.nil?
96
+ nickname, registered_name, options = :default, nickname, {}
97
+ elsif options.nil?
98
+ if registered_name.is_a?(Hash)
99
+ nickname, registered_name, options = :default, nickname, registered_name
100
+ else
101
+ nickname, registered_name, options = nickname, registered_name, {}
102
+ end
103
+ end
104
+ transforms[nickname] = Migratrix.transform(nickname, registered_name, options)
70
105
  end
71
106
 
72
107
  def self.extend_transform(transform_name, options={})
@@ -78,6 +113,13 @@ module Migratrix
78
113
 
79
114
  def self.transforms
80
115
  @transforms ||= {}
116
+ ancestry = ancestors.select {|klass| klass != self && klass.respond_to?(:transforms) }.reverse
117
+ # take oldest ancestor and merge transforms forward
118
+ ext = {}
119
+ ancestry.each do |ancestor|
120
+ ext = ext.merge(ancestor.transforms || {})
121
+ end
122
+ @transforms = ext.merge(@transforms)
81
123
  end
82
124
 
83
125
  def transforms
@@ -85,10 +127,28 @@ module Migratrix
85
127
  end
86
128
 
87
129
  # load crap
88
- def self.set_load(name, type, options={})
89
- loads[name] = Migratrix.load(name, type, options)
130
+ # set_load :nickname, :registered_name, options_hash
131
+ # set_load :nickname, :registered_name # options = {}
132
+ # set_load :registered_name, options_hash # nickname = :default
133
+ # set_load :registered_name # nickname = :default, options={}
134
+ def self.set_load(nickname, registered_name=nil, options=nil)
135
+ # barf, seriously these args need some detangler.
136
+ if registered_name.nil?
137
+ nickname, registered_name, options = :default, nickname, {}
138
+ elsif options.nil?
139
+ if registered_name.is_a?(Hash)
140
+ nickname, registered_name, options = :default, nickname, registered_name
141
+ else
142
+ nickname, registered_name, options = nickname, registered_name, {}
143
+ end
144
+ end
145
+ loads[nickname] = Migratrix.load(nickname, registered_name, options)
90
146
  end
91
147
 
148
+ # def self.set_load(name, type, options={})
149
+ # loads[name] = Migratrix.load(name, type, options)
150
+ # end
151
+
92
152
  def self.extend_load(load_name, options={})
93
153
  migration = ancestors.detect {|k| k.respond_to?(:loads) && k.loads[load_name]}
94
154
  raise LoadNotDefined.new("Could not extend extractar '%s'; no parent Migration defines it" % load_name) unless migration
@@ -98,6 +158,13 @@ module Migratrix
98
158
 
99
159
  def self.loads
100
160
  @loads ||= {}
161
+ ancestry = ancestors.select {|klass| klass != self && klass.respond_to?(:loads) }.reverse
162
+ # take oldest ancestor and merge loads forward
163
+ ext = {}
164
+ ancestry.each do |ancestor|
165
+ ext = ext.merge(ancestor.loads || {})
166
+ end
167
+ @loads = ext.merge(@loads)
101
168
  end
102
169
 
103
170
  def loads
@@ -52,12 +52,12 @@ module Migratrix
52
52
  registry[:extractions]
53
53
  end
54
54
 
55
- def self.register_extraction(class_name, klass, options={})
56
- self.extractions.register(class_name, klass, options)
55
+ def self.register_extraction(registered_name, klass, options={})
56
+ self.extractions.register(registered_name, klass, options)
57
57
  end
58
58
 
59
- def self.extraction(class_name, extraction_name, options={})
60
- self.extractions.class_for(class_name).new(extraction_name, options)
59
+ def self.extraction(nickname, registered_name, options={})
60
+ self.extractions.class_for(registered_name).new(nickname, options)
61
61
  end
62
62
  # --------------------
63
63
 
@@ -71,8 +71,8 @@ module Migratrix
71
71
  self.transforms.register(name, klass, options)
72
72
  end
73
73
 
74
- def self.transform(transform_name, class_name, options={})
75
- self.transforms.class_for(class_name).new(transform_name, options)
74
+ def self.transform(nickname, registered_name, options={})
75
+ self.transforms.class_for(registered_name).new(nickname, options)
76
76
  end
77
77
  # --------------------
78
78
 
@@ -86,8 +86,8 @@ module Migratrix
86
86
  self.loads.register(name, klass, options)
87
87
  end
88
88
 
89
- def self.load(load_name, class_name, options={})
90
- self.loads.class_for(class_name).new(load_name, options)
89
+ def self.load(nickname, registered_name, options={})
90
+ self.loads.class_for(registered_name).new(nickname, options)
91
91
  end
92
92
  # --------------------
93
93
 
@@ -0,0 +1,22 @@
1
+ class NoOpExtraction < Migratrix::Extractions::Extraction
2
+ def extract(options={})
3
+ []
4
+ end
5
+ end
6
+
7
+ class NoOpTransform < Migratrix::Transforms::Transform
8
+ def transform(exts, options={})
9
+ []
10
+ end
11
+ end
12
+
13
+ class NoOpLoad < Migratrix::Loads::Load
14
+ def load(trans, options={})
15
+ []
16
+ end
17
+ end
18
+
19
+ Migratrix::Migratrix.register_extraction :no_op, NoOpExtraction
20
+ Migratrix::Migratrix.register_transform :no_op, NoOpTransform
21
+ Migratrix::Migratrix.register_load :no_op, NoOpLoad
22
+
@@ -0,0 +1,11 @@
1
+ require 'test_migration'
2
+
3
+ class ChildMigration1 < TestMigration
4
+ end
5
+
6
+ class ChildMigration2 < TestMigration
7
+ end
8
+
9
+ class GrandchildMigration1 < ChildMigration1
10
+ end
11
+
@@ -0,0 +1,3 @@
1
+ class TestMigration < Migratrix::Migration
2
+ end
3
+
@@ -1,25 +1,4 @@
1
- class NoOpExtraction < Migratrix::Extractions::Extraction
2
- def extract(options={})
3
- []
4
- end
5
- end
6
-
7
- class NoOpTransform < Migratrix::Transforms::Transform
8
- def transform(exts, options={})
9
- []
10
- end
11
- end
12
-
13
- class NoOpLoad < Migratrix::Loads::Load
14
- def load(trans, options={})
15
- []
16
- end
17
- end
18
-
19
- Migratrix::Migratrix.register_extraction :no_op, NoOpExtraction
20
- Migratrix::Migratrix.register_transform :no_op, NoOpTransform
21
- Migratrix::Migratrix.register_load :no_op, NoOpLoad
22
-
1
+ require 'no_op_components'
23
2
 
24
3
  class TestCallbackMigration < Migratrix::Migration
25
4
  set_extraction :test, :no_op
@@ -1,18 +1,7 @@
1
1
  require 'spec_helper'
2
-
3
- # This migration is embedded in migration_spec.rb to allow testing of
4
- # the class methods that specialize subclasses.
5
- class TestMigration < Migratrix::Migration
6
- end
7
-
8
- class ChildMigration1 < TestMigration
9
- end
10
-
11
- class ChildMigration2 < TestMigration
12
- end
13
-
14
- class GrandchildMigration1 < ChildMigration1
15
- end
2
+ require 'no_op_components'
3
+ require 'test_migration'
4
+ require 'inherited_migrations'
16
5
 
17
6
  describe Migratrix::Migration do
18
7
  let(:migration) { TestMigration.new :cheese => 42 }
@@ -30,6 +19,31 @@ describe Migratrix::Migration do
30
19
  end
31
20
  end
32
21
 
22
+ [:extraction, :transform, :load].each do |component|
23
+ describe ".set_#{component}" do
24
+ describe "without options" do
25
+ it "creates #{component} with empty options" do
26
+ Migratrix::Migratrix.should_receive(component).with(:test, :no_op, {})
27
+ TestMigration.send "set_#{component}", :test, :no_op
28
+ end
29
+ end
30
+
31
+ describe "without nickname" do
32
+ it "creates #{component} with nickname :default" do
33
+ Migratrix::Migratrix.should_receive(component).with(:default, :no_op, {opt: 2})
34
+ TestMigration.send "set_#{component}", :no_op, {opt: 2}
35
+ end
36
+ end
37
+
38
+ describe "without options or nickname" do
39
+ it "creates #{component} with nickname :default and empty options hash" do
40
+ Migratrix::Migratrix.should_receive(component).with(:default, :no_op, {})
41
+ TestMigration.send "set_#{component}", :no_op
42
+ end
43
+ end
44
+ end
45
+ end
46
+
33
47
  describe "with mocked components" do
34
48
  let(:map) { { :id => :id, :name => :name }}
35
49
  let(:extraction) {
@@ -162,7 +176,7 @@ describe Migratrix::Migration do
162
176
  end
163
177
  end
164
178
 
165
- describe "extending" do
179
+ describe "with inheritance" do
166
180
  before do
167
181
  [TestMigration, ChildMigration1, ChildMigration2, GrandchildMigration1].each do |klass|
168
182
  [:extractions, :transforms, :loads].each do |kollection|
@@ -172,56 +186,68 @@ describe Migratrix::Migration do
172
186
  TestMigration.set_extraction :cheese, :extraction, { first_option: 'id>100' }
173
187
  TestMigration.set_transform :cheese, :transform, { first_option: 'id>100' }
174
188
  TestMigration.set_load :cheese, :load, { first_option: 'id>100' }
175
-
176
189
  end
177
190
 
178
- [:extraction, :transform, :load ].each do |component|
179
- describe "#{component}" do
180
- it "extends the #{component} to child class" do
181
- ChildMigration1.send("extend_#{component}", :cheese, { second_option: 2 })
182
- ChildMigration1.new.send("#{component}s")[:cheese].options.should == { second_option: 2, first_option: 'id>100'}
183
- end
184
-
185
- it "extends the #{component} to the grandchild class" do
186
- ChildMigration1.send("extend_#{component}", :cheese, { second_option: 2 })
187
- GrandchildMigration1.send("extend_#{component}", :cheese, { surprise_option: 50 })
188
- GrandchildMigration1.new.send("#{component}s")[:cheese].options.should == { second_option: 2, first_option: 'id>100', surprise_option: 50 }
189
- end
190
-
191
- it "extends the #{component} to the grandchild class even if the child class does not extend" do
192
- GrandchildMigration1.send("extend_#{component}", :cheese, { surprise_option: 50 })
193
- GrandchildMigration1.new.send("#{component}s")[:cheese].options.should == { first_option: 'id>100', surprise_option: 50 }
191
+ describe "extending" do
192
+ [:extraction, :transform, :load ].each do |component|
193
+ describe "#{component}" do
194
+ it "extends the #{component} to child class" do
195
+ ChildMigration1.send("extend_#{component}", :cheese, { second_option: 2 })
196
+ ChildMigration1.new.send("#{component}s")[:cheese].options.should == { second_option: 2, first_option: 'id>100'}
197
+ end
198
+
199
+ it "extends the #{component} to the grandchild class" do
200
+ ChildMigration1.send("extend_#{component}", :cheese, { second_option: 2 })
201
+ GrandchildMigration1.send("extend_#{component}", :cheese, { surprise_option: 50 })
202
+ GrandchildMigration1.new.send("#{component}s")[:cheese].options.should == { second_option: 2, first_option: 'id>100', surprise_option: 50 }
203
+ end
204
+
205
+ it "extends the #{component} to the grandchild class even if the child class does not extend" do
206
+ GrandchildMigration1.send("extend_#{component}", :cheese, { surprise_option: 50 })
207
+ GrandchildMigration1.new.send("#{component}s")[:cheese].options.should == { first_option: 'id>100', surprise_option: 50 }
208
+ end
209
+
210
+ it "overrides parent options" do
211
+ ChildMigration1.send("extend_#{component}", :cheese, { second_option: 2, first_option: 'id>50' })
212
+ ChildMigration1.new.send("#{component}s")[:cheese].options.should == { second_option: 2, first_option: 'id>50'}
213
+ end
214
+
215
+ it "does not affect sibling class options" do
216
+ ChildMigration1.send("extend_#{component}", :cheese, { second_option: 2, first_option: 'id>50' })
217
+ ChildMigration2.send("extend_#{component}", :cheese, { zany_option: Hash, first_option: 'id>75' })
218
+ ChildMigration1.new.send("#{component}s")[:cheese].options.should == { second_option: 2, first_option: 'id>50'}
219
+ ChildMigration2.new.send("#{component}s")[:cheese].options.should == { zany_option: Hash, first_option: 'id>75'}
220
+ end
221
+
222
+ it "does not affect parent class options" do
223
+ ChildMigration1.send("extend_#{component}", :cheese, { second_option: 2, first_option: 'id>50' })
224
+ ChildMigration1.new.send("#{component}s")[:cheese].options.should == { second_option: 2, first_option: 'id>50'}
225
+ TestMigration.new.send("#{component}s")[:cheese].options.should == { first_option: 'id>100'}
226
+ end
227
+
228
+ it "raises #{component.capitalize}NotDefined if no parent has that #{component}" do
229
+ exception = "Migratrix::#{component.capitalize}NotDefined".constantize
230
+ lambda { ChildMigration1.send("extend_#{component}", :blargle, { second_option: 2, first_option: 'id>50' }) }.should raise_error(exception)
231
+ end
194
232
  end
233
+ end
234
+ end
195
235
 
196
- it "overrides parent options" do
197
- ChildMigration1.send("extend_#{component}", :cheese, { second_option: 2, first_option: 'id>50' })
198
- ChildMigration1.new.send("#{component}s")[:cheese].options.should == { second_option: 2, first_option: 'id>50'}
199
- end
236
+ [:extraction, :transform, :load].each do |component|
237
+ describe "#{component}s" do
238
+ let(:opts) { { opts_option: 'id>100' } }
200
239
 
201
- it "does not affect sibling class options" do
202
- ChildMigration1.send("extend_#{component}", :cheese, { second_option: 2, first_option: 'id>50' })
203
- ChildMigration2.send("extend_#{component}", :cheese, { zany_option: Hash, first_option: 'id>75' })
204
- ChildMigration1.new.send("#{component}s")[:cheese].options.should == { second_option: 2, first_option: 'id>50'}
205
- ChildMigration2.new.send("#{component}s")[:cheese].options.should == { zany_option: Hash, first_option: 'id>75'}
240
+ it "inherit from ancestor #{component}s" do
241
+ GrandchildMigration1.send("#{component}s").should == TestMigration.send("#{component}s")
206
242
  end
207
243
 
208
- it "does not affect parent class options" do
209
- ChildMigration1.send("extend_#{component}", :cheese, { second_option: 2, first_option: 'id>50' })
210
- ChildMigration1.new.send("#{component}s")[:cheese].options.should == { second_option: 2, first_option: 'id>50'}
211
- TestMigration.new.send("#{component}s")[:cheese].options.should == { first_option: 'id>100'}
212
- end
213
-
214
- it "raises #{component.capitalize}NotDefined if no parent has that #{component}" do
215
- exception = "Migratrix::#{component.capitalize}NotDefined".constantize
216
- lambda { ChildMigration1.send("extend_#{component}", :blargle, { second_option: 2, first_option: 'id>50' }) }.should raise_error(exception)
244
+ it "are merged with ancestor #{component}s" do
245
+ GrandchildMigration1.send "set_#{component}", :wine, component, opts
246
+ my_component = GrandchildMigration1.send("#{component}s")[:wine]
247
+ GrandchildMigration1.send("#{component}s").should == TestMigration.send("#{component}s").merge( { wine: my_component })
217
248
  end
218
249
  end
219
250
  end
220
-
221
-
222
- # TODO: lambdas cannot be deep-copied, and form closures at the
223
- # time of creation. Is there a way to detect if a lambda has a
224
- # closure?
225
251
  end
226
252
  end
227
253
 
@@ -77,7 +77,7 @@ describe Migratrix::Migratrix do
77
77
  end
78
78
 
79
79
  describe "with logger as a singleton" do
80
- let (:migration) { Migratrix::MarblesMigration.new }
80
+ let (:migration) { Migratrix::Migration.new }
81
81
  let (:buffer) { StringIO.new }
82
82
 
83
83
  def spec_all_loggers_are(this_logger)
@@ -85,7 +85,7 @@ describe Migratrix::Migratrix do
85
85
  Migratrix::Migratrix.logger.should == this_logger
86
86
  migratrix.logger.should == this_logger
87
87
  migration.logger.should == this_logger
88
- Migratrix::MarblesMigration.logger.should == this_logger
88
+ Migratrix::Migration.logger.should == this_logger
89
89
  end
90
90
 
91
91
  describe ".logger=" do
data/spec/spec_helper.rb CHANGED
@@ -28,7 +28,9 @@ Dir[SPEC + "support/**/*.rb"].each {|f| require f}
28
28
 
29
29
  require LIB + 'migratrix'
30
30
 
31
- require SPEC + "fixtures/migrations/marbles_migration"
31
+ $:.unshift SPEC + "fixtures/migrations/"
32
+ $:.unshift SPEC + "fixtures/components/"
33
+
32
34
 
33
35
  # Redirect singleton logger to logger of our choice, then release it
34
36
  # after the spec finishes or crashes.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: migratrix
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.8.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-25 00:00:00.000000000Z
12
+ date: 2011-10-26 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: trollop
16
- requirement: &2152828360 !ruby/object:Gem::Requirement
16
+ requirement: &2161676040 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2152828360
24
+ version_requirements: *2161676040
25
25
  description: Migratrix, a Rails legacy database migration tool supporting multiple
26
26
  strategies, including arbitrary n-ary migrations (1->n, n->1, n->m), arbitrary inputs
27
27
  and outputs (ActiveRecord, bare SQL, CSV) and migration logging
@@ -54,7 +54,9 @@ files:
54
54
  - lib/patches/andand.rb
55
55
  - lib/patches/object_ext.rb
56
56
  - lib/patches/string_ext.rb
57
- - spec/fixtures/migrations/marbles_migration.rb
57
+ - spec/fixtures/components/no_op_components.rb
58
+ - spec/fixtures/migrations/inherited_migrations.rb
59
+ - spec/fixtures/migrations/test_migration.rb
58
60
  - spec/lib/migratrix/_loggable_spec.rb
59
61
  - spec/lib/migratrix/callbacks_spec.rb
60
62
  - spec/lib/migratrix/extractions/active_record_spec.rb
@@ -1,19 +0,0 @@
1
- module Migratrix
2
- # Fake migration fixture for "Marbles"
3
- class MarblesMigration < Migration
4
- # :nocov: # because we play some games with file loading/unloading, SimpleCov often misses lines in this file
5
- def initialize(options={})
6
- super
7
- @migrated = false
8
- end
9
-
10
- def migrate
11
- @migrated = true
12
- end
13
-
14
- def migrated?
15
- @migrated
16
- end
17
- # :nocov:
18
- end
19
- end