activerecord-model-spaces 0.2.0

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,186 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'active_support/core_ext/class' # SchemaDumper needs this
4
+
5
+ require 'active_record/model_spaces/table_manager'
6
+
7
+ module ActiveRecord
8
+ module ModelSpaces
9
+
10
+ describe TableManager do
11
+
12
+ describe "initialize" do
13
+ it "should initialize with a model" do
14
+ m = double('model')
15
+ c = double('connection')
16
+ m.should_receive(:connection).and_return(c)
17
+ tm = TableManager.new(m)
18
+ tm.model.should == m
19
+ tm.connection.should == c
20
+ end
21
+
22
+ it "should initialize with a model name" do
23
+ c = double('connection')
24
+ ActiveRecord::ModelSpaces.should_receive(:connection).and_return(c)
25
+ tm = TableManager.new("ActiveRecord::ModelSpaces")
26
+ tm.model.should == ActiveRecord::ModelSpaces
27
+ tm.connection.should == c
28
+ end
29
+ end
30
+
31
+ def create_table_manager(model=nil)
32
+ model ||= double('model')
33
+ connection = double('connection')
34
+ model.stub(:connection).and_return(connection)
35
+ TableManager.new(model)
36
+ end
37
+
38
+ describe "create table" do
39
+ it "should extract the base_table schema, and use it to create a new table" do
40
+ tm = create_table_manager
41
+ tm.connection.should_receive(:table_exists?).with('bars')
42
+
43
+ tsc = double('table-schema-copier')
44
+ tm.should_receive(:get_table_schema_copier).with(tm.connection).and_return(tsc)
45
+
46
+ tsc.should_receive(:copy_table_schema).with(tm.connection, 'foos', 'bars')
47
+
48
+ tm.create_table('foos', 'bars')
49
+ end
50
+ end
51
+
52
+ describe "drop table" do
53
+ it "should drop the given table if it exists" do
54
+ tm = create_table_manager
55
+ tm.connection.should_receive(:table_exists?).with("foos").and_return(true)
56
+ tm.connection.should_receive(:execute).with("drop table foos")
57
+ tm.drop_table("foos")
58
+ end
59
+
60
+ it "should do nothing if the given table does not exist" do
61
+ tm = create_table_manager
62
+ tm.connection.should_receive(:table_exists?).with("foos").and_return(false)
63
+ tm.drop_table("foos")
64
+ end
65
+ end
66
+
67
+ describe "recreate table" do
68
+ it "should drop the table if it exists, and recreate it from the base table if the table_name is different from the base_table_name" do
69
+ tm = create_table_manager
70
+ tm.should_receive(:drop_table).with("bars")
71
+ tm.should_receive(:create_table).with("foos", "bars")
72
+ tm.recreate_table("foos", "bars")
73
+ end
74
+
75
+ it "should do nothing if the base_table_name is the same as the table_name" do
76
+ tm = create_table_manager
77
+ tm.recreate_table("foos", "foos")
78
+ end
79
+ end
80
+
81
+ describe "truncate table" do
82
+ it "should truncate the given table" do
83
+ tm = create_table_manager
84
+ tm.connection.should_receive(:execute).with("truncate table foos")
85
+ tm.truncate_table('foos')
86
+ end
87
+ end
88
+
89
+ describe "copy table" do
90
+ it "should copy data from the source to the target table if source and target are different" do
91
+ tm = create_table_manager
92
+ tm.connection.should_receive(:execute).with("insert into bars select * from foos")
93
+ tm.copy_table('foos', 'bars')
94
+ end
95
+
96
+ it "should do nothing if source and target are the same" do
97
+ tm = create_table_manager
98
+ tm.copy_table('foos', 'foos')
99
+ end
100
+ end
101
+
102
+ describe "get_table_schema_copier" do
103
+ it "should get a TableSchemaCopier specialised for the connection adapter, if available" do
104
+ c = double('connection')
105
+ c.stub(:adapter_name).and_return('MySQL')
106
+
107
+ tm = create_table_manager
108
+ tm.send(:get_table_schema_copier, c).should == MySQLTableSchemaCopier
109
+ end
110
+
111
+ it "should get a DefaultTableSchemaCopier if no specialised TableSchemaCopier available" do
112
+ c = double('connection')
113
+ c.stub(:adapter_name).and_return('Random')
114
+
115
+ tm = create_table_manager
116
+ tm.send(:get_table_schema_copier, c).should == DefaultTableSchemaCopier
117
+ end
118
+ end
119
+
120
+ describe MySQLTableSchemaCopier do
121
+
122
+ describe "copy_table_schema" do
123
+ it "should ask mysql for the create-table statement, modify it and execute the modified statement" do
124
+ c = double('connection')
125
+ c.should_receive(:select_rows).with("SHOW CREATE TABLE `foos`").and_return([["foos", "CREATE TABLE `foos` (blah)"]])
126
+ c.should_receive(:execute).with("CREATE TABLE `bars` (blah)")
127
+
128
+ MySQLTableSchemaCopier.copy_table_schema(c, "foos", "bars")
129
+ end
130
+ end
131
+
132
+ describe "table_schema" do
133
+ it "should ask mysql for the create-table statement for the table" do
134
+ c = double('connection')
135
+ c.should_receive(:select_rows).with("SHOW CREATE TABLE `foos`").and_return([["foos", "CREATE TABLE `foos` (blah)"]])
136
+ MySQLTableSchemaCopier.table_schema(c, "foos").should == "CREATE TABLE `foos` (blah)"
137
+ end
138
+ end
139
+
140
+ describe "change_table_name" do
141
+ it "should change the table name in the CREATE TABLE statement" do
142
+ MySQLTableSchemaCopier.change_table_name('foos', 'bars', "CREATE TABLE `foos` (blah)").should ==
143
+ "CREATE TABLE `bars` (blah)"
144
+ end
145
+ end
146
+
147
+ end
148
+
149
+ describe DefaultTableSchemaCopier do
150
+
151
+ describe "copy_table_schema" do
152
+ it "should extract ruby schema, modify and eval it to create a new table" do
153
+ c = double('connection')
154
+ c.should_receive(:instance_eval).with('create_table "bars" ()')
155
+
156
+ DefaultTableSchemaCopier.should_receive(:table_schema).with(c, "foos").and_return('create_table "foos" ()')
157
+
158
+ DefaultTableSchemaCopier.copy_table_schema(c, "foos", "bars")
159
+ end
160
+ end
161
+
162
+ describe "table_schema" do
163
+ it "should use the schema dumper to retrieve ruby code to create a table" do
164
+ c = double('connection')
165
+
166
+ sd = double('schema-dumper')
167
+ ActiveRecord::SchemaDumper.should_receive(:new).with(c).and_return(sd)
168
+
169
+ sd.should_receive(:table).with('foos', anything).and_return(StringIO.new('create_table "foos" ()'))
170
+
171
+ DefaultTableSchemaCopier.table_schema(c, "foos").should == 'create_table "foos" ()'
172
+ end
173
+ end
174
+
175
+ describe "change_table_name" do
176
+ it "should alter the provided schema generating code to change the table_name" do
177
+ tm = create_table_manager
178
+ DefaultTableSchemaCopier.change_table_name( "foos", "bars", 'create_table "foos" (blahblah)\nadd_index "foos" blahblah').should ==
179
+ 'create_table "bars" (blahblah)\nadd_index "bars" blahblah'
180
+ end
181
+ end
182
+
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,90 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'active_record/model_spaces/table_names'
4
+ module ActiveRecord
5
+ module ModelSpaces
6
+ describe TableNames do
7
+
8
+ describe "base_table_name" do
9
+ it "should underscore and pluralize the classname" do
10
+ TableNames.base_table_name("FooBar").should == "foo_bars"
11
+ end
12
+
13
+ it "should remove module names" do
14
+ TableNames.base_table_name(ModelSpaces).should == "model_spaces"
15
+ end
16
+ end
17
+
18
+ describe "model_space_table_name" do
19
+ it "should return base_table_name if no model-space or model-space-key given" do
20
+ TableNames.model_space_table_name(nil, nil, "foo_bars").should == "foo_bars"
21
+ end
22
+
23
+ it "should return base_table_name if an empty model-space and model-space-key given" do
24
+ TableNames.model_space_table_name("", "", "foo_bars").should == "foo_bars"
25
+ end
26
+
27
+ it "should prefix with model-space-name if given alone" do
28
+ TableNames.model_space_table_name("blarghl", nil, "foo_bars").should == "blarghl__foo_bars"
29
+ end
30
+
31
+ it "should prefix a model-space-name and model-space-key if bothgiven" do
32
+ TableNames.model_space_table_name("blarghl", "one", "foo_bars").should == "blarghl__one__foo_bars"
33
+ end
34
+
35
+ it "should raise an error if a model-space-key is given without a model-space-name" do
36
+
37
+ expect {
38
+ TableNames.model_space_table_name(nil, "one", "FooBar")
39
+ }.to raise_error /model_space_key cannot be non-empty if model_space_name is empty/
40
+
41
+ end
42
+ end
43
+
44
+ describe "table_name" do
45
+ it "should always suffix version provided if non-nil and >0" do
46
+ TableNames.table_name("blarghl", "one", "foo_bars", nil, nil).should == "blarghl__one__foo_bars"
47
+ TableNames.table_name("blarghl", "one", "foo_bars", nil, 1).should == "blarghl__one__foo_bars__1"
48
+ TableNames.table_name("blarghl", "one", "foo_bars", 0, nil).should == "blarghl__one__foo_bars"
49
+ TableNames.table_name("blarghl", "one", "foo_bars", 0, 1).should == "blarghl__one__foo_bars__1"
50
+
51
+ TableNames.table_name("blarghl", "one", "foo_bars", 1, 0).should == "blarghl__one__foo_bars"
52
+ TableNames.table_name("blarghl", "one", "foo_bars", 1, 1).should == "blarghl__one__foo_bars__1"
53
+ TableNames.table_name("blarghl", "one", "foo_bars", 1, 2).should == "blarghl__one__foo_bars__2"
54
+ TableNames.table_name("blarghl", "one", "foo_bars", 1, 3).should == "blarghl__one__foo_bars__3"
55
+
56
+ TableNames.table_name("blarghl", "one", "foo_bars", 2, 0).should == "blarghl__one__foo_bars"
57
+ TableNames.table_name("blarghl", "one", "foo_bars", 2, 1).should == "blarghl__one__foo_bars__1"
58
+ TableNames.table_name("blarghl", "one", "foo_bars", 2, 2).should == "blarghl__one__foo_bars__2"
59
+ TableNames.table_name("blarghl", "one", "foo_bars", 2, 3).should == "blarghl__one__foo_bars__3"
60
+ TableNames.table_name("blarghl", "one", "foo_bars", 2, 4).should == "blarghl__one__foo_bars__4"
61
+ end
62
+ end
63
+
64
+ describe "next_version" do
65
+ it "should return the next version" do
66
+ TableNames.next_version(nil, nil).should == 0
67
+ TableNames.next_version(nil, 0).should == 0
68
+ TableNames.next_version(nil, 1).should == 0
69
+
70
+ TableNames.next_version(0, nil).should == 0
71
+ TableNames.next_version(0, 0).should == 0
72
+ TableNames.next_version(0, 1).should == 0
73
+
74
+ TableNames.next_version(1, nil).should == 1
75
+ TableNames.next_version(1, 0).should == 1
76
+ TableNames.next_version(1, 1).should == 0
77
+ TableNames.next_version(1, 2).should == 1
78
+
79
+ TableNames.next_version(2, nil).should == 1
80
+ TableNames.next_version(2, 0).should == 1
81
+ TableNames.next_version(2, 1).should == 2
82
+ TableNames.next_version(2, 2).should == 0
83
+ TableNames.next_version(2, 3).should == 1
84
+ end
85
+ end
86
+
87
+
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,106 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'active_record'
4
+ require 'active_record/model_spaces/util'
5
+
6
+ module ActiveRecord
7
+ module ModelSpaces
8
+
9
+ describe Util do
10
+
11
+ describe "name_from_model" do
12
+ it "should stringify the model" do
13
+ m = double('model')
14
+ mk = double('model-key')
15
+ m.should_receive(:to_s).and_return(mk)
16
+ Util.name_from_model(m).should == mk
17
+ end
18
+
19
+ end
20
+
21
+ describe "model_from_name" do
22
+ it "should return the model class from the classname" do
23
+ Util.model_from_name("ActiveRecord::ModelSpaces").should == ActiveRecord::ModelSpaces
24
+ end
25
+
26
+ it "should do nothing if given a model class" do
27
+ Util.model_from_name(ActiveRecord::ModelSpaces).should == ActiveRecord::ModelSpaces
28
+ end
29
+ end
30
+
31
+ describe "require_for_classname" do
32
+ it "should require a file based on the classname then eval the classname to get the class" do
33
+ Kernel.should_receive(:require).with('active_record/model_spaces/foo_table_schema_copier')
34
+ klass = double('the-class')
35
+ Kernel.should_receive(:eval).with("ActiveRecord::ModelSpaces::FooTableSchemaCopier").and_return(klass)
36
+ Util.require_for_classname("ActiveRecord::ModelSpaces::FooTableSchemaCopier").should == klass
37
+ end
38
+
39
+ it "should return false in the case of any error" do
40
+ Kernel.should_receive(:require).with('active_record/model_spaces/foo_table_schema_copier').and_return{raise "boo"}
41
+ Util.require_for_classname("ActiveRecord::ModelSpaces::FooTableSchemaCopier").should == false
42
+ end
43
+ end
44
+
45
+ describe "class_for_classname" do
46
+ it "should eval a classname to get a class" do
47
+ klass = double('the-class')
48
+ Kernel.should_receive(:eval).with("ActiveRecord::ModelSpaces::FooTableSchemaCopier").and_return(klass)
49
+
50
+ Util.class_for_classname("ActiveRecord::ModelSpaces::FooTableSchemaCopier").should == klass
51
+ end
52
+
53
+ it "should return false in the case of any error" do
54
+ Kernel.should_receive(:eval).with("ActiveRecord::ModelSpaces::FooTableSchemaCopier").and_return{raise "boo"}
55
+ Util.class_for_classname("ActiveRecord::ModelSpaces::FooTableSchemaCopier").should == false
56
+ end
57
+ end
58
+
59
+ describe "class_from_classname" do
60
+ it "should try class_for_classname then require_for_classname to find a class" do
61
+ klass = double('the-class')
62
+
63
+ Kernel.should_receive(:eval).with("ActiveRecord::ModelSpaces::FooTableSchemaCopier").and_return{raise "boo"}
64
+
65
+ Kernel.should_receive(:require).with('active_record/model_spaces/foo_table_schema_copier').and_return do
66
+ Kernel.rspec_reset
67
+ Kernel.should_receive(:eval).with("ActiveRecord::ModelSpaces::FooTableSchemaCopier").and_return(klass)
68
+ end
69
+
70
+ Util.class_from_classname("ActiveRecord::ModelSpaces::FooTableSchemaCopier").should == klass
71
+ end
72
+ end
73
+
74
+ describe "all_model_superclasses" do
75
+ it "should return an ordered list of all model superclasses of a class" do
76
+ c1 = Class.new(ActiveRecord::Base)
77
+ c2 = Class.new(c1)
78
+ c3 = Class.new(c2)
79
+
80
+ Util.all_model_superclasses(c3).should == [c3,c2,c1]
81
+ end
82
+ end
83
+
84
+ describe "is_active_record_model?" do
85
+ it "should return true for direct or indirect subclasses of ActiveRecord::Base" do
86
+ c1 = Class.new(ActiveRecord::Base)
87
+ Util.is_active_record_model?(c1).should == true
88
+
89
+ c2 = Class.new(c1)
90
+ Util.is_active_record_model?(c2).should ==true
91
+ end
92
+
93
+ it "should return false for non-subclasses of ActiveRecord::Base" do
94
+ Util.is_active_record_model?(ActiveRecord::Base).should == false
95
+
96
+ c1 = Class.new
97
+ Util.is_active_record_model?(c1).should == false
98
+
99
+ c2 = Class.new
100
+ Util.is_active_record_model?(c2).should == false
101
+ end
102
+ end
103
+
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,116 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module ActiveRecord
4
+ describe ModelSpaces do
5
+
6
+ describe "with_context" do
7
+ it "should pass with_context calls to the registry" do
8
+ ModelSpaces::REGISTRY.should_receive(:with_context).and_return do |model_space_name, model_space_key, &block|
9
+ model_space_name.should == :foo_space
10
+ model_space_key.should == :one
11
+ block.call
12
+ end
13
+
14
+ ModelSpaces.with_context(:foo_space, :one) do
15
+ :result
16
+ end.should == :result
17
+ end
18
+ end
19
+
20
+ describe "active_key" do
21
+ it "should pass active_key calls to the registry" do
22
+ ModelSpaces::REGISTRY.should_receive(:active_key).with(:foo_space)
23
+ ModelSpaces.active_key(:foo_space)
24
+ end
25
+ end
26
+
27
+ describe "kill_context" do
28
+ it "should pass kill_context calls to the registry" do
29
+ ModelSpaces::REGISTRY.should_receive(:kill_context).with(:foo_space, :one)
30
+ ModelSpaces.kill_context(:foo_space, :one)
31
+ end
32
+ end
33
+
34
+ describe "enforce_context" do
35
+ it "should pass enforce_contrext calls to the registry" do
36
+ ec = double('enforce-context')
37
+ ModelSpaces::REGISTRY.should_receive(:enforce_context).and_return(ec)
38
+ ModelSpaces.enforce_context.should == ec
39
+ end
40
+ end
41
+
42
+ describe "set_enforce_context" do
43
+ it "should pass set_enforce_context calls to the registry" do
44
+ ec = double('enforce-context')
45
+ ModelSpaces::REGISTRY.should_receive(:set_enforce_context).with(ec)
46
+ ModelSpaces.set_enforce_context(ec)
47
+ end
48
+ end
49
+
50
+ def create_model_spaces_class
51
+ klass = Class.new
52
+ klass.class_eval do
53
+ include ActiveRecord::ModelSpaces
54
+ end
55
+ klass
56
+ end
57
+
58
+ it "should pass set_table_name calls to the registry" do
59
+ klass = create_model_spaces_class
60
+ ModelSpaces::REGISTRY.should_receive(:set_base_table_name).with(klass, "random_models")
61
+ klass.set_table_name("random_models")
62
+ end
63
+
64
+ it "should pass table_name= calls to the registry" do
65
+ klass = create_model_spaces_class
66
+ ModelSpaces::REGISTRY.should_receive(:set_base_table_name).with(klass, "random_models")
67
+ klass.table_name = "random_models"
68
+ end
69
+
70
+ it "should pass in_model_space calls to the registry" do
71
+ klass = create_model_spaces_class
72
+ ModelSpaces::REGISTRY.should_receive(:register_model).with(klass, :foo_space, {})
73
+ klass.in_model_space :foo_space
74
+ end
75
+
76
+ it "should pass table_name calls to the registry" do
77
+ klass = create_model_spaces_class
78
+ ModelSpaces::REGISTRY.should_receive(:table_name).with(klass).and_return("foos")
79
+ klass.table_name.should == "foos"
80
+ end
81
+
82
+ it "should pass current_table_name calls to the registry" do
83
+ klass = create_model_spaces_class
84
+ ModelSpaces::REGISTRY.should_receive(:current_table_name).with(klass).and_return("foos")
85
+ klass.current_table_name.should == "foos"
86
+ end
87
+
88
+ it "should pass working_table_name calls to the registry" do
89
+ klass = create_model_spaces_class
90
+ ModelSpaces::REGISTRY.should_receive(:working_table_name).with(klass).and_return("foos")
91
+ klass.working_table_name.should == "foos"
92
+ end
93
+
94
+ it "should pass new_version calls to the registry" do
95
+ klass = create_model_spaces_class
96
+ ModelSpaces::REGISTRY.should_receive(:new_version).with(klass).and_return do |k, &proc|
97
+ proc.call.should == :blah
98
+ end
99
+ klass.new_version{:blah}
100
+ end
101
+
102
+ it "should pass updated_version calls to the registry" do
103
+ klass = create_model_spaces_class
104
+ ModelSpaces::REGISTRY.should_receive(:updated_version).with(klass).and_return do |k, &proc|
105
+ proc.call.should == :blah
106
+ end
107
+ klass.updated_version{:blah}
108
+ end
109
+
110
+ it "should pass hoover calls to the registry" do
111
+ klass = create_model_spaces_class
112
+ ModelSpaces::REGISTRY.should_receive(:hoover).with(klass).and_return(true)
113
+ klass.hoover
114
+ end
115
+ end
116
+ end