migratrix 0.0.9 → 0.8.1

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.
Files changed (31) hide show
  1. data/lib/migratrix.rb +62 -6
  2. data/lib/migratrix/exceptions.rb +4 -1
  3. data/lib/migratrix/{extractors → extractions}/active_record.rb +14 -10
  4. data/lib/migratrix/{extractors/extractor.rb → extractions/extraction.rb} +21 -20
  5. data/lib/migratrix/loads/load.rb +43 -0
  6. data/lib/migratrix/loads/yaml.rb +15 -0
  7. data/lib/migratrix/migration.rb +115 -27
  8. data/lib/migratrix/migratrix.rb +43 -84
  9. data/lib/migratrix/registry.rb +20 -0
  10. data/lib/migratrix/transforms/map.rb +57 -0
  11. data/lib/migratrix/transforms/transform.rb +268 -0
  12. data/lib/migratrix/valid_options.rb +22 -0
  13. data/lib/patches/object_ext.rb +0 -4
  14. data/spec/fixtures/migrations/marbles_migration.rb +6 -4
  15. data/spec/lib/migratrix/{loggable_spec.rb → _loggable_spec.rb} +0 -0
  16. data/spec/lib/migratrix/extractions/active_record_spec.rb +146 -0
  17. data/spec/lib/migratrix/extractions/extraction_spec.rb +71 -0
  18. data/spec/lib/migratrix/loads/load_spec.rb +59 -0
  19. data/spec/lib/migratrix/loads/yaml_spec.rb +39 -0
  20. data/spec/lib/migratrix/migration_spec.rb +195 -27
  21. data/spec/lib/migratrix/migratrix_spec.rb +57 -85
  22. data/spec/lib/migratrix/registry_spec.rb +28 -0
  23. data/spec/lib/migratrix/transforms/map_spec.rb +55 -0
  24. data/spec/lib/migratrix/transforms/transform_spec.rb +134 -0
  25. data/spec/lib/migratrix_spec.rb +98 -0
  26. data/spec/lib/patches/object_ext_spec.rb +0 -7
  27. data/spec/spec_helper.rb +18 -13
  28. metadata +21 -10
  29. data/spec/lib/migratrix/extractors/active_record_spec.rb +0 -43
  30. data/spec/lib/migratrix/extractors/extractor_spec.rb +0 -63
  31. data/spec/lib/migratrix_module_spec.rb +0 -63
@@ -1,106 +1,83 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Migratrix::Migratrix do
4
- let (:migratrix) { Migratrix::Migratrix.new }
5
-
6
- it "exists (sanity check)" do
7
- Migratrix.should_not be_nil
8
- Migratrix.class.should == Module
9
- Migratrix.class.should_not == Class
10
- Migratrix::Migratrix.class.should_not == Module
11
- Migratrix::Migratrix.class.should == Class
12
- Migratrix.const_defined?("Migratrix").should be_true
13
- end
14
-
15
- describe "MigrationRegistry (needs to be extracted)" do
16
- before do
17
- reset_migratrix! migratrix
18
- Migratrix.class_eval("class PantsMigration < Migration; end")
19
- migratrix.register_migration "PantsMigration", Migratrix::PantsMigration
20
- end
21
-
22
- it "can register migrations by name" do
23
- migratrix.loaded?("PantsMigration").should be_true
24
- Migratrix.const_defined?("PantsMigration").should be_true
25
- end
3
+ class TestExtraction < Migratrix::Extractions::Extraction
4
+ end
26
5
 
27
- it "can fetch registered migration class" do
28
- migratrix.fetch_migration("PantsMigration").should == Migratrix::PantsMigration
29
- end
6
+ class TestTransform < Migratrix::Transforms::Transform
7
+ end
30
8
 
31
- it "raises fetch error when fetching unregistered migration" do
32
- lambda { migratrix.fetch_migration("arglebargle") }.should raise_error(KeyError)
33
- end
34
- end
9
+ class TestLoad < Migratrix::Loads::Load
10
+ end
35
11
 
36
- describe ".migrations_path" do
37
- it "uses ./db/legacy by default" do
38
- migratrix.migrations_path.should == ROOT + "db/legacy"
39
- end
12
+ describe Migratrix::Migratrix do
13
+ let (:migratrix) { Migratrix::Migratrix.new }
40
14
 
