old_api_resource 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/.document +5 -0
  2. data/.rspec +3 -0
  3. data/Gemfile +26 -0
  4. data/Guardfile +22 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +19 -0
  7. data/Rakefile +49 -0
  8. data/VERSION +1 -0
  9. data/lib/old_api_resource.rb +70 -0
  10. data/lib/old_api_resource/associations.rb +192 -0
  11. data/lib/old_api_resource/associations/association_proxy.rb +92 -0
  12. data/lib/old_api_resource/associations/multi_object_proxy.rb +74 -0
  13. data/lib/old_api_resource/associations/related_object_hash.rb +12 -0
  14. data/lib/old_api_resource/associations/relation_scope.rb +24 -0
  15. data/lib/old_api_resource/associations/resource_scope.rb +25 -0
  16. data/lib/old_api_resource/associations/scope.rb +88 -0
  17. data/lib/old_api_resource/associations/single_object_proxy.rb +64 -0
  18. data/lib/old_api_resource/attributes.rb +162 -0
  19. data/lib/old_api_resource/base.rb +548 -0
  20. data/lib/old_api_resource/callbacks.rb +49 -0
  21. data/lib/old_api_resource/connection.rb +167 -0
  22. data/lib/old_api_resource/core_extensions.rb +7 -0
  23. data/lib/old_api_resource/custom_methods.rb +119 -0
  24. data/lib/old_api_resource/exceptions.rb +85 -0
  25. data/lib/old_api_resource/formats.rb +14 -0
  26. data/lib/old_api_resource/formats/json_format.rb +25 -0
  27. data/lib/old_api_resource/formats/xml_format.rb +36 -0
  28. data/lib/old_api_resource/log_subscriber.rb +15 -0
  29. data/lib/old_api_resource/mocks.rb +260 -0
  30. data/lib/old_api_resource/model_errors.rb +86 -0
  31. data/lib/old_api_resource/observing.rb +29 -0
  32. data/lib/old_api_resource/railtie.rb +18 -0
  33. data/old_api_resource.gemspec +134 -0
  34. data/spec/lib/associations_spec.rb +519 -0
  35. data/spec/lib/attributes_spec.rb +121 -0
  36. data/spec/lib/base_spec.rb +499 -0
  37. data/spec/lib/callbacks_spec.rb +68 -0
  38. data/spec/lib/mocks_spec.rb +28 -0
  39. data/spec/lib/model_errors_spec.rb +29 -0
  40. data/spec/spec_helper.rb +36 -0
  41. data/spec/support/mocks/association_mocks.rb +46 -0
  42. data/spec/support/mocks/error_resource_mocks.rb +21 -0
  43. data/spec/support/mocks/test_resource_mocks.rb +43 -0
  44. data/spec/support/requests/association_requests.rb +14 -0
  45. data/spec/support/requests/error_resource_requests.rb +25 -0
  46. data/spec/support/requests/test_resource_requests.rb +31 -0
  47. data/spec/support/test_resource.rb +50 -0
  48. metadata +286 -0
