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.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +56 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +98 -0
- data/Rakefile +55 -0
- data/VERSION +1 -0
- data/activerecord-model-spaces.gemspec +87 -0
- data/lib/active_record/model_spaces.rb +89 -0
- data/lib/active_record/model_spaces/context.rb +184 -0
- data/lib/active_record/model_spaces/model_space.rb +121 -0
- data/lib/active_record/model_spaces/persistor.rb +72 -0
- data/lib/active_record/model_spaces/registry.rb +195 -0
- data/lib/active_record/model_spaces/table_manager.rb +111 -0
- data/lib/active_record/model_spaces/table_names.rb +51 -0
- data/lib/active_record/model_spaces/util.rb +55 -0
- data/spec/active_record/model_spaces/context_spec.rb +479 -0
- data/spec/active_record/model_spaces/model_space_spec.rb +292 -0
- data/spec/active_record/model_spaces/persistor_spec.rb +101 -0
- data/spec/active_record/model_spaces/registry_spec.rb +522 -0
- data/spec/active_record/model_spaces/table_manager_spec.rb +186 -0
- data/spec/active_record/model_spaces/table_names_spec.rb +90 -0
- data/spec/active_record/model_spaces/util_spec.rb +106 -0
- data/spec/active_record/model_spaces_spec.rb +116 -0
- data/spec/spec_helper.rb +18 -0
- metadata +205 -0
@@ -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
|