migratrix 0.0.9 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
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
+