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,292 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'active_record/model_spaces/model_space'
4
+ module ActiveRecord
5
+ module ModelSpaces
6
+
7
+ describe ModelSpace do
8
+
9
+ describe "initialize" do
10
+
11
+ it "should initialize with a name symbol" do
12
+ ModelSpace.new(:foo).name.should == :foo
13
+ end
14
+
15
+ it "should convert a string name to a symbol" do
16
+ ModelSpace.new("foo").name.should == :foo
17
+ end
18
+
19
+ end
20
+
21
+ def create_model(name, superklass=ActiveRecord::Base)
22
+ m = Class.new(superklass)
23
+ m.stub(:to_s).and_return(name)
24
+ m.stub(:inspect).and_return(name)
25
+ m
26
+ end
27
+
28
+ describe "register_model" do
29
+
30
+ it "should register a model" do
31
+ ms = ModelSpace.new(:foo)
32
+ m = create_model('BarModel')
33
+
34
+ r = ms.register_model(m)
35
+ r.should == ms # registering a model returns the ModelSpace
36
+
37
+ r.registered_model_keys.include?("BarModel").should == true
38
+ r.history_versions(m).should == 0
39
+ end
40
+
41
+ it "should register a model with history_versions" do
42
+ ms = ModelSpace.new(:foo)
43
+ m = create_model('BarModel')
44
+
45
+ r = ms.register_model(m, :history_versions=>3)
46
+ r.should == ms # registering a model returns the ModelSpace
47
+
48
+ r.registered_model_keys.include?("BarModel").should == true
49
+ r.history_versions(m).should == 3
50
+ end
51
+
52
+ it "should register a model with a base_table_name" do
53
+ ms = ModelSpace.new(:foo)
54
+ m = create_model('BarModel')
55
+
56
+ r = ms.register_model(m, :base_table_name=>"a_random_name")
57
+ r.should == ms # registering a model returns the ModelSpace
58
+
59
+ r.registered_model_keys.include?("BarModel").should == true
60
+ r.base_table_name(m).should == "a_random_name"
61
+ end
62
+
63
+ it "should bork if an attempt to register a non-ActiveRecord model is made" do
64
+ ms = ModelSpace.new(:foo)
65
+ m = create_model('FooModel', Object)
66
+
67
+ expect {
68
+ ms.register_model(m)
69
+ }.to raise_error /FooModel is not an ActiveRecord model Class/
70
+ end
71
+ end
72
+
73
+ describe "registered_model" do
74
+ it "should return the registered model for a model" do
75
+ ms = ModelSpace.new(:foo)
76
+ m = create_model('BarModel')
77
+ ms.register_model(m)
78
+ ms.registered_model(m).should == m
79
+ end
80
+
81
+ it "should return the registered superclass for a model" do
82
+ ms = ModelSpace.new(:foo)
83
+ m1 = create_model('BarModel')
84
+ m2 = create_model('BazModel', m1)
85
+
86
+ ms.register_model(m1)
87
+
88
+ ms.registered_model(m2).should == m1
89
+ end
90
+ end
91
+
92
+ describe "registered_model_name" do
93
+ it "should return the name of the registered model" do
94
+ ms = ModelSpace.new(:foo)
95
+ m = create_model('BarModel')
96
+ ms.register_model(m)
97
+ ms.registered_model_name(m).should == 'BarModel'
98
+ end
99
+
100
+ it "should return the name of the registered superclass for a model" do
101
+ ms = ModelSpace.new(:foo)
102
+ m1 = create_model('BarModel')
103
+ m2 = create_model('BazModel', m1)
104
+
105
+ ms.register_model(m1)
106
+
107
+ ms.registered_model_name(m2).should == 'BarModel'
108
+ end
109
+ end
110
+
111
+ describe "unchecked_get_model_registration" do
112
+ it "should retrieve a model registration" do
113
+ ms = ModelSpace.new(:foo)
114
+ m = create_model('BarModel')
115
+
116
+ ms.register_model(m)
117
+ ms.send(:unchecked_get_model_registration, m).should == {:model=>m}
118
+ ms.is_registered?(m).should == true
119
+ end
120
+
121
+ it "should return nil if a model is not registered" do
122
+ ms = ModelSpace.new(:foo)
123
+ m = create_model('BarModel')
124
+ ms.is_registered?(m).should == false
125
+ ms.send(:unchecked_get_model_registration, m).should == nil
126
+ end
127
+
128
+ it "should check model superclasses when searching for a registration" do
129
+ ms = ModelSpace.new(:foo)
130
+ m = create_model('BarModel')
131
+ m2 = create_model('BazModel', m)
132
+ ms.register_model(m, :history_versions=>2)
133
+
134
+ ms.send(:unchecked_get_model_registration, m2).should == {:model=>m, :history_versions=>2}
135
+ ms.is_registered?(m2).should == true
136
+ end
137
+ end
138
+
139
+ describe "get_model_registration" do
140
+ it "should bork if a model is not registered" do
141
+ ms = ModelSpace.new(:foo)
142
+ m = create_model('BarModel')
143
+ ms.is_registered?(m).should == false
144
+ expect{
145
+ ms.send(:get_model_registration, m)
146
+ }.to raise_error /BarModel is not registered in ModelSpace: foo/
147
+ end
148
+ end
149
+
150
+ describe "deregister_model" do
151
+ it "should deregister a model" do
152
+ ms = ModelSpace.new(:foo)
153
+ m = create_model('BarModel')
154
+
155
+ ms.register_model(m)
156
+ ms.is_registered?(m).should == true
157
+ ms.deregister_model(m)
158
+ ms.is_registered?(m).should == false
159
+ end
160
+ end
161
+
162
+ describe "is_registered?" do
163
+ it "should return true if a model is registered, false otherwise" do
164
+ ms = ModelSpace.new(:foo)
165
+ m = create_model('BarModel')
166
+
167
+ m2 = create_model('BazModel')
168
+
169
+ ms.register_model(m)
170
+ ms.is_registered?(m).should == true
171
+
172
+ ms.is_registered?(m2).should == false
173
+ end
174
+ end
175
+
176
+ describe "history_versions" do
177
+ it "should return 0 if no history_versions were specified" do
178
+ ms = ModelSpace.new(:foo)
179
+ m = create_model('BarModel')
180
+
181
+ r = ms.register_model(m)
182
+ r.should == ms # registering a model returns the ModelSpace
183
+
184
+ r.registered_model_keys.include?("BarModel").should == true
185
+ r.history_versions(m).should == 0
186
+ end
187
+ end
188
+
189
+ describe "set_base_table_name" do
190
+ it "should set the models base_table_name" do
191
+ ms = ModelSpace.new(:foo)
192
+ m = create_model('BarModel')
193
+
194
+ ms.register_model(m)
195
+ ms.base_table_name(m).should == "bar_models"
196
+ ms.set_base_table_name(m, 'moar_models')
197
+ ms.base_table_name(m).should == 'moar_models'
198
+ end
199
+ end
200
+
201
+ describe "base_table_name" do
202
+ it "should use TableNames.base_table_name to determine the base_table_name if non is specified" do
203
+ ms = ModelSpace.new(:foo)
204
+ m = create_model('BarModel')
205
+
206
+ r = ms.register_model(m)
207
+ r.should == ms # registering a model returns the ModelSpace
208
+
209
+ ms.registered_model_keys.include?("BarModel").should == true
210
+ ms.base_table_name(m).should == "bar_models"
211
+ end
212
+
213
+ it "should use the registered superclass to determine the base_table_name if the class is not registered" do
214
+ ms = ModelSpace.new(:foo)
215
+
216
+ m1 = create_model('BarModel')
217
+ m2 = create_model('BazModel', m1)
218
+
219
+ ms.register_model(m1)
220
+
221
+ ms.base_table_name(m2).should == "bar_models"
222
+ end
223
+ end
224
+
225
+ describe "create_context" do
226
+
227
+ it "should create a new context with a persistor" do
228
+
229
+ p = double("persistor")
230
+ ModelSpaces.should_receive(:create_persistor).with().and_return(p)
231
+
232
+ ms = ModelSpace.new(:foo)
233
+
234
+ ctx = double("context")
235
+ Context.should_receive(:new).with(ms, "foofoo", p)
236
+
237
+ ms.create_context("foofoo")
238
+ end
239
+ end
240
+
241
+ describe "kill_context" do
242
+ it "should call drop_tables on Context with itself and the given model_space key" do
243
+ ms = ModelSpace.new(:foo)
244
+
245
+ Context.should_receive(:drop_tables).with(ms, :one)
246
+
247
+ ms.kill_context(:one)
248
+ end
249
+
250
+ end
251
+
252
+ end
253
+
254
+
255
+
256
+ describe "create_persistor" do
257
+ it "should create a persistor with the default connection and empty table-name" do
258
+ c = double('connection')
259
+ ActiveRecord::Base.should_receive(:connection).and_return(c)
260
+
261
+ Persistor.should_receive(:new).with(c, nil)
262
+
263
+ ModelSpaces.create_persistor.should == p
264
+ end
265
+
266
+ it "should create a persistor with a given connection and table-name" do
267
+ c = double('connection')
268
+ ModelSpaces.stub(:connection).and_return(c)
269
+ ModelSpaces.stub(:table_name).and_return("foo_model_spaces")
270
+
271
+ Persistor.should_receive(:new).with(c, "foo_model_spaces")
272
+
273
+ ModelSpaces.create_persistor.should == p
274
+ end
275
+ end
276
+
277
+ describe "check_model_registration_keys" do
278
+ it "should accept the history_versions key" do
279
+ expect {
280
+ ModelSpaces.check_model_registration_keys([:history_versions])
281
+ }.not_to raise_error
282
+ end
283
+
284
+ it "should not accept another key" do
285
+ expect {
286
+ ModelSpaces.check_model_registration_keys([:another_key])
287
+ }.to raise_error "unknown keys: [:another_key]"
288
+ end
289
+ end
290
+
291
+ end
292
+ end
@@ -0,0 +1,101 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'active_record/model_spaces/persistor'
4
+
5
+ module ActiveRecord
6
+ module ModelSpaces
7
+
8
+ describe Persistor do
9
+
10
+ def create_persistor(connection, table_name)
11
+ Persistor.any_instance.should_receive(:create_model_spaces_table)
12
+ Persistor.new(connection, table_name)
13
+ end
14
+
15
+ describe "initialize" do
16
+ it "should initialize with a connection and default table_name" do
17
+ c = double('connection')
18
+ p = create_persistor(c, nil)
19
+ p.connection.should == c
20
+ p.table_name.should == "model_spaces_tables"
21
+ end
22
+
23
+ it "should initialize with a connection and table_name" do
24
+ c = double('connection')
25
+ p = create_persistor(c, "foo_model_spaces_tables")
26
+ p.connection.should == c
27
+ p.table_name.should == "foo_model_spaces_tables"
28
+ end
29
+ end
30
+
31
+ describe "list_keys" do
32
+ it "should query the connection for a list of prefixes for a model_space" do
33
+ c = double('connection')
34
+
35
+ c.should_receive(:select_rows).with("select model_space_key from ms_tables where model_space_name='blah'").and_return([["foo"], ["bar"]])
36
+
37
+ p = create_persistor(c, "ms_tables")
38
+ p.list_keys('blah').should == ["foo", "bar"]
39
+ end
40
+ end
41
+
42
+ describe "read_model_space_model_versions" do
43
+ it "should query the connection for model_space model_versions" do
44
+ c = double('connection')
45
+
46
+ c.should_receive(:select_all).with("select model_name, version from ms_tables where model_space_name='blah' and model_space_key='one'").and_return([{"model_name"=>"Users", "version"=>"1"}, {"model_name"=>"Items", "version"=>"0"}])
47
+
48
+ p = create_persistor(c, 'ms_tables')
49
+ p.read_model_space_model_versions('blah', 'one').should == {"Users"=>1, "Items"=>0}
50
+ end
51
+ end
52
+
53
+ describe "update_model_space_model_versions" do
54
+ it "should update model_version" do
55
+ ActiveRecord::Base.stub(:transaction).and_return {|&block| block.call}
56
+
57
+ c = double('connection')
58
+ c.should_receive(:execute).with("update ms_tables set version=2 where model_space_name='blah' and model_space_key='one' and model_name='Foo'")
59
+ c.should_receive(:execute).with("insert into ms_tables (model_space_name, model_space_key, model_name, version) values ('blah', 'one', 'Bar', 1)")
60
+ c.should_receive(:execute).with("delete from ms_tables where model_space_name='blah' and model_space_key='one' and model_name='Baz'")
61
+
62
+ p = create_persistor(c, 'ms_tables')
63
+
64
+ p.should_receive(:read_model_space_model_versions).with('blah', 'one').and_return("Foo"=>1, "Baz"=>2, "Blah"=>1)
65
+
66
+ p.update_model_space_model_versions('blah', 'one', "Foo"=>2, "Bar"=>1, "Baz"=>0, "Blah"=>1)
67
+ end
68
+ end
69
+
70
+ describe "create_model_spaces_table" do
71
+ it "should not issue migration statements against the connection if the persistor table exists" do
72
+ c = double('connection')
73
+ c.should_receive(:table_exists?).with("foo_table").and_return(true)
74
+ p = Persistor.new(c, "foo_table")
75
+ end
76
+
77
+ it "should issue migration statements against the connection if the persistor table does not exist" do
78
+ c = double('connection')
79
+ c.should_receive(:table_exists?).with("foo_table").and_return(false)
80
+
81
+ c.should_receive(:create_table).and_return do |table_name, &block|
82
+ table_name.should == "foo_table"
83
+
84
+ t = double("table")
85
+ t.should_receive(:string).with(:model_space_name, :null=>false)
86
+ t.should_receive(:string).with(:model_space_key, :null=>false)
87
+ t.should_receive(:string).with(:model_name, :null=>false)
88
+ t.should_receive(:integer).with(:version, :null=>false, :default=>0)
89
+
90
+ block.call(t)
91
+ end
92
+
93
+ c.should_receive(:add_index).with("foo_table", [:model_space_name, :prefix, :model_name], :unique=>true)
94
+
95
+ p = Persistor.new(c, "foo_table")
96
+ end
97
+
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,522 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ module ActiveRecord
4
+ module ModelSpaces
5
+ describe Registry do
6
+
7
+ describe "context_stack" do
8
+ it "should retrieve the context-stack from a Thread local" do
9
+ cs = double('context-stack')
10
+ Thread.current.should_receive("[]").with(Registry::CONTEXT_STACK_KEY).and_return(cs)
11
+
12
+ r = Registry.new
13
+ r.send(:context_stack).should == cs
14
+ end
15
+
16
+ it "should initialise the context-stack if necessary" do
17
+ Thread.current.should_receive('[]=').with(Registry::CONTEXT_STACK_KEY, []).and_return([])
18
+ r = Registry.new
19
+ r.send(:context_stack).should == []
20
+ end
21
+ end
22
+
23
+ describe "merged_context" do
24
+ it "should retrieve the merged-context from a Thread local" do
25
+ mc = double('merged-context')
26
+ Thread.current.should_receive("[]").with(Registry::MERGED_CONTEXT_KEY).and_return(mc)
27
+
28
+ r = Registry.new
29
+ r.send(:merged_context).should == mc
30
+ end
31
+ end
32
+
33
+ def create_model(name, superklass=ActiveRecord::Base)
34
+ m = Class.new(superklass)
35
+ m.stub(:to_s).and_return(name)
36
+ m.stub(:inspect).and_return(name)
37
+ m
38
+ end
39
+
40
+ describe "reset!" do
41
+ it "should reset model and model_space registrations" do
42
+ r = Registry.new
43
+ m = create_model('FooModel')
44
+ r.register_model(m, :foo_space)
45
+ r.send(:get_model_space, :foo_space).is_registered?(m).should == true
46
+ r.reset!
47
+ r.send(:get_model_space, :foo_space).should == nil
48
+ r.send(:unchecked_get_model_space_for_model, m).should == nil
49
+ end
50
+ end
51
+
52
+ describe "register_model" do
53
+ it "should register a model" do
54
+ r = Registry.new
55
+ m = create_model('FooModeln')
56
+ r.register_model(m, :foo_space)
57
+ r.send(:get_model_space, :foo_space).is_registered?(m).should == true
58
+ end
59
+ end
60
+
61
+ describe "base_table_name" do
62
+ it "should retrieve the models base_table_name" do
63
+ r = Registry.new
64
+ m = create_model('FooModel')
65
+ r.register_model(m, :foo_space)
66
+ r.base_table_name(m).should == "foo_models"
67
+
68
+ m2 = create_model('BarModel')
69
+ r.register_model(m2, :foo_space, :base_table_name=>"moar_models")
70
+ r.base_table_name(m2).should == "moar_models"
71
+ end
72
+ end
73
+
74
+ describe "set_base_table_name" do
75
+ it "should set a base_table_name" do
76
+ r = Registry.new
77
+ m = create_model('FooModel')
78
+ r.register_model(m, :foo_space)
79
+ r.base_table_name(m).should == "foo_models"
80
+ r.set_base_table_name(m, "random_models")
81
+ r.base_table_name(m).should == "random_models"
82
+ end
83
+
84
+ it "should provide an informative error if the model is not yet registered to a model space" do
85
+ r = Registry.new
86
+ m = create_model('FooModel')
87
+
88
+ expect {
89
+ r.set_base_table_name(m, "random_models")
90
+ }.to raise_error /FooModel is not \(yet\) registered to a ModelSpace/
91
+ end
92
+ end
93
+
94
+ describe "table_name" do
95
+ it "should call base_table_name on the model's ModelSpace if no context is registered and !enforce_context" do
96
+ r = Registry.new
97
+ m = create_model('FooModel')
98
+ r.register_model(m, :foo_space)
99
+
100
+ ms = r.send(:get_model_space, :foo_space)
101
+ ms.should_receive(:base_table_name).with(m)
102
+
103
+ r.table_name(m)
104
+ end
105
+
106
+ it "should bork if no context is registered for the model's ModelSpace and enforce_context" do
107
+ r = Registry.new
108
+ m = create_model('FooModel')
109
+ r.register_model(m, :foo_space)
110
+
111
+ r.set_enforce_context(true)
112
+
113
+ expect {
114
+ r.table_name(m)
115
+ }.to raise_error /'foo_space' has no current context/
116
+ end
117
+ end
118
+
119
+ describe "get_active_key" do
120
+ it "should return the key if a context is registered" do
121
+ r = Registry.new
122
+ m = create_model('FooModel')
123
+ r.register_model(m, :foo_space)
124
+
125
+ ms = r.send(:get_model_space, :foo_space)
126
+ ctx = double('foo-context')
127
+ ctx.stub(:model_space).and_return(ms)
128
+ msk = double('foo-space-key')
129
+ ctx.stub(:model_space_key).and_return(msk)
130
+ ctx.should_receive(:commit)
131
+ ms.should_receive(:create_context).with(:one).and_return(ctx)
132
+ r.with_context(:foo_space, :one) { r.active_key(:foo_space) }.should == msk
133
+ end
134
+
135
+ it "should return nil if no context is registered" do
136
+ r = Registry.new
137
+ m = create_model('FooModel')
138
+ r.register_model(m, :foo_space)
139
+
140
+ r.active_key(:foo_space).should == nil
141
+ end
142
+
143
+ it "should bork if the model_space is not registered" do
144
+ r = Registry.new
145
+ expect {
146
+ r.active_key(:foo_space)
147
+ }.to raise_error /no such model space: foo_space/
148
+
149
+ end
150
+ end
151
+
152
+ describe "context proxy methods" do
153
+ it "should call table_name on the live context" do
154
+
155
+ r = Registry.new
156
+ m = create_model('FooModel')
157
+ r.register_model(m, :foo_space)
158
+
159
+ ms = r.send(:get_model_space, :foo_space)
160
+ ctx = double('foo-one-context')
161
+ ctx.stub(:model_space).and_return(ms)
162
+ ctx.should_receive(:commit)
163
+ ms.should_receive(:create_context).with(:one).and_return(ctx)
164
+ ctx.should_receive(:table_name).with(m)
165
+ r.with_context(:foo_space, :one) {r.table_name(m)}
166
+
167
+ ctx2 = double('foo-two-context')
168
+ ctx2.stub(:model_space).and_return(ms)
169
+ ctx2.should_receive(:commit)
170
+ ms.should_receive(:create_context).with(:two).and_return(ctx2)
171
+ ctx2.should_receive(:current_table_name).with(m)
172
+ r.with_context(:foo_space, :two) {r.current_table_name(m)}
173
+
174
+ ctx3 = double('foo-three-context')
175
+ ctx3.stub(:model_space).and_return(ms)
176
+ ctx3.should_receive(:commit)
177
+ ms.should_receive(:create_context).with(:three).and_return(ctx3)
178
+ ctx3.should_receive(:working_table_name).with(m)
179
+ r.with_context(:foo_space, :three) {r.working_table_name(m)}
180
+
181
+ ctx4 = double('foo-four-context')
182
+ ctx4.stub(:model_space).and_return(ms)
183
+ ctx4.should_receive(:commit)
184
+ ms.should_receive(:create_context).with(:four).and_return(ctx4)
185
+ ctx4.should_receive(:hoover)
186
+ r.with_context(:foo_space, :four) {r.hoover(m)}
187
+
188
+ ctx5 = double('foo-five-context')
189
+ ctx5.stub(:model_space).and_return(ms)
190
+ ctx5.should_receive(:commit)
191
+ ms.should_receive(:create_context).with(:five).and_return(ctx5)
192
+ ctx5.should_receive(:new_version).and_return{|model,&block|
193
+ model.should == m
194
+ block.call
195
+ }
196
+ r.with_context(:foo_space, :five) {
197
+ r.new_version(m){ :result }.should == :result
198
+ }
199
+
200
+ ctx6 = double('foo-six-context')
201
+ ctx6.stub(:model_space).and_return(ms)
202
+ ctx6.should_receive(:commit)
203
+ ms.should_receive(:create_context).with(:six).and_return(ctx6)
204
+ ctx6.should_receive(:updated_version).and_return{|model, &block|
205
+ model.should == m
206
+ block.call
207
+ }
208
+ r.with_context(:foo_space, :six) {
209
+ r.updated_version(m){ :result }.should == :result
210
+ }
211
+ end
212
+ end
213
+
214
+ describe "with_context" do
215
+
216
+ it "should bork if a non-existent model_space_name is given" do
217
+ expect {
218
+ r = Registry.new
219
+ r.with_context(:foo_space, "moar_foos") {}
220
+ }.to raise_error /no such model space: foo_space/
221
+ end
222
+
223
+ it "should push a new context to the stack and create a new merged contexts hash if stack empty" do
224
+ r = Registry.new
225
+ m = create_model('FooModel')
226
+ r.register_model(m, :foo_space)
227
+
228
+ ms = r.send(:get_model_space, :foo_space)
229
+ ctx = double('context')
230
+ ctx.stub(:model_space).and_return(ms)
231
+ ctx.should_receive(:commit)
232
+
233
+ ms.should_receive(:create_context).with("moar_foos").and_return(ctx)
234
+
235
+ r.with_context(:foo_space, "moar_foos") do
236
+ r.send(:context_stack).last.should == ctx
237
+ r.send(:merged_context)[:foo_space].should == ctx
238
+ :result
239
+ end.should == :result
240
+ end
241
+
242
+ it "should resist the attempt to register a context for a model-space which already has a context" do
243
+ r = Registry.new
244
+ m = create_model('FooModel')
245
+ r.register_model(m, :foo_space)
246
+
247
+ ms = r.send(:get_model_space, :foo_space)
248
+ ctx = double('context')
249
+ ctx.stub(:model_space).and_return(ms)
250
+ ctx.stub(:model_space_key).and_return(:moar_foos)
251
+ ctx.should_receive(:commit)
252
+
253
+ ms.should_receive(:create_context).with("moar_foos").and_return(ctx)
254
+
255
+ r.with_context(:foo_space, "moar_foos") do
256
+
257
+ expect {
258
+ r.with_context(:foo_space, "even_moar_foos") do
259
+ end
260
+ }.to raise_error /ModelSpace: foo_space: context with key moar_foos already active/
261
+ end
262
+ end
263
+
264
+ it "should just call the block if a context is registered for a model-space which already has a context with the same model-space-key" do
265
+ r = Registry.new
266
+ m = create_model('FooModel')
267
+ r.register_model(m, :foo_space)
268
+
269
+ ms = r.send(:get_model_space, :foo_space)
270
+ ctx = double('context')
271
+ ctx.stub(:model_space).and_return(ms)
272
+ ctx.stub(:model_space_key).and_return(:moar_foos)
273
+ ctx.should_receive(:commit)
274
+
275
+ ms.should_receive(:create_context).with(:moar_foos).and_return(ctx)
276
+
277
+ r.with_context(:foo_space, :moar_foos) do
278
+
279
+ r.with_context(:foo_space, "moar_foos") do
280
+ :one_million_pounds
281
+ end
282
+
283
+ end.should == :one_million_pounds
284
+ end
285
+
286
+ it "should push a new context to the stack and create a new merged contexts hash if stack not empty" do
287
+ r = Registry.new
288
+
289
+ fm = create_model('FooModel')
290
+ r.register_model(fm, :foo_space)
291
+ fms = r.send(:get_model_space, :foo_space)
292
+ fctx = double('foo-context')
293
+ fctx.stub(:model_space).and_return(fms)
294
+ fctx.should_receive(:commit)
295
+ fms.should_receive(:create_context).with("moar_foos").and_return(fctx)
296
+
297
+ bm = create_model('BarModel')
298
+ r.register_model(bm, :bar_space)
299
+ bms = r.send(:get_model_space, :bar_space)
300
+ bctx = double('bar-context')
301
+ bctx.stub(:model_space).and_return(bms)
302
+ bctx.should_receive(:commit)
303
+ bms.should_receive(:create_context).with("moar_bars").and_return(bctx)
304
+
305
+ r.with_context(:foo_space, "moar_foos") do
306
+ r.send(:context_stack).last.should == fctx
307
+ r.send(:merged_context).should == {:foo_space=>fctx}
308
+
309
+ r.with_context(:bar_space, "moar_bars") do
310
+ r.send(:context_stack).last.should == bctx
311
+ r.send(:merged_context).should == {:foo_space=>fctx, :bar_space=>bctx}
312
+ :inner_result
313
+ end.should == :inner_result
314
+
315
+ r.send(:context_stack).last.should == fctx
316
+ r.send(:merged_context).should == {:foo_space=>fctx}
317
+ :outer_result
318
+ end.should == :outer_result
319
+
320
+ end
321
+ end
322
+
323
+ describe "kill_context" do
324
+ it "should call kill_context on the named model_space" do
325
+ r = Registry.new
326
+ m = create_model('FooModel')
327
+ r.register_model(m, :foo_space)
328
+
329
+ ms = r.send(:get_model_space, :foo_space)
330
+ ms.should_receive(:kill_context).with(:one)
331
+
332
+ r.kill_context(:foo_space, :one)
333
+ end
334
+ end
335
+
336
+
337
+ describe "model spaces registry" do
338
+ it "should create a ModelSpace object if it doesn't exist" do
339
+ r = Registry.new
340
+ r.send(:register_model_space, :foo)
341
+ r.send(:get_model_space, :foo).should_not == nil
342
+ end
343
+
344
+ it "should register with a keyword name if a string is given" do
345
+ r = Registry.new
346
+ r.send(:register_model_space, "foo")
347
+ ms = r.send(:get_model_space, :foo)
348
+ ms.should_not == nil
349
+ ms.name.should == :foo
350
+ r.send(:get_model_space, "foo").should == ms
351
+ end
352
+ end
353
+
354
+ describe "unchecked_get_model_space_for_model" do
355
+ it "should retrieve a model space for a model" do
356
+ m = create_model('FooModel')
357
+ r = Registry.new
358
+ r.register_model(m, :foo_space)
359
+ r.send(:unchecked_get_model_space_for_model, m).should == r.send(:get_model_space, :foo_space)
360
+ end
361
+
362
+ it "should return nil if the model is not registered to a model space" do
363
+ m = create_model('FooModel')
364
+ r = Registry.new
365
+ r.send(:unchecked_get_model_space_for_model, m).should == nil
366
+ end
367
+
368
+ it "should check the superclass chain for registrations and return the model space for the nearest registered superclass" do
369
+ m1 = create_model('FooModel')
370
+ m2 = create_model('BarModel', m1)
371
+
372
+ r = Registry.new
373
+ r.register_model(m1, :foo_space)
374
+ r.send(:unchecked_get_model_space_for_model, m2).should == r.send(:get_model_space, :foo_space)
375
+ end
376
+ end
377
+
378
+
379
+ describe "model spaces by model" do
380
+ it "should register a ModelSpace for a model" do
381
+ m = create_model('FooModel')
382
+ ms = double('model-space')
383
+
384
+ r = Registry.new
385
+ r.send(:register_model_space_for_model, m , ms)
386
+ r.send(:unchecked_get_model_space_for_model, m).should == ms
387
+ r.send(:get_model_space_for_model, m).should == ms
388
+ end
389
+
390
+ it "should bork if a model is not registered" do
391
+ m = create_model('A::SomeModel')
392
+
393
+ r = Registry.new
394
+ expect {
395
+ r.send(:get_model_space_for_model, m)
396
+ }.to raise_error /A::SomeModel is not registered to any ModelSpace/
397
+ end
398
+
399
+ it "should re-register if a model is registered twice" do
400
+ m = create_model('AModel')
401
+
402
+ r = Registry.new
403
+ r.register_model(m, :foo_space, :history_versions=>2)
404
+
405
+ fs = r.send(:get_model_space, :foo_space)
406
+ r.send(:get_model_space_for_model, m).should == fs
407
+ fs.is_registered?(m).should == true
408
+ fs.history_versions(m).should == 2
409
+
410
+ r.register_model(m, :bar_space, :base_table_name=>"moar_models")
411
+
412
+ fs.is_registered?(m).should == false
413
+
414
+ bs = r.send(:get_model_space, :bar_space)
415
+ r.send(:get_model_space_for_model, m).should == bs
416
+ bs.is_registered?(m).should == true
417
+ bs.history_versions(m).should == 0
418
+ bs.base_table_name(m).should == "moar_models"
419
+ end
420
+ end
421
+
422
+ describe "merge_context_stack" do
423
+
424
+ it "should merge contexts into a hash of contexts" do
425
+ ms1 = double('model-space-1')
426
+ ms1.stub(:name).and_return(:space_1)
427
+ ctx1 = double('context-1')
428
+ ctx1.stub(:model_space).and_return(ms1)
429
+
430
+ ms2 = double('model-space-2')
431
+ ms2.stub(:name).and_return(:space_2)
432
+ ctx2 = double('context-2')
433
+ ctx2.stub(:model_space).and_return(ms2)
434
+
435
+ r = Registry.new
436
+ r.stub(:context_stack).and_return( [ctx1, ctx2] )
437
+
438
+ r.send(:merge_context_stack).should == {:space_1=>ctx1, :space_2=>ctx2}
439
+ end
440
+ end
441
+
442
+ describe "unchecked_get_context_for_model" do
443
+ it "should return an active context" do
444
+ r = Registry.new
445
+ m = create_model('FooModel')
446
+ r.register_model(m, :foo_space)
447
+
448
+ ms = r.send(:get_model_space, :foo_space)
449
+ ctx = double('context')
450
+ ctx.stub(:model_space).and_return(ms)
451
+ ctx.should_receive(:commit)
452
+
453
+ ms.should_receive(:create_context).with("moar_foos").and_return(ctx)
454
+
455
+ r.with_context(:foo_space, "moar_foos") do
456
+ r.send(:unchecked_get_context_for_model, m).should == ctx
457
+ end
458
+ end
459
+
460
+ it "should return nil if the model_space of the model is unknown" do
461
+ r = Registry.new
462
+ m = create_model('FooModel')
463
+ r.send(:unchecked_get_context_for_model, m).should == nil
464
+ end
465
+
466
+ it "should return nil if the model_space is known but there is no active context" do
467
+ r = Registry.new
468
+ m = create_model('FooModel')
469
+ r.register_model(m, :foo_space)
470
+
471
+ ms = r.send(:get_model_space, :foo_space)
472
+
473
+ r.send(:unchecked_get_context_for_model, m).should == nil
474
+ end
475
+ end
476
+
477
+ describe "get_context_for_model" do
478
+
479
+ it "should bork if the model is not registered to a model space" do
480
+ r = Registry.new
481
+
482
+ m = create_model('A::Foo')
483
+
484
+ expect {
485
+ r.send(:get_context_for_model, m)
486
+ }.to raise_error /A::Foo is not registered to any ModelSpace/
487
+ end
488
+
489
+ it "should bork if the model's ModelSpace has no current context" do
490
+ r = Registry.new
491
+
492
+ m = create_model('FooModel')
493
+ r.register_model(m, :foo_space)
494
+
495
+ expect {
496
+ r.send(:get_context_for_model, m)
497
+ }.to raise_error /ModelSpace: 'foo_space' has no current context/
498
+ end
499
+
500
+ it "should return the registered context for the model's ModelSpace" do
501
+ r = Registry.new
502
+ m = create_model('FooModel')
503
+ r.register_model(m, :foo_space)
504
+
505
+ ms = r.send(:get_model_space, :foo_space)
506
+ ctx = double('context')
507
+ ctx.stub(:model_space).and_return(ms)
508
+ ctx.should_receive(:commit)
509
+
510
+ ms.should_receive(:create_context).with("moar_foos").and_return(ctx)
511
+
512
+ r.with_context(:foo_space, "moar_foos") do
513
+ r.send(:get_context_for_model, m).should == ctx
514
+ end
515
+
516
+ end
517
+ end
518
+
519
+
520
+ end
521
+ end
522
+ end