old_api_resource 0.3.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.
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