41
- it "can be overridden" do
42
- migratrix.migrations_path = Pathname.new('/tmp')
43
- migratrix.migrations_path.should == Pathname.new("/tmp")
15
+ describe "sanity check cat" do
16
+ it "is sanity checked" do
17
+ Migratrix.should_not be_nil
18
+ Migratrix.class.should == Module
19
+ Migratrix.class.should_not == Class
20
+ Migratrix::Migratrix.class.should_not == Module
21
+ Migratrix::Migratrix.class.should == Class
22
+ Migratrix.const_defined?("Migratrix").should be_true
44
23
  end
45
24
  end
46
25
 
47
- describe "#valid_options" do
48
- it "returns the valid set of option keys" do
49
- migratrix.valid_options.should == ["limit", "offset", "order", "where"]
50
- end
51
- end
26
+ describe "Migration Component Registry" do
27
+ describe ".register_extraction" do
28
+ before do
29
+ Migratrix::Migratrix.register_extraction :test_extraction, TestExtraction, { :source => Object }
30
+ end
52
31
 
53
- describe "#filter_options" do
54
- it "filters out invalid options" do
55
- options = migratrix.filter_options({ "pants" => 42, "limit" => 3})
56
- options["limit"].should == 3
57
- options.should_not have_key("pants")
58
- end
59
- end
32
+ it "registers the extraction" do
33
+ Migratrix::Migratrix.extractions.registered?(:test_extraction).should be_true
34
+ Migratrix::Migratrix.extractions.class_for(:test_extraction).should == TestExtraction
35
+ end
60
36
 
61
- describe "#migration_name" do
62
- it "classifies the name and adds Migration" do
63
- migratrix.migration_name("shirt").should == "ShirtMigration"
37
+ it "creates the extraction with given options" do
38
+ extraction = TestExtraction.new :test
39
+ Migratrix::Migratrix.extractions.registered?(:test_extraction).should be_true
40
+ Migratrix::Migratrix.extractions.class_for(:test_extraction).should == TestExtraction
41
+ end
64
42
  end
65
43
 
66
- it "handles symbols" do
67
- migratrix.migration_name(:socks).should == "SocksMigration"
68
- end
44
+ describe ".register_transform" do
45
+ before do
46
+ Migratrix::Migratrix.register_transform :test_transform, TestTransform, { :source => Object }
47
+ end
69
48
 
70
- it "preserves pluralization" do
71
- migratrix.migration_name(:pants).should == "PantsMigration"
72
- migratrix.migration_name(:shirts).should == "ShirtsMigration"
73
- end
74
- end
49
+ it "registers the transform" do
50
+ Migratrix::Migratrix.transforms.registered?(:test_transform).should be_true
51
+ Migratrix::Migratrix.transforms.class_for(:test_transform).should == TestTransform
52
+ end
75
53
 
76
- describe "#create_migration" do
77
- before do
78
- reset_migratrix! migratrix
79
- migratrix.migrations_path = SPEC + "fixtures/migrations"
54
+ it "creates the transform with given options" do
55
+ transform = TestTransform.new :monkeys
56
+ Migratrix::Migratrix.transforms.registered?(:test_transform).should be_true
57
+ Migratrix::Migratrix.transforms.class_for(:test_transform).should == TestTransform
58
+ end
80
59
  end
81
60
 
82
- it "creates new migration by name with filtered options" do
83
- migration = migratrix.create_migration :marbles, { "cheese" => 42, "where" => "id > 100", "limit" => "100" }
84
- migration.class.should == Migratrix::MarblesMigration
85
- Migratrix::MarblesMigration.should_not be_migrated
86
- migration.options.should == { "where" => "id > 100", "limit" => "100" }
87
- end
88
- end
61
+ describe ".register_load" do
62
+ before do
63
+ Migratrix::Migratrix.register_load :test_load, TestLoad
64
+ end
89
65
 
90
- describe ".migrate" do
91
- before do
92
- reset_migratrix! migratrix
93
- migratrix.migrations_path = SPEC + "fixtures/migrations"
94
- end
66
+ it "registers the load" do
67
+ Migratrix::Migratrix.loads.registered?(:test_load).should be_true
68
+ Migratrix::Migratrix.loads.class_for(:test_load).should == TestLoad
69
+ end
95
70
 
