api_resource 0.3.14 → 0.4.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/VERSION +1 -1
- data/api_resource.gemspec +5 -2
- data/lib/api_resource/associations/generic_scope.rb +68 -0
- data/lib/api_resource/associations/resource_scope.rb +11 -15
- data/lib/api_resource/associations/scope.rb +29 -12
- data/lib/api_resource/associations/single_object_proxy.rb +0 -8
- data/lib/api_resource/associations.rb +2 -1
- data/lib/api_resource/decorators/caching_decorator.rb +20 -0
- data/lib/api_resource/decorators.rb +6 -0
- data/lib/api_resource/scopes.rb +3 -0
- data/lib/api_resource.rb +1 -4
- data/spec/lib/associations_spec.rb +119 -109
- data/spec/support/mocks/association_mocks.rb +2 -1
- data/spec/support/requests/association_requests.rb +12 -4
- data/spec/support/requests/test_resource_requests.rb +3 -3
- metadata +56 -53
@@ -3,13 +3,13 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
3
3
|
include ApiResource
|
4
4
|
|
5
5
|
describe "Associations" do
|
6
|
-
|
6
|
+
|
7
7
|
after(:all) do
|
8
8
|
TestResource.reload_class_attributes
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
context "creating and testing for associations of various types" do
|
12
|
-
|
12
|
+
|
13
13
|
it "should be able to give a list of all associations" do
|
14
14
|
AllAssociations = Class.new(ApiResource::Base)
|
15
15
|
AllAssociations.class_eval do
|
@@ -20,90 +20,90 @@ describe "Associations" do
|
|
20
20
|
AllAssociations.association_names.sort.should eql [:has_many_objects, :belongs_to_object, :has_one_object].sort
|
21
21
|
AllAssociations.new.association_names.sort.should eql [:has_many_objects, :belongs_to_object, :has_one_object].sort
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
it "should be be able to define an asociation using a method named after that association type" do
|
25
25
|
TestResource.has_many :has_many_objects
|
26
26
|
TestResource.has_many?(:has_many_objects).should be_true
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
29
|
it "should be able to define associations with different class names" do
|
30
30
|
TestResource.has_many :test_name, :class_name => :has_many_objects
|
31
31
|
TestResource.has_many?(:test_name).should be_true
|
32
32
|
TestResource.has_many_class_name(:test_name).should eql("HasManyObject")
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
it "should be able to define multiple associations at the same time" do
|
36
36
|
TestResource.has_many :has_many_objects, :other_has_many_objects
|
37
37
|
TestResource.has_many?(:has_many_objects).should be_true
|
38
38
|
TestResource.has_many?(:other_has_many_objects).should be_true
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
it "should be able to tell if something is an association via the association? method" do
|
42
42
|
TestResource.belongs_to :belongs_to_object
|
43
43
|
TestResource.association?(:belongs_to_object).should be_true
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
it "should be able to get the class name of an association via the association_class_name method" do
|
47
47
|
TestResource.belongs_to :belongs_to_object
|
48
48
|
TestResource.association_class_name(:belongs_to_object).should eql("BelongsToObject")
|
49
49
|
TestResource.belongs_to :strange_name, :class_name => :belongs_to_object
|
50
50
|
TestResource.association_class_name(:strange_name).should eql("BelongsToObject")
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
it "should only define relationships for the given class - they should not cascade" do
|
54
54
|
TestResource.belongs_to :belongs_to_object
|
55
55
|
AnotherTestResource.association?(:belongs_to_object).should_not be_true
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
it "should have its relationship cascade when sub-classed after the relationship is defined" do
|
59
59
|
TestResource.belongs_to :belongs_to_object
|
60
60
|
class ChildTestResource2 < TestResource; end
|
61
61
|
ChildTestResource2.association?(:belongs_to_object).should be true
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
context "Determining associated classes with a namespace" do
|
65
|
-
|
65
|
+
|
66
66
|
it "should be able to find classes for associations that exist in the same module without a namespace" do
|
67
67
|
TestMod::TestClass.belongs_to :test_association
|
68
68
|
TestMod::TestClass.association_class_name(:test_association).should eql("TestMod::TestAssociation")
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
it "should be return a regular class name for a class defined at the root level" do
|
72
72
|
TestMod::TestClass.belongs_to :belongs_to_object
|
73
73
|
TestMod::TestClass.association_class_name(:belongs_to_object).should eql("BelongsToObject")
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
it "should work for a class name specified with a namespace module" do
|
77
77
|
TestMod::TestClass.belongs_to :nonsense, :class_name => "TestMod::TestAssociation"
|
78
78
|
TestMod::TestClass.association_class_name(:nonsense).should eql("TestMod::TestAssociation")
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
it "should work for nested module as well" do
|
82
82
|
TestMod::InnerMod::InnerClass.belongs_to :test_association
|
83
83
|
TestMod::InnerMod::InnerClass.association_class_name(:test_association).should eql("TestMod::TestAssociation")
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
it "should prefer to find classes within similar modules to ones in the root namespace" do
|
87
87
|
TestMod::InnerMod::InnerClass.belongs_to :test_resource
|
88
88
|
TestMod::InnerMod::InnerClass.association_class_name(:test_resource).should eql("TestMod::TestResource")
|
89
89
|
end
|
90
|
-
|
90
|
+
|
91
91
|
it "should be able to override into the root namespace by prefixing with ::" do
|
92
92
|
TestMod::InnerMod::InnerClass.belongs_to :test_resource, :class_name => "::TestResource"
|
93
93
|
TestMod::InnerMod::InnerClass.association_class_name(:test_resource).should eql("::TestResource")
|
94
94
|
end
|
95
|
-
|
95
|
+
|
96
96
|
end
|
97
|
-
|
98
|
-
|
97
|
+
|
98
|
+
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
context "Remote Definitions" do
|
102
|
-
|
102
|
+
|
103
103
|
before(:all) do
|
104
104
|
TestResource.reload_class_attributes
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
it "should be able define an association remotely" do
|
108
108
|
TestResource.belongs_to?(:belongs_to_object).should be true
|
109
109
|
TestResource.new.belongs_to_object.klass.should eql BelongsToObject
|
@@ -113,19 +113,19 @@ describe "Associations" do
|
|
113
113
|
TestResource.belongs_to?(:custom_name).should be true
|
114
114
|
TestResource.new.custom_name.klass.should eql BelongsToObject
|
115
115
|
end
|
116
|
-
|
116
|
+
|
117
117
|
end
|
118
|
-
|
119
|
-
|
118
|
+
|
119
|
+
|
120
120
|
context "creating and testing for scopes" do
|
121
|
-
|
121
|
+
|
122
122
|
it "should be able to define scopes which require class names" do
|
123
123
|
lambda {
|
124
124
|
TestResource.scope :test_scope
|
125
125
|
}.should raise_error
|
126
126
|
TestResource.scope :test_scope, {:has_many_objects => "test"}
|
127
127
|
end
|
128
|
-
|
128
|
+
|
129
129
|
it "should be able to test if a scope exists" do
|
130
130
|
TestResource.scope :test_scope, {:item => "test"}
|
131
131
|
TestResource.scope?(:test_scope).should be_true
|
@@ -149,66 +149,66 @@ describe "Associations" do
|
|
149
149
|
Scope2Class.scope?(:two).should be true
|
150
150
|
|
151
151
|
end
|
152
|
-
|
152
|
+
|
153
153
|
end
|
154
|
-
|
154
|
+
|
155
155
|
context "testing for scopes and associations on an instance" do
|
156
|
-
|
156
|
+
|
157
157
|
it "should be able to define associations on a class and test for them on an instance" do
|
158
158
|
TestResource.has_many :has_many_objects, :class_name => :other_has_many_objects
|
159
159
|
tst = TestResource.new
|
160
160
|
tst.has_many?(:has_many_objects).should be_true
|
161
161
|
tst.has_many_class_name(:has_many_objects).should eql("OtherHasManyObject")
|
162
162
|
end
|
163
|
-
|
163
|
+
|
164
164
|
it "should be able to define scopes on a class and test for them on an instance" do
|
165
165
|
TestResource.scope :has_many_objects, {:item => "test"}
|
166
166
|
tst = TestResource.new
|
167
167
|
tst.scope?(:has_many_objects).should be_true
|
168
168
|
tst.scope_attributes(:has_many_objects).should eql({"item" => "test"})
|
169
169
|
end
|
170
|
-
|
170
|
+
|
171
171
|
end
|
172
|
-
|
172
|
+
|
173
173
|
describe "Single Object Associations" do
|
174
|
-
|
174
|
+
|
175
175
|
before(:all) do
|
176
176
|
TestResource.reload_class_attributes
|
177
177
|
end
|
178
|
-
|
178
|
+
|
179
179
|
after(:all) do
|
180
180
|
TestResource.reload_class_attributes
|
181
181
|
end
|
182
|
-
|
182
|
+
|
183
183
|
it "should return nil if its internal object is nil" do
|
184
184
|
ap = Associations::SingleObjectProxy.new("TestResource", {})
|
185
185
|
ap.instance_variable_set(:@internal_object, nil)
|
186
186
|
ap.blank?.should be_true
|
187
187
|
end
|
188
|
-
|
188
|
+
|
189
189
|
it "should not throw an error on serializable hash if its internal object is nil" do
|
190
190
|
ap = Associations::SingleObjectProxy.new("TestResource", {})
|
191
191
|
ap.instance_variable_set(:@internal_object, nil)
|
192
192
|
lambda {ap.serializable_hash}.should_not raise_error
|
193
193
|
end
|
194
|
-
|
194
|
+
|
195
195
|
it "should be able to create a SingleObjectProxy around a blank hash" do
|
196
196
|
ap = Associations::SingleObjectProxy.new("TestResource", {})
|
197
197
|
ap.remote_path.should be_blank
|
198
198
|
end
|
199
|
-
|
199
|
+
|
200
200
|
it "should be able to extract a service uri from the contents hash" do
|
201
201
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => "/path"})
|
202
202
|
ap.remote_path.should eql("/path")
|
203
203
|
end
|
204
|
-
|
204
|
+
|
205
205
|
it "should be able to recognize the attributes of an object and not make them scopes" do
|
206
206
|
TestResource.define_attributes :test
|
207
207
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => "/path", :test => "testval"})
|
208
208
|
ap.scope?("test").should be_false
|
209
209
|
ap.remote_path.should eql("/path")
|
210
210
|
end
|
211
|
-
|
211
|
+
|
212
212
|
it "should make all attributes except the service uri into scopes given the scopes_only option" do
|
213
213
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => "/path", :test_scope => {"testval" => true}, :scopes_only => true})
|
214
214
|
ap.scope?("test_scope").should be_true
|
@@ -221,7 +221,7 @@ describe "Associations" do
|
|
221
221
|
ap.internal_object.attributes.keys.should include("test")
|
222
222
|
end
|
223
223
|
end
|
224
|
-
|
224
|
+
|
225
225
|
describe "Multi Object Associations" do
|
226
226
|
|
227
227
|
before(:all) do
|
@@ -297,24 +297,29 @@ describe "Associations" do
|
|
297
297
|
end
|
298
298
|
|
299
299
|
describe "Selecting scopes" do
|
300
|
-
|
300
|
+
|
301
301
|
before(:all) do
|
302
302
|
ScopeResource.class_eval do
|
303
|
-
scope :
|
304
|
-
scope :
|
305
|
-
scope :
|
303
|
+
scope :no_arg, {}
|
304
|
+
scope :one_arg, {:id => :req}
|
305
|
+
scope :one_array_arg, {:ids => :req}
|
306
|
+
scope :two_args, {:page => :req, :per_page => :req}
|
307
|
+
scope :opt_args, {:arg1 => :opt}
|
308
|
+
scope :var_args, {:ids => :rest}
|
309
|
+
scope :mix_args, {:id => :req, :vararg => :rest}
|
306
310
|
end
|
307
311
|
end
|
308
|
-
|
309
|
-
|
312
|
+
|
310
313
|
it "should be able to query scopes on the current model" do
|
311
|
-
ScopeResource.
|
312
|
-
ScopeResource.
|
313
|
-
ScopeResource.
|
314
|
-
|
315
|
-
ScopeResource.
|
314
|
+
ScopeResource.no_arg.to_query.should eql "no_arg=true"
|
315
|
+
# ScopeResource.one_arg(5).to_query.should eql "one_arg[id]=5"
|
316
|
+
# ScopeResource.one_array_arg([3, 5]).to_query.should eql "one_array_arg[ids][]=3&one_array_arg[ids][]=5"
|
317
|
+
# ScopeResource.two_args(1, 20).to_query.should eql "two_args[page]=1&two_args[per_page]=20"
|
318
|
+
# ScopeResource.opt_arg.to_query.should eql "opt_args=true"
|
319
|
+
# ScopeResource.opt_args(3).to_query.should eql "opt_args[arg1]=3"
|
320
|
+
# ScopeResource.var_args(1, 2).to_query.should eql "var_args[ids][]=1&var_args[ids][]=2"
|
321
|
+
# ScopeResource.mix_args("a", {:opt1 => 1}, {:opt2 => 2}).to_query.should eql "mix_args[arg1]=a&mix_args[vararg][][opt1]=1&mix_arg[vararg][][opt2]=2"
|
316
322
|
end
|
317
|
-
|
318
323
|
|
319
324
|
it "should be able to change scopes" do
|
320
325
|
ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope1 => {"scope1" => true}, :scope2 => {"scope2" => true}}])
|
@@ -327,17 +332,17 @@ describe "Associations" do
|
|
327
332
|
ap.scope1.scope2.current_scope.scope1_and_scope2_scope?.should be_true
|
328
333
|
ap.scope1.scope2.to_query.should eql("scope1=true&scope2=true")
|
329
334
|
end
|
330
|
-
|
335
|
+
|
331
336
|
it "should support scopes that contain underscores" do
|
332
337
|
ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope_1 => {"scope_1" => true}, :scope_2 => {"scope_2" => true}}])
|
333
338
|
ap.scope_1.scope_2.current_scope.scope_1_and_scope_2_scope?.should be_true
|
334
339
|
end
|
335
|
-
|
340
|
+
|
336
341
|
it "should be able to return the current query string" do
|
337
342
|
ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope_1 => {"scope_1" => true}, :scope_2 => {"scope_2" => true}}])
|
338
343
|
ap.scope_1.scope_2.to_query.should eql("scope_1=true&scope_2=true")
|
339
344
|
end
|
340
|
-
|
345
|
+
|
341
346
|
it "should be able to substitute values into the scope query strings by passing a hash to the methods" do
|
342
347
|
ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope_1 => {"scope_1" => true, :test_sub => false}, :scope_2 => {"scope_2" => true}}])
|
343
348
|
obj = ap.scope_1(:test_sub => true).scope_2
|
@@ -347,15 +352,15 @@ describe "Associations" do
|
|
347
352
|
|
348
353
|
|
349
354
|
end
|
350
|
-
|
355
|
+
|
351
356
|
describe "Loading and Caching loaded data" do
|
352
|
-
|
357
|
+
|
353
358
|
context "Single Object" do
|
354
|
-
|
359
|
+
|
355
360
|
before(:all) do
|
356
361
|
TestResource.reload_class_attributes
|
357
362
|
end
|
358
|
-
|
363
|
+
|
359
364
|
it "should be able to force load an object" do
|
360
365
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :scopes_only => true})
|
361
366
|
ap.loaded.should be_blank
|
@@ -365,7 +370,7 @@ describe "Associations" do
|
|
365
370
|
# Make sure it isn't reloaded
|
366
371
|
ap.name.should eql(name)
|
367
372
|
end
|
368
|
-
|
373
|
+
|
369
374
|
it "should be able to load a scope" do
|
370
375
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :scopes_only => true})
|
371
376
|
ap.internal_object.active.should be_false
|
@@ -377,7 +382,7 @@ describe "Associations" do
|
|
377
382
|
# another check that the resource wasn't reloaded
|
378
383
|
ap.times_loaded.should eql(2)
|
379
384
|
end
|
380
|
-
|
385
|
+
|
381
386
|
it "should be able to load a chain of scopes" do
|
382
387
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :with_birthday => {:birthday => true}, :scopes_only => true})
|
383
388
|
first = ap.active.with_birthday.id
|
@@ -385,36 +390,42 @@ describe "Associations" do
|
|
385
390
|
ap.times_loaded.should eql(1)
|
386
391
|
ap.active.with_birthday.birthday.should_not be_blank
|
387
392
|
end
|
388
|
-
|
393
|
+
|
389
394
|
it "should proxy unknown methods to the object loading if it hasn't already" do
|
390
395
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => false}, :with_birthday => {:birthday => true}, :scopes_only => true})
|
391
396
|
ap.times_loaded.should eql(0)
|
392
397
|
ap.id.should_not be_blank
|
393
398
|
ap.times_loaded.should eql(1)
|
394
399
|
end
|
395
|
-
|
400
|
+
|
396
401
|
it "should load scopes with caching" do
|
397
|
-
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active =>
|
402
|
+
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :scopes_only => true})
|
398
403
|
ap.times_loaded.should eql(0)
|
399
|
-
ap.active(
|
404
|
+
ap.active.expires_in(30).internal_object
|
405
|
+
ap.active.expires_in(30).internal_object
|
400
406
|
ap.times_loaded.should eql(1)
|
401
|
-
ap.active(:active => true, :expires_in => 10).ttl.should eql(10)
|
402
407
|
end
|
403
|
-
|
408
|
+
|
409
|
+
it "should check that ttl matches the expiration parameter" do
|
410
|
+
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :scopes_only => true})
|
411
|
+
ap.active.expires_in(10).ttl.should eql(10)
|
412
|
+
end
|
413
|
+
|
404
414
|
it "should cache scopes when caching enabled" do
|
405
415
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => false}, :with_birthday => {:birthday => true}, :scopes_only => true})
|
406
416
|
ApiResource.expects(:with_ttl).with(10)
|
407
417
|
ap.active(:active => true, :expires_in => 10).internal_object
|
408
418
|
end
|
409
|
-
|
419
|
+
|
410
420
|
it "should only load each distinct set of scopes once" do
|
411
421
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => false}, :with_birthday => {:birthday => true}, :scopes_only => true})
|
412
422
|
ap.times_loaded.should eql(0)
|
413
|
-
ap.active
|
414
|
-
ap.with_birthday.
|
423
|
+
ap.active.with_birthday.internal_object
|
424
|
+
ap.active.with_birthday.internal_object
|
425
|
+
ap.with_birthday.active.internal_object
|
415
426
|
ap.times_loaded.should eql(1)
|
416
427
|
end
|
417
|
-
|
428
|
+
|
418
429
|
it "should be able to clear it's loading cache" do
|
419
430
|
ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :with_birthday => {:birthday => true}, :scopes_only => true})
|
420
431
|
ap.active.internal_object
|
@@ -423,7 +434,7 @@ describe "Associations" do
|
|
423
434
|
ap.active.internal_object
|
424
435
|
ap.times_loaded.should eql(1)
|
425
436
|
end
|
426
|
-
|
437
|
+
|
427
438
|
end
|
428
439
|
|
429
440
|
it "should be able to reload a single-object association" do
|
@@ -454,44 +465,44 @@ describe "Associations" do
|
|
454
465
|
|
455
466
|
ap.first.name.should eql old_name
|
456
467
|
end
|
457
|
-
|
468
|
+
|
458
469
|
context "Multi Object" do
|
459
|
-
|
470
|
+
|
460
471
|
it "should be able to load 'all'" do
|
461
472
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => false}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
462
473
|
results = ap.all
|
463
474
|
results.size.should eql(5)
|
464
475
|
results.first.active.should be_false
|
465
476
|
end
|
466
|
-
|
477
|
+
|
467
478
|
it "should be able to load a scope" do
|
468
479
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => false}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
469
480
|
results = ap.active.internal_object
|
470
481
|
results.size.should eql(5)
|
471
482
|
results.first.active.should be_true
|
472
483
|
end
|
473
|
-
|
484
|
+
|
474
485
|
it "should be able to load a chain of scopes" do
|
475
486
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
476
487
|
results = ap.active.with_birthday.internal_object
|
477
488
|
results.first.active.should be_true
|
478
489
|
results.first.birthday.should_not be_blank
|
479
490
|
end
|
480
|
-
|
491
|
+
|
481
492
|
it "should be able to load a chain of scopes with substitution" do
|
482
493
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
483
494
|
results = ap.inactive(:active => true).with_birthday.internal_object
|
484
495
|
results.first.active.should be_true
|
485
496
|
results.first.birthday.should_not be_blank
|
486
497
|
end
|
487
|
-
|
498
|
+
|
488
499
|
it "should proxy unknown methods to the object array loading if it hasn't already" do
|
489
500
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
490
501
|
ap.first.should be_a TestResource
|
491
502
|
ap.active.first.should be_a TestResource
|
492
503
|
ap.times_loaded.should eql(2)
|
493
504
|
end
|
494
|
-
|
505
|
+
|
495
506
|
it "should only load each distinct set of scopes once" do
|
496
507
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
497
508
|
ap.first
|
@@ -503,7 +514,7 @@ describe "Associations" do
|
|
503
514
|
ap.with_birthday.active.first
|
504
515
|
ap.times_loaded.should eql(3)
|
505
516
|
end
|
506
|
-
|
517
|
+
|
507
518
|
it "should be able to clear it's loading cache" do
|
508
519
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
509
520
|
ap.active.first
|
@@ -512,38 +523,38 @@ describe "Associations" do
|
|
512
523
|
ap.active.first
|
513
524
|
ap.times_loaded.should eql(1)
|
514
525
|
end
|
515
|
-
|
526
|
+
|
516
527
|
it "should be enumerable" do
|
517
528
|
ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
|
518
529
|
ap.each do |tr|
|
519
530
|
tr.name.should_not be_blank
|
520
531
|
end
|
521
532
|
end
|
522
|
-
|
533
|
+
|
523
534
|
end
|
524
|
-
|
535
|
+
|
525
536
|
context "Scopes" do
|
526
|
-
|
537
|
+
|
527
538
|
before(:all) do
|
528
539
|
TestResource.reload_class_attributes
|
529
540
|
end
|
530
|
-
|
541
|
+
|
531
542
|
it "should define class methods for the known scopes" do
|
532
543
|
TestResource.scopes.each do |key, _|
|
533
544
|
TestResource.should respond_to key
|
534
545
|
end
|
535
546
|
end
|
536
|
-
|
547
|
+
|
537
548
|
it "should return a ResourceScope when calling any scope on a class" do
|
538
549
|
TestResource.send(TestResource.scopes.first.first.to_sym).should be_a Associations::ResourceScope
|
539
550
|
end
|
540
|
-
|
551
|
+
|
541
552
|
it "should be able to chain scopes" do
|
542
553
|
scp = TestResource.active.paginate
|
543
554
|
scp.should be_a Associations::ResourceScope
|
544
|
-
scp.to_query.should eql("active=true&
|
555
|
+
scp.to_query.should eql("active=true&paginate=true")
|
545
556
|
end
|
546
|
-
|
557
|
+
|
547
558
|
it "should load when calling all" do
|
548
559
|
TestResource.active.should respond_to :all
|
549
560
|
TestResource.active.should respond_to :internal_object
|
@@ -554,14 +565,14 @@ describe "Associations" do
|
|
554
565
|
res.should be_a TestResource
|
555
566
|
end
|
556
567
|
end
|
557
|
-
|
568
|
+
|
558
569
|
it "should load when calling an enumerable method or an array method" do
|
559
570
|
TestResource.active.each do |result|
|
560
571
|
result.should be_a TestResource
|
561
572
|
end
|
562
573
|
end
|
563
574
|
end
|
564
|
-
|
575
|
+
|
565
576
|
context "Assigning Data" do
|
566
577
|
context "Single Object Association" do
|
567
578
|
before(:all) do
|
@@ -571,25 +582,25 @@ describe "Associations" do
|
|
571
582
|
after(:all) do
|
572
583
|
TestResource.reload_class_attributes
|
573
584
|
end
|
574
|
-
|
585
|
+
|
575
586
|
it "should assign associations to the correct type on initialization" do
|
576
587
|
#binding.pry
|
577
588
|
tr = TestResource.new(:has_one_object => {:name => "Dan"}, :belongs_to_object => {:name => "Dan"})
|
578
|
-
|
589
|
+
|
579
590
|
tr.has_one_object.internal_object.should be_instance_of HasOneObject
|
580
591
|
tr.belongs_to_object.internal_object.should be_instance_of BelongsToObject
|
581
|
-
|
592
|
+
|
582
593
|
end
|
583
|
-
|
594
|
+
|
584
595
|
it "should assign associations to the correct type when setting attributes directly" do
|
585
596
|
tr = TestResource.new()
|
586
597
|
tr.has_one_object = {:name => "Dan"}
|
587
598
|
tr.belongs_to_object = {:name => "Dan"}
|
588
|
-
|
599
|
+
|
589
600
|
tr.has_one_object.internal_object.should be_instance_of HasOneObject
|
590
601
|
tr.belongs_to_object.internal_object.should be_instance_of BelongsToObject
|
591
602
|
end
|
592
|
-
|
603
|
+
|
593
604
|
it "should be able to reload a single-object association" do
|
594
605
|
ApiResource::Associations::SingleObjectProxy.any_instance.stubs(:remote_path => "/has_one_objects")
|
595
606
|
HasOneObject.connection.stubs(:get => nil)
|
@@ -599,12 +610,11 @@ describe "Associations" do
|
|
599
610
|
tr.has_one_object = {:color => "Blue"}
|
600
611
|
|
601
612
|
tr.has_one_object.reload
|
602
|
-
|
603
|
-
tr.has_one_object.should be_blank
|
613
|
+
tr.has_one_object.instance_variable_get(:@internal_object).should be_blank
|
604
614
|
end
|
605
|
-
|
615
|
+
|
606
616
|
end
|
607
|
-
|
617
|
+
|
608
618
|
context "Multi Object Association" do
|
609
619
|
before(:all) do
|
610
620
|
TestResource.has_many(:has_many_objects)
|
@@ -612,19 +622,19 @@ describe "Associations" do
|
|
612
622
|
after(:all) do
|
613
623
|
TestResource.reload_class_attributes
|
614
624
|
end
|
615
|
-
|
625
|
+
|
616
626
|
it "should assign associations to the correct type on initialization" do
|
617
627
|
tr = TestResource.new(:has_many_objects => [{:name => "Dan"}])
|
618
628
|
tr.has_many_objects.internal_object.first.should be_instance_of HasManyObject
|
619
|
-
|
629
|
+
|
620
630
|
end
|
621
|
-
|
631
|
+
|
622
632
|
it "should assign associations to the correct type when setting attributes directly" do
|
623
633
|
tr = TestResource.new()
|
624
634
|
tr.has_many_objects = [{:name => "Dan"}]
|
625
635
|
tr.has_many_objects.internal_object.first.should be_instance_of HasManyObject
|
626
636
|
end
|
627
|
-
|
637
|
+
|
628
638
|
it "should be able to reload a multi-object association" do
|
629
639
|
ApiResource::Associations::MultiObjectProxy.any_instance.stubs(:remote_path => "/has_many_objects")
|
630
640
|
ApiResource::Connection.any_instance.stubs(:get => [])
|
@@ -637,7 +647,7 @@ describe "Associations" do
|
|
637
647
|
end
|
638
648
|
|
639
649
|
end
|
640
|
-
|
650
|
+
|
641
651
|
context "ActiveModel" do
|
642
652
|
before(:all) do
|
643
653
|
require 'active_record'
|
@@ -6,6 +6,7 @@ Mocks.define do
|
|
6
6
|
get(HashDealer.roll(:test_association_resource), :params => {})
|
7
7
|
get(HashDealer.roll(:active_test_association_resource), :params => {:active => true})
|
8
8
|
get(HashDealer.roll(:active_birthday_test_association_resource), :params => {:active => true, :birthday => true})
|
9
|
+
get(HashDealer.roll(:inactive_birthday_test_association_resource), :params => {:active => false, :birthday => true})
|
9
10
|
end
|
10
11
|
|
11
12
|
endpoint("/mock_with_block/:id") do
|
@@ -59,4 +60,4 @@ Mocks.define do
|
|
59
60
|
get({})
|
60
61
|
end
|
61
62
|
|
62
|
-
end
|
63
|
+
end
|
@@ -13,11 +13,19 @@ HashDealer.define(:active_birthday_test_association_resource, :parent => :active
|
|
13
13
|
birthday{Date.today}
|
14
14
|
end
|
15
15
|
|
16
|
+
HashDealer.define(:inactive_test_association_resource, :parent => :test_association_resource) do
|
17
|
+
active(false)
|
18
|
+
end
|
19
|
+
|
20
|
+
HashDealer.define(:inactive_birthday_test_association_resource, :parent => :inactive_test_association_resource) do
|
21
|
+
birthday{Date.today}
|
22
|
+
end
|
23
|
+
|
16
24
|
HashDealer.define(:has_one_object) do
|
17
|
-
|
18
|
-
|
25
|
+
size("large")
|
26
|
+
color("blue")
|
19
27
|
end
|
20
28
|
|
21
29
|
HashDealer.define(:has_many_object) do
|
22
|
-
|
23
|
-
end
|
30
|
+
name("name")
|
31
|
+
end
|
@@ -4,8 +4,8 @@ HashDealer.define(:new_test_object) do
|
|
4
4
|
:public => [:name, :age, :is_active, [:bday, :date], [:roles, :array]]
|
5
5
|
})
|
6
6
|
scopes({
|
7
|
-
:active => {:active =>
|
8
|
-
:paginate => {:
|
7
|
+
:active => {:active => :opt},
|
8
|
+
:paginate => {:per_page => :opt, :current_page => :opt}
|
9
9
|
})
|
10
10
|
associations({
|
11
11
|
:has_many => {:has_many_objects => {}},
|
@@ -35,4 +35,4 @@ HashDealer.define(:test_resource_errors) do
|
|
35
35
|
:name => ["can't be blank"],
|
36
36
|
:age => ["must be a valid number"]
|
37
37
|
})
|
38
|
-
end
|
38
|
+
end
|