@@ -0,0 +1,18 @@
1
+ require 'old_api_resource'
2
+ require 'rails'
3
+
4
+ module OldApiResource
5
+
6
+ class Railtie < ::Rails::Railtie
7
+
8
+ config.old_api_resource = ActiveSupport::OrderedOptions.new
9
+
10
+ initializer "old_api_resource.set_configs" do |app|
11
+ app.config.old_api_resource.each do |k,v|
12
+ OldApiResource::Base.send "#{k}=", v
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,134 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{old_api_resource}
8
+ s.version = "0.3.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = [%q{Ethan Langevin}]
12
+ s.date = %q{2012-01-05}
13
+ s.description = %q{A replacement for ActiveResource for RESTful APIs that handles associated object and multiple data sources}
14
+ s.email = %q{ejl6266@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Guardfile",
24
+ "LICENSE.txt",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "lib/old_api_resource.rb",
29
+ "lib/old_api_resource/associations.rb",
30
+ "lib/old_api_resource/associations/association_proxy.rb",
31
+ "lib/old_api_resource/associations/multi_object_proxy.rb",
32
+ "lib/old_api_resource/associations/related_object_hash.rb",
33
+ "lib/old_api_resource/associations/relation_scope.rb",
34
+ "lib/old_api_resource/associations/resource_scope.rb",
35
+ "lib/old_api_resource/associations/scope.rb",
36
+ "lib/old_api_resource/associations/single_object_proxy.rb",
37
+ "lib/old_api_resource/attributes.rb",
38
+ "lib/old_api_resource/base.rb",
39
+ "lib/old_api_resource/callbacks.rb",
40
+ "lib/old_api_resource/connection.rb",
41
+ "lib/old_api_resource/core_extensions.rb",
42
+ "lib/old_api_resource/custom_methods.rb",
43
+ "lib/old_api_resource/exceptions.rb",
44
+ "lib/old_api_resource/formats.rb",
45
+ "lib/old_api_resource/formats/json_format.rb",
46
+ "lib/old_api_resource/formats/xml_format.rb",
47
+ "lib/old_api_resource/log_subscriber.rb",
48
+ "lib/old_api_resource/mocks.rb",
49
+ "lib/old_api_resource/model_errors.rb",
50
+ "lib/old_api_resource/observing.rb",
51
+ "lib/old_api_resource/railtie.rb",
52
+ "old_api_resource.gemspec",
53
+ "spec/lib/associations_spec.rb",
54
+ "spec/lib/attributes_spec.rb",
55
+ "spec/lib/base_spec.rb",
56
+ "spec/lib/callbacks_spec.rb",
57
+ "spec/lib/mocks_spec.rb",
58
+ "spec/lib/model_errors_spec.rb",
59
+ "spec/spec_helper.rb",
60
+ "spec/support/mocks/association_mocks.rb",
61
+ "spec/support/mocks/error_resource_mocks.rb",
62
+ "spec/support/mocks/test_resource_mocks.rb",
63
+ "spec/support/requests/association_requests.rb",
64
+ "spec/support/requests/error_resource_requests.rb",
65
+ "spec/support/requests/test_resource_requests.rb",
66
+ "spec/support/test_resource.rb"
67
+ ]
68
+ s.homepage = %q{http://github.com/ejlangev/resource}
69
+ s.licenses = [%q{MIT}]
70
+ s.require_paths = [%q{lib}]
71
+ s.rubygems_version = %q{1.8.8}
72
+ s.summary = %q{A replacement for ActiveResource for RESTful APIs that handles associated object and multiple data sources}
73
+
74
+ if s.respond_to? :specification_version then
75
+ s.specification_version = 3
76
+
77
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
78
+ s.add_runtime_dependency(%q<rails>, ["= 3.0.9"])
79
+ s.add_runtime_dependency(%q<hash_dealer>, [">= 0"])
80
+ s.add_runtime_dependency(%q<rest-client>, [">= 0"])
81
+ s.add_runtime_dependency(%q<log4r>, [">= 0"])
82
+ s.add_development_dependency(%q<rspec>, [">= 0"])
83
+ s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
84
+ s.add_development_dependency(%q<growl>, [">= 0"])
85
+ s.add_development_dependency(%q<rspec-rails>, [">= 0"])
86
+ s.add_development_dependency(%q<factory_girl>, [">= 0"])
87
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
88
+ s.add_development_dependency(%q<faker>, [">= 0"])
89
+ s.add_development_dependency(%q<guard>, [">= 0"])
90
+ s.add_development_dependency(%q<guard-rspec>, [">= 0"])
91
+ s.add_development_dependency(%q<mocha>, [">= 0"])
92
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
93
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
94
+ s.add_development_dependency(%q<rcov>, [">= 0"])
95
+ else
96
+ s.add_dependency(%q<rails>, ["= 3.0.9"])
97
+ s.add_dependency(%q<hash_dealer>, [">= 0"])
98
+ s.add_dependency(%q<rest-client>, [">= 0"])
99
+ s.add_dependency(%q<log4r>, [">= 0"])
100
+ s.add_dependency(%q<rspec>, [">= 0"])
101
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
102
+ s.add_dependency(%q<growl>, [">= 0"])
103
+ s.add_dependency(%q<rspec-rails>, [">= 0"])
104
+ s.add_dependency(%q<factory_girl>, [">= 0"])
105
+ s.add_dependency(%q<simplecov>, [">= 0"])
106
+ s.add_dependency(%q<faker>, [">= 0"])
107
+ s.add_dependency(%q<guard>, [">= 0"])
108
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
109
+ s.add_dependency(%q<mocha>, [">= 0"])
110
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
111
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
112
+ s.add_dependency(%q<rcov>, [">= 0"])
113
+ end
114
+ else
115
+ s.add_dependency(%q<rails>, ["= 3.0.9"])
116
+ s.add_dependency(%q<hash_dealer>, [">= 0"])
117
+ s.add_dependency(%q<rest-client>, [">= 0"])
118
+ s.add_dependency(%q<log4r>, [">= 0"])
119
+ s.add_dependency(%q<rspec>, [">= 0"])
120
+ s.add_dependency(%q<ruby-debug19>, [">= 0"])
121
+ s.add_dependency(%q<growl>, [">= 0"])
122
+ s.add_dependency(%q<rspec-rails>, [">= 0"])
123
+ s.add_dependency(%q<factory_girl>, [">= 0"])
124
+ s.add_dependency(%q<simplecov>, [">= 0"])
125
+ s.add_dependency(%q<faker>, [">= 0"])
126
+ s.add_dependency(%q<guard>, [">= 0"])
127
+ s.add_dependency(%q<guard-rspec>, [">= 0"])
128
+ s.add_dependency(%q<mocha>, [">= 0"])
129
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
130
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
131
+ s.add_dependency(%q<rcov>, [">= 0"])
132
+ end
133
+ end
134
+
@@ -0,0 +1,519 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ include OldApiResource
4
+
5
+ describe "Associations" do
6
+
7
+ after(:all) do
8
+ TestResource.reload_class_attributes
9
+ end
10
+
11
+ context "creating and testing for associations of various types" do
12
+
13
+ it "should be be able to define an asociation using a method named after that association type" do
14
+ TestResource.has_many :has_many_objects
15
+ TestResource.has_many?(:has_many_objects).should be_true
16
+ end
17
+
18
+ it "should be able to define associations with different class names" do
19
+ TestResource.has_many :test_name, :class_name => :has_many_objects
20
+ TestResource.has_many?(:test_name).should be_true
21
+ TestResource.has_many_class_name(:test_name).should eql("HasManyObject")
22
+ end
23
+
24
+ it "should be able to define multiple associations at the same time" do
25
+ TestResource.has_many :has_many_objects, :other_has_many_objects
26
+ TestResource.has_many?(:has_many_objects).should be_true
27
+ TestResource.has_many?(:other_has_many_objects).should be_true
28
+ end
29
+
30
+ it "should be able to tell if something is an association via the association? method" do
31
+ TestResource.belongs_to :belongs_to_object
32
+ TestResource.association?(:belongs_to_object).should be_true
33
+ end
34
+
35
+ it "should be able to get the class name of an association via the association_class_name method" do
36
+ TestResource.belongs_to :belongs_to_object
37
+ TestResource.association_class_name(:belongs_to_object).should eql("BelongsToObject")
38
+ TestResource.belongs_to :strange_name, :class_name => :belongs_to_object
39
+ TestResource.association_class_name(:strange_name).should eql("BelongsToObject")
40
+ end
41
+
42
+ it "should only define relationships for the given class - they should not cascade" do
43
+ TestResource.belongs_to :belongs_to_object
44
+ AnotherTestResource.association?(:belongs_to_object).should_not be true
45
+ end
46
+
47
+ it "should have its relationship cascade when sub-classed" do
48
+ TestResource.belongs_to :belongs_to_object
49
+ ChildTestResource.association?(:belongs_to_object).should be true
50
+ end
51
+
52
+ it "should have its relationship cascade when sub-classed after the relationship is defined" do
53
+ TestResource.belongs_to :belongs_to_object
54
+ class ChildTestResource2 < TestResource; end
55
+ ChildTestResource2.association?(:belongs_to_object).should be true
56
+ end
57
+
58
+ context "Determining associated classes with a namespace" do
59
+
60
+ it "should be able to find classes for associations that exist in the same module without a namespace" do
61
+ TestMod::TestClass.belongs_to :test_association
62
+ TestMod::TestClass.association_class_name(:test_association).should eql("TestMod::TestAssociation")
63
+ end
64
+
65
+ it "should be return a regular class name for a class defined at the root level" do
66
+ TestMod::TestClass.belongs_to :belongs_to_object
67
+ TestMod::TestClass.association_class_name(:belongs_to_object).should eql("BelongsToObject")
68
+ end
69
+
70
+ it "should work for a class name specified with a namespace module" do
71
+ TestMod::TestClass.belongs_to :nonsense, :class_name => "TestMod::TestAssociation"
72
+ TestMod::TestClass.association_class_name(:nonsense).should eql("TestMod::TestAssociation")
73
+ end
74
+
75
+ it "should work for nested module as well" do
76
+ TestMod::InnerMod::InnerClass.belongs_to :test_association
77
+ TestMod::InnerMod::InnerClass.association_class_name(:test_association).should eql("TestMod::TestAssociation")
78
+ end
79
+
80
+ it "should prefer to find classes within similar modules to ones in the root namespace" do
81
+ TestMod::InnerMod::InnerClass.belongs_to :test_resource
82
+ TestMod::InnerMod::InnerClass.association_class_name(:test_resource).should eql("TestMod::TestResource")
83
+ end
84
+
85
+ it "should be able to override into the root namespace by prefixing with ::" do
86
+ TestMod::InnerMod::InnerClass.belongs_to :test_resource, :class_name => "::TestResource"
87
+ TestMod::InnerMod::InnerClass.association_class_name(:test_resource).should eql("::TestResource")
88
+ end
89
+
90
+ end
91
+
92
+
93
+ end
94
+
95
+ context "creating and testing for scopes" do
96
+
97
+ it "should be able to define scopes which require class names" do
98
+ lambda {
99
+ TestResource.scope :test_scope
100
+ }.should raise_error
101
+ TestResource.scope :test_scope, {:has_many_objects => "test"}
102
+ end
103
+
104
+ it "should be able to test if a scope exists" do
105
+ TestResource.scope :test_scope, {:item => "test"}
106
+ TestResource.scope?(:test_scope).should be_true
107
+ TestResource.scope_attributes(:test_scope).should eql({"item" => "test"})
108
+ end
109
+
110
+ end
111
+
112
+ context "testing for scopes and associations on an instance" do
113
+
114
+ it "should be able to define associations on a class and test for them on an instance" do
115
+ TestResource.has_many :has_many_objects, :class_name => :other_has_many_objects
116
+ tst = TestResource.new
117
+ tst.has_many?(:has_many_objects).should be_true
118
+ tst.has_many_class_name(:has_many_objects).should eql("OtherHasManyObject")
119
+ end
120
+
121
+ it "should be able to define scopes on a class and test for them on an instance" do
122
+ TestResource.scope :has_many_objects, {:item => "test"}
123
+ tst = TestResource.new
124
+ tst.scope?(:has_many_objects).should be_true
125
+ tst.scope_attributes(:has_many_objects).should eql({"item" => "test"})
126
+ end
127
+
128
+ end
129
+
130
+ describe "Single Object Associations" do
131
+
132
+ before(:all) do
133
+ TestResource.reload_class_attributes
134
+ end
135
+
136
+ after(:all) do
137
+ TestResource.reload_class_attributes
138
+ end
139
+
140
+ it "should be able to create a SingleObjectProxy around a blank hash" do
141
+ ap = Associations::SingleObjectProxy.new("TestResource", {})
142
+ ap.remote_path.should be_blank
143
+ end
144
+
145
+ it "should be able to extract a service uri from the contents hash" do
146
+ ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => "/path"})
147
+ ap.remote_path.should eql("/path")
148
+ end
149
+
150
+ it "should be able to recognize the attributes of an object and not make them scopes" do
151
+ TestResource.define_attributes :test
152
+ ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => "/path", :test => "testval"})
153
+ ap.scope?("test").should be_false
154
+ ap.remote_path.should eql("/path")
155
+ end
156
+
157
+ it "should make all attributes except the service uri into scopes given the scopes_only option" do
158
+ ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => "/path", :test_scope => {"testval" => true}, :scopes_only => true})
159
+ ap.scope?("test_scope").should be_true
160
+ ap.remote_path.should eql("/path")
161
+ end
162
+
163
+ it "should pass the attributes that are not scopes and make them attributes of the object" do
164
+ TestResource.define_attributes :test
165
+ ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => "/path", :test => "testval"})
166
+ ap.internal_object.attributes.keys.should include("test")
167
+ end
168
+ end
169
+
170
+ describe "Multi Object Associations" do
171
+
172
+ before(:all) do
173
+ TestResource.related_objects[:scope].clear
174
+ end
175
+
176
+ after(:each) do
177
+ Associations::MultiObjectProxy.remote_path_element = :service_uri
178
+ end
179
+
180
+ describe "Loading settings" do
181
+
182
+ context "Loading array contents" do
183
+
184
+ it "should be able to load a blank array" do
185
+ ap = Associations::MultiObjectProxy.new("TestResource",[])
186
+ ap.remote_path.should be_nil
187
+ ap.scopes.keys.should eql([])
188
+ end
189
+
190
+ it "should be able to recognize a settings hash if it has a service_uri" do
191
+ ap = Associations::MultiObjectProxy.new("TestResource",[{:service_uri => "/route"}])
192
+ ap.remote_path.should eql("/route")
193
+ end
194
+
195
+ it "should be able to recognize a settings hash if it has a 'service_uri' with another preset name" do
196
+ Associations::MultiObjectProxy.remote_path_element = :the_element
197
+ ap = Associations::MultiObjectProxy.new("TestResource",[{:the_element => "/route"}])
198
+ ap.remote_path.should eql("/route")
199
+ end
200
+
201
+ end
202
+
203
+ context "Loading hash contents" do
204
+
205
+ it "should not be able to load a hash without a 'service_uri'" do
206
+ lambda {
207
+ Associations::MultiObjectProxy.new("TestResource", {})
208
+ }.should raise_error
209
+ end
210
+
211
+ it "should be able to recognize settings from a hash" do
212
+ ap = Associations::MultiObjectProxy.new("TestResource", {:service_uri => "/route"})
213
+ ap.remote_path.should eql("/route")
214
+ end
215
+
216
+ it "should recognize settings with differing 'service_uri' names" do
217
+ Associations::MultiObjectProxy.remote_path_element = :the_element
218
+ ap = Associations::MultiObjectProxy.new("TestResource",{:the_element => "/route"})
219
+ ap.remote_path.should eql("/route")
220
+ end
221
+ end
222
+
223
+ context "Defining scopes" do
224
+
225
+ it "should define scopes based on the other keys in a settings hash" do
226
+ ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope1 => {"scope1" => true}, :scope2 => {"scope2" => true}}])
227
+ [:scope1, :scope2].each{|s| ap.scopes.include?(s).should be_true }
228
+ end
229
+
230
+ it "should identify known scopes based on the scopes defined on the object it is a proxy to" do
231
+ TestResource.scope :class_scope, "class_scope" => "true"
232
+ ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope1 => {"scope1" => true}, :scope2 => {"scope2" => true}}])
233
+ [:scope1, :scope2, :class_scope].each{|s| ap.scopes.include?(s).should be_true}
234
+ end
235
+
236
+ it "scopes in the response should shadow class defined scopes" do
237
+ TestResource.scope :scope1, "scope1" => "true"
238
+ ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope1 => {"scope1" => true}, :scope2 => {"scope2" => true}}])
239
+ ap.scopes[:scope1].should eql({"scope1" => true})
240
+ end
241
+ end
242
+
243
+ end
244
+
245
+ describe "Selecting scopes" do
246
+
247
+ it "should be able to change scopes" do
248
+ ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope1 => {"scope1" => true}, :scope2 => {"scope2" => true}}])
249
+ ap.scope1.should be_a(Associations::RelationScope)
250
+ ap.scope1.current_scope.scope1_scope?.should be_true
251
+ end
252
+
253
+ it "should be able to chain scope calls together" do
254
+ ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope1 => {"scope1" => true}, :scope2 => {"scope2" => true}}])
255
+ ap.scope1.scope2.current_scope.scope1_and_scope2_scope?.should be_true
256
+ ap.scope1.scope2.to_query.should eql("scope1=true&scope2=true")
257
+ end
258
+
259
+ it "should support scopes that contain underscores" do
260
+ ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope_1 => {"scope_1" => true}, :scope_2 => {"scope_2" => true}}])
261
+ ap.scope_1.scope_2.current_scope.scope_1_and_scope_2_scope?.should be_true
262
+ end
263
+
264
+ it "should be able to return the current query string" do
265
+ ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope_1 => {"scope_1" => true}, :scope_2 => {"scope_2" => true}}])
266
+ ap.scope_1.scope_2.to_query.should eql("scope_1=true&scope_2=true")
267
+ end
268
+
269
+ it "should be able to substitute values into the scope query strings by passing a hash to the methods" do
270
+ ap = Associations::MultiObjectProxy.new("TestResource", [{:service_uri => "/route", :scope_1 => {"scope_1" => true, :test_sub => false}, :scope_2 => {"scope_2" => true}}])
271
+ obj = ap.scope_1(:test_sub => true).scope_2
272
+ obj.to_query.should eql("scope_1=true&scope_2=true&test_sub=true")
273
+ end
274
+ end
275
+
276
+
277
+ end
278
+
279
+ describe "Loading and Caching loaded data" do
280
+
281
+ context "Single Object" do
282
+
283
+ before(:all) do
284
+ TestResource.reload_class_attributes
285
+ end
286
+
287
+ it "should be able to force load an object" do
288
+ ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :scopes_only => true})
289
+ ap.loaded.should be_blank
290
+ name = ap.name
291
+ name.should_not be_blank
292
+ ap.loaded.should_not be_blank
293
+ # Make sure it isn't reloaded
294
+ ap.name.should eql(name)
295
+ end
296
+
297
+ it "should be able to load a scope" do
298
+ ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :scopes_only => true})
299
+ ap.internal_object.active.should be_false
300
+ ap.times_loaded.should eql(1)
301
+ ap.active.should be_a Associations::RelationScope
302
+ ap.active.name.should_not be_blank
303
+ ap.times_loaded.should eql(2)
304
+ ap.active.internal_object.active.should be_true
305
+ # another check that the resource wasn't reloaded
306
+ ap.times_loaded.should eql(2)
307
+ end
308
+
309
+ it "should be able to load a chain of scopes" do
310
+ ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :with_birthday => {:birthday => true}, :scopes_only => true})
311
+ first = ap.active.with_birthday.id
312
+ ap.with_birthday.active.id.should eql(first)
313
+ ap.times_loaded.should eql(1)
314
+ ap.active.with_birthday.birthday.should_not be_blank
315
+ end
316
+
317
+ it "should be able to load a chain of scopes with substitution" do
318
+ ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => false}, :with_birthday => {:birthday => true}, :scopes_only => true})
319
+ item = ap.active(:active => true).internal_object
320
+ item.active.should be_true
321
+ ap.times_loaded.should eql(1)
322
+ # This error and incrementing times_loaded means it tried to load again
323
+ lambda {
324
+ ap.active.internal_object
325
+ }.should raise_error
326
+ ap.times_loaded.should eql(2)
327
+ end
328
+
329
+ it "should proxy unknown methods to the object loading if it hasn't already" do
330
+ ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => false}, :with_birthday => {:birthday => true}, :scopes_only => true})
331
+ ap.times_loaded.should eql(0)
332
+ ap.id.should_not be_blank
333
+ ap.times_loaded.should eql(1)
334
+ end
335
+
336
+ it "should only load each distinct set of scopes once" do
337
+ ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => false}, :with_birthday => {:birthday => true}, :scopes_only => true})
338
+ ap.times_loaded.should eql(0)
339
+ ap.active(:active => true).with_birthday.internal_object
340
+ ap.with_birthday.active(:active => true).internal_object
341
+ ap.times_loaded.should eql(1)
342
+ end
343
+
344
+ it "should be able to clear it's loading cache" do
345
+ ap = Associations::SingleObjectProxy.new("TestResource",{:service_uri => '/single_object_association', :active => {:active => true}, :with_birthday => {:birthday => true}, :scopes_only => true})
346
+ ap.active.internal_object
347
+ ap.times_loaded.should eql(1)
348
+ ap.reload
349
+ ap.active.internal_object
350
+ ap.times_loaded.should eql(1)
351
+ end
352
+
353
+ end
354
+
355
+ context "Multi Object" do
356
+
357
+ it "should be able to load 'all'" do
358
+ ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => false}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
359
+ results = ap.all
360
+ results.size.should eql(5)
361
+ results.first.active.should be_false
362
+ end
363
+
364
+ it "should be able to load a scope" do
365
+ ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => false}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
366
+ results = ap.active.internal_object
367
+ results.size.should eql(5)
368
+ results.first.active.should be_true
369
+ end
370
+
371
+ it "should be able to load a chain of scopes" do
372
+ ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
373
+ results = ap.active.with_birthday.internal_object
374
+ results.first.active.should be_true
375
+ results.first.birthday.should_not be_blank
376
+ end
377
+
378
+ it "should be able to load a chain of scopes with substitution" do
379
+ ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
380
+ results = ap.inactive(:active => true).with_birthday.internal_object
381
+ results.first.active.should be_true
382
+ results.first.birthday.should_not be_blank
383
+ end
384
+
385
+ it "should proxy unknown methods to the object array loading if it hasn't already" do
386
+ ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
387
+ ap.first.should be_a TestResource
388
+ ap.active.first.should be_a TestResource
389
+ ap.times_loaded.should eql(2)
390
+ end
391
+
392
+ it "should only load each distinct set of scopes once" do
393
+ ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
394
+ ap.first
395
+ ap.active.first
396
+ ap.times_loaded.should eql(2)
397
+ ap.active.first
398
+ ap.times_loaded.should eql(2)
399
+ ap.active.with_birthday.first
400
+ ap.with_birthday.active.first
401
+ ap.times_loaded.should eql(3)
402
+ end
403
+
404
+ it "should be able to clear it's loading cache" do
405
+ ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
406
+ ap.active.first
407
+ ap.times_loaded.should eql(1)
408
+ ap.reload
409
+ ap.active.first
410
+ ap.times_loaded.should eql(1)
411
+ end
412
+
413
+ it "should be enumerable" do
414
+ ap = Associations::MultiObjectProxy.new("TestResource",{:service_uri => '/multi_object_association', :active => {:active => true}, :inactive => {:active => false}, :with_birthday => {:birthday => true}})
415
+ ap.each do |tr|
416
+ tr.name.should_not be_blank
417
+ end
418
+ end
419
+
420
+ end
421
+
422
+ context "Scopes" do
423
+
424
+ before(:all) do
425
+ TestResource.reload_class_attributes
426
+ end
427
+
428
+ it "should define class methods for the known scopes" do
429
+ TestResource.scopes.each do |key, _|
430
+ TestResource.should respond_to key
431
+ end
432
+ end
433
+
434
+ it "should return a ResourceScope when calling any scope on a class" do
435
+ TestResource.send(TestResource.scopes.first.first.to_sym).should be_a Associations::ResourceScope
436
+ end
437
+
438
+ it "should be able to chain scopes" do
439
+ scp = TestResource.active.paginate
440
+ scp.should be_a Associations::ResourceScope
441
+ scp.to_query.should eql("active=true&current_page=current_page&paginate=true&per_page=per_page")
442
+ end
443
+
444
+ it "should load when calling all" do
445
+ TestResource.active.should respond_to :all
446
+ TestResource.active.should respond_to :internal_object
447
+ results = TestResource.active.all
448
+ results.should be_a Array
449
+ results.size.should eql(5)
450
+ results.each do |res|
451
+ res.should be_a TestResource
452
+ end
453
+ end
454
+
455
+ it "should load when calling an enumerable method or an array method" do
456
+ TestResource.active.each do |result|
457
+ result.should be_a TestResource
458
+ end
459
+ end
460
+ end
461
+
462
+ context "Assigning Data" do
463
+ context "Single Object Association" do
464
+ before(:all) do
465
+ TestResource.has_one(:has_one_object)
466
+ TestResource.belongs_to(:belongs_to_object)
467
+ end
468
+ after(:all) do
469
+ TestResource.reload_class_attributes
470
+ end
471
+
472
+ it "should assign associations to the correct type on initialization" do
473
+ tr = TestResource.new(:has_one_object => {:name => "Dan"}, :belongs_to_object => {:name => "Dan"})
474
+
475
+ tr.has_one_object.internal_object.should be_instance_of HasOneObject
476
+ tr.belongs_to_object.internal_object.should be_instance_of BelongsToObject
477
+
478
+ end
479
+
480
+ it "should assign associations to the correct type when setting attributes directly" do
481
+ tr = TestResource.new()
482
+ tr.has_one_object = {:name => "Dan"}
483
+ tr.belongs_to_object = {:name => "Dan"}
484
+
485
+ tr.has_one_object.internal_object.should be_instance_of HasOneObject
486
+ tr.belongs_to_object.internal_object.should be_instance_of BelongsToObject
487
+ end
488
+
489
+
490
+ end
491
+
492
+ context "Single Object Association" do
493
+ before(:all) do
494
+ TestResource.has_many(:has_many_objects)
495
+ end
496
+ after(:all) do
497
+ TestResource.reload_class_attributes
498
+ end
499
+
500
+ it "should assign associations to the correct type on initialization" do
501
+ tr = TestResource.new(:has_many_objects => [{:name => "Dan"}])
502
+ tr.has_many_objects.internal_object.first.should be_instance_of HasManyObject
503
+
504
+ end
505
+
506
+ it "should assign associations to the correct type when setting attributes directly" do
507
+ tr = TestResource.new()
508
+ tr.has_many_objects = [{:name => "Dan"}]
509
+ tr.has_many_objects.internal_object.first.should be_instance_of HasManyObject
510
+ end
511
+
512
+
513
+ end
514
+
515
+ end
516
+
517
+ end
518
+
519
+ end