96
- it "loads migration and migrates it" do
97
- Migratrix::Migratrix.stub!(:new).and_return(migratrix)
98
- Migratrix::Migratrix.migrate :marbles
71
+ it "creates the load with given options" do
72
+ load = TestLoad.new :monkeys
73
+ Migratrix::Migratrix.loads.registered?(:test_load).should be_true
74
+ Migratrix::Migratrix.loads.class_for(:test_load).should == TestLoad
75
+ end
99
76
  end
100
77
  end
101
78
 
102
79
  describe "with logger as a singleton" do
103
- let (:migration) { migratrix.create_migration :marbles }
80
+ let (:migration) { Migratrix::MarblesMigration.new }
104
81
  let (:buffer) { StringIO.new }
105
82
 
106
83
  def spec_all_loggers_are(this_logger)
@@ -111,11 +88,6 @@ describe Migratrix::Migratrix do
111
88
  Migratrix::MarblesMigration.logger.should == this_logger
112
89
  end
113
90
 
114
- before do
115
- reset_migratrix! migratrix
116
- migratrix.migrations_path = SPEC + "fixtures/migrations"
117
- end
118
-
119
91
  describe ".logger=" do
120
92
  it "sets logger globally across all Migratrices, the Migratrix module, Migrators and Models" do
121
93
  logger = Migratrix::Migratrix.create_logger(buffer)
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Migratrix::Registry do
4
+ describe "sanity check cat" do
5
+ it "is sanity checked" do
6
+ ::Migratrix::Registry.should_not be_nil
7
+ end
8
+ end
9
+
10
+ describe "#register" do
11
+ let(:registry) { ::Migratrix::Registry.new }
12
+ before do
13
+ registry.register(:test, Array, 3)
14
+ end
15
+
16
+ it "registers the class by name" do
17
+ registry.registered?(:test).should be_true
18
+ end
19
+
20
+ describe "#class_for" do
21
+ it "returns the registered class" do
22
+ registry.class_for(:test).should == Array
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ class TestMap < Migratrix::Transforms::Map
4
+ end
5
+
6
+ describe Migratrix::Transforms::Map do
7
+ describe "sanity check cat" do
8
+ it "is sanity checked" do
9
+ Migratrix::Transforms::Map.should_not be_nil
10
+ TestMap.should_not be_nil
11
+ end
12
+ end
13
+
14
+ let(:loggable) { TestMap.new(:loggable) }
15
+ it_should_behave_like "loggable"
16
+
17
+ describe ".local_valid_options" do
18
+ it "returns the valid set of option keys" do
19
+ Migratrix::Transforms::Map.local_valid_options.should == []
20
+ end
21
+ end
22
+
23
+ describe ".valid_options" do
24
+ it "returns the valide set of options plus those of the superclass" do
25
+ Migratrix::Transforms::Map.valid_options.should == Migratrix::Transforms::Transform.local_valid_options
26
+ end
27
+ end
28
+
29
+ describe "with pet types fixture" do
30
+ let(:extracted_pets) {
31
+ [
32
+ { :pet_type_id => 42, :pet_species => 'Dog' },
33
+ { :pet_type_id => 43, :pet_species => 'Cat' },
34
+ { :pet_type_id => 44, :pet_species => 'Rat' },
35
+ { :pet_type_id => 45, :pet_species => 'Parrot' }
36
+ ]
37
+ }
38
+ let(:map) { { :id => :pet_type_id, :name => :pet_species } }
39
+ let(:expected_transform) { {
40
+ 42 => { :id => 42, :name => 'Dog' },
41
+ 43 => { :id => 43, :name => 'Cat' },
42
+ 44 => { :id => 44, :name => 'Rat' },
43
+ 45 => { :id => 45, :name => 'Parrot' }
44
+ }
45
+ }
46
+ let(:transform) { Migratrix::Transforms::Map.new(:pet_types, :transform => map) }
47
+
48
+ it "transforms data correctly" do
49
+ with_logging_to(StringIO.new) do
50
+ transform.transform(extracted_pets).should == expected_transform
51
+ end
52
+ end
53
+ end
54
+ end
55
+
@@ -0,0 +1,134 @@
1
+ require 'spec_helper'
2
+
3
+ class TestTransform < Migratrix::Transforms::Transform
4
+ include Migratrix::Loggable
5
+ end
6
+
7
+ describe Migratrix::Transforms::Transform do
8
+ describe "sanity check cat" do
9
+ it "is sanity checked" do
10
+ Migratrix::Transforms::Transform.should_not be_nil
11
+ TestTransform.should_not be_nil
12
+ end
13
+ end
14
+
15
+ let(:loggable) { TestTransform.new(:loggable) }
16
+ it_should_behave_like "loggable"
17
+
18
+ describe ".local_valid_options" do
19
+ it "returns the valid set of option keys" do
20
+ Migratrix::Transforms::Transform.local_valid_options.should == [:apply_attribute, :extract_attribute, :extraction, :final_class, :finalize_object, :store_transform, :target, :transform, :transform_class, :transform_collection]
21
+ end
22
+ end
23
+
24
+
25
+ describe "#extraction" do
26
+ it "returns extraction name when set" do
27
+ transform = Migratrix::Transforms::Transform.new(:pants_transform, { extraction: :pants_extraction })
28
+ transform.extraction.should == :pants_extraction
29
+ end
30
+
31
+ it "#returns transform name when no extraction name is set" do
32
+ transform = Migratrix::Transforms::Transform.new(:pants_transform)
33
+ transform.extraction.should == :pants_transform
34
+ end
35
+ end
36
+
37
+ describe "unimplemented methods:" do
38
+ [ [:create_transformed_collection, []],
39
+ [:create_new_object, [:extracted_row]],
40
+ [:apply_attribute, [:object, :value, :attribute_or_apply]],
41
+ [:extract_attribute, [:object, :attribute_or_extract]],
42
+ [:store_transformed_object, [:object, :collection]] ].each do |method, args|
43
+ describe "#{method}(#{args.map(&:inspect)*','})" do
44
+ let(:object_with_not_implemented_methods) { Migratrix::Transforms::Transform.new(:brain_damaged_transform) }
45
+ it "raises NotImplementedError" do
46
+ lambda { object_with_not_implemented_methods.send(method, *args) }.should raise_error(NotImplementedError)
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ describe "TypeError methods" do
53
+ [:transform_collection, :transform_class, :extract_attribute, :apply_attribute, :final_class, :finalize_object, :store_transformed_object].each do |method|
54
+ describe "With #{method} set to a string" do
55
+ let(:transform_options) { {
56
+ extraction: :test_stream,
57
+ transform: { id: :src_id, name: :src_name },
58
+ transform_collection: Array,
59
+ transform_class: Hash,
60
+ extract_attribute: ->(object, attribute) { object[attribute] },
61
+ apply_attribute: ->(object, attribute, value) { object[attribute] = value },
62
+ final_class: Set,
63
+ finalize_object: ->(object) { object.to_a },
64
+ store_transformed_object: :<<
65
+ }.merge( method => "cheese")
66
+ }
67
+ let(:transform) { TestTransform.new :test, transform_options }
68
+ let(:test_stream) { [{src_id: 42, src_name: "Alice"}, {src_id: 43, src_name: "Bob"} ] }
69
+ let(:extractions) { { test_stream: mock("extraction", name: "test_stream", extract: test_stream )}}
70
+
71
+ it "should raise TypeError" do
72
+ lambda { transform.transform(test_stream) }.should raise_error(TypeError)
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ describe "with Proc options" do
79
+ let(:transform) { TestTransform.new :test, {
80
+ extraction: :test_stream,
81
+ transform: { id: :src_id, name: :src_name },
82
+ transform_collection: ->{ Array.new },
83
+ transform_class: ->(row) { Hash.new },
84
+ extract_attribute: ->(object, attribute) { object[attribute] },
85
+ apply_attribute: ->(object, attribute, value) { object[attribute] = value },
86
+ final_class: Set,
87
+ finalize_object: ->(object) { object.to_a },
88
+ store_transformed_object: ->(object, collection) { collection << object }
89
+ }
90
+ }
91
+
92
+ let(:test_stream) { [{src_id: 42, src_name: "Alice"}, {src_id: 43, src_name: "Bob"} ] }
93
+ let(:extractions) { { test_stream: mock("extraction", name: "test_stream", extract: test_stream )}}
94
+
95
+ before do
96
+ TestTransform.stub!(:extractions).and_return(extractions)
97
+ end
98
+
99
+ it "should delegate to procs" do
100
+ transform.transform(test_stream).should == [
101
+ Set.new([[:id, 42], [:name, "Alice"]]),
102
+ Set.new([[:id, 43], [:name, "Bob"]])
103
+ ]
104
+ end
105
+ end
106
+
107
+ describe "with symbol and class options" do
108
+ let(:transform) { TestTransform.new :test, {
109
+ extraction: :test_stream,
110
+ transform: { id: :src_id, name: :src_name },
111
+ transform_collection: Array,
112
+ transform_class: Hash,
113
+ extract_attribute: :[],
114
+ apply_attribute: :[]=,
115
+ store_transformed_object: :<<
116
+ }
117
+ }
118
+
119
+ let(:test_stream) { [{src_id: 42, src_name: "Alice"}, {src_id: 43, src_name: "Bob"} ] }
120
+ let(:extractions) { { test_stream: mock("extraction", name: "test_stream", extract: test_stream )}}
121
+
122
+ before do
123
+ TestTransform.stub!(:extractions).and_return(extractions)
124
+ end
125
+
126
+ it "should delegate to procs" do
127
+ transform.transform(test_stream).should == [
128
+ {id: 42, name: "Alice"},
129
+ {id: 43, name: "Bob"}
130
+ ]
131
+ end
132
+ end
133
+ end
134
+
@@ -0,0 +1,98 @@
1
+ require 'spec_helper'
2
+
3
+ describe Migratrix do
4
+ describe "sanity check cat" do
5
+ it "is sanity checked" do
6
+ Migratrix.should_not be_nil
7
+ Migratrix.class.should == Module
8
+ end
9
+ end
10
+
11
+ describe "convenience delegator methods" do
12
+ def spec_delegates_to_migratrix_class(method, *args)
13
+ if args.size > 0
14
+ Migratrix::Migratrix.should_receive(method).with(*args).once
15
+ else
16
+ Migratrix::Migratrix.should_receive(method).once
17
+ end
18
+ Migratrix.send(method, *args)
19
+ end
20
+
21
+ describe ".logger" do
22
+ it "delegates to Migratrix::Migratrix" do
23
+ spec_delegates_to_migratrix_class :logger
24
+ end
25
+ end
26
+
27
+ describe ".logger=" do
28
+ let (:logger) { Logger.new(StringIO.new) }
29
+ it "delegates to Migratrix::Migratrix" do
30
+ spec_delegates_to_migratrix_class :logger=, logger
31
+ end
32
+ end
33
+
34
+ describe ".log_to" do
35
+ let (:buffer) { StringIO.new }
36
+ it "delegates to Migratrix::Migratrix" do
37
+ spec_delegates_to_migratrix_class :log_to, buffer
38
+ end
39
+ end
40
+
41
+ describe ".register_extraction" do
42
+ it "delegates to Migratrix::Migratrix" do
43
+ spec_delegates_to_migratrix_class :register_extraction, :marbles, Array, 3
44
+ end
45
+ end
46
+
47
+ describe ".extractions" do
48
+ it "delegates to Migratrix::Migratrix" do
49
+ spec_delegates_to_migratrix_class :extractions
50
+ end
51
+ end
52
+
53
+ describe ".register_transform" do
54
+ it "delegates to Migratrix::Migratrix" do
55
+ spec_delegates_to_migratrix_class :register_transform, :marbles, Array, 3
56
+ end
57
+ end
58
+
59
+ describe ".transforms" do
60
+ it "delegates to Migratrix::Migratrix" do
61
+ spec_delegates_to_migratrix_class :transforms
62
+ end
63
+ end
64
+
65
+ describe ".register_load" do
66
+ it "delegates to Migratrix::Migratrix" do
67
+ spec_delegates_to_migratrix_class :register_load, :marbles, Array, 3
68
+ end
69
+ end
70
+
71
+ describe ".loads" do
72
+ it "delegates to Migratrix::Migratrix" do
73
+ spec_delegates_to_migratrix_class :loads
74
+ end
75
+ end
76
+ end
77
+
78
+ describe "gem-installed components:" do
79
+ describe "extractions" do
80
+ it ":active_record is registered" do
81
+ Migratrix.extractions.class_for(:active_record).should == ::Migratrix::Extractions::ActiveRecord
82
+ end
83
+ end
84
+
85
+ describe "transforms" do
86
+ it ":transform is registered" do
87
+ Migratrix.transforms.class_for(:transform).should == ::Migratrix::Transforms::Transform
88
+ end
89
+
90
+ it ":map is registered" do
91
+ Migratrix.transforms.class_for(:map).should == ::Migratrix::Transforms::Map
92
+ end
93
+ end
94
+
95
+ # transforms: map, transform
96
+ end
97
+ end
98
+