api_resource 0.2.1

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 (59) hide show
  1. data/.document +5 -0
  2. data/.rspec +3 -0
  3. data/Gemfile +29 -0
  4. data/Gemfile.lock +152 -0
  5. data/Guardfile +22 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.rdoc +19 -0
  8. data/Rakefile +49 -0
  9. data/VERSION +1 -0
  10. data/api_resource.gemspec +154 -0
  11. data/lib/api_resource.rb +129 -0
  12. data/lib/api_resource/association_activation.rb +19 -0
  13. data/lib/api_resource/associations.rb +169 -0
  14. data/lib/api_resource/associations/association_proxy.rb +115 -0
  15. data/lib/api_resource/associations/belongs_to_remote_object_proxy.rb +16 -0
  16. data/lib/api_resource/associations/dynamic_resource_scope.rb +23 -0
  17. data/lib/api_resource/associations/has_many_remote_object_proxy.rb +16 -0
  18. data/lib/api_resource/associations/has_one_remote_object_proxy.rb +24 -0
  19. data/lib/api_resource/associations/multi_argument_resource_scope.rb +15 -0
  20. data/lib/api_resource/associations/multi_object_proxy.rb +73 -0
  21. data/lib/api_resource/associations/related_object_hash.rb +12 -0
  22. data/lib/api_resource/associations/relation_scope.rb +30 -0
  23. data/lib/api_resource/associations/resource_scope.rb +34 -0
  24. data/lib/api_resource/associations/scope.rb +107 -0
  25. data/lib/api_resource/associations/single_object_proxy.rb +81 -0
  26. data/lib/api_resource/attributes.rb +162 -0
  27. data/lib/api_resource/base.rb +587 -0
  28. data/lib/api_resource/callbacks.rb +49 -0
  29. data/lib/api_resource/connection.rb +171 -0
  30. data/lib/api_resource/core_extensions.rb +7 -0
  31. data/lib/api_resource/custom_methods.rb +119 -0
  32. data/lib/api_resource/exceptions.rb +87 -0
  33. data/lib/api_resource/formats.rb +14 -0
  34. data/lib/api_resource/formats/json_format.rb +25 -0
  35. data/lib/api_resource/formats/xml_format.rb +36 -0
  36. data/lib/api_resource/local.rb +12 -0
  37. data/lib/api_resource/log_subscriber.rb +15 -0
  38. data/lib/api_resource/mocks.rb +269 -0
  39. data/lib/api_resource/model_errors.rb +86 -0
  40. data/lib/api_resource/observing.rb +29 -0
  41. data/lib/api_resource/railtie.rb +22 -0
  42. data/lib/api_resource/scopes.rb +45 -0
  43. data/spec/lib/associations_spec.rb +656 -0
  44. data/spec/lib/attributes_spec.rb +121 -0
  45. data/spec/lib/base_spec.rb +504 -0
  46. data/spec/lib/callbacks_spec.rb +68 -0
  47. data/spec/lib/connection_spec.rb +76 -0
  48. data/spec/lib/local_spec.rb +20 -0
  49. data/spec/lib/mocks_spec.rb +28 -0
  50. data/spec/lib/model_errors_spec.rb +29 -0
  51. data/spec/spec_helper.rb +36 -0
  52. data/spec/support/mocks/association_mocks.rb +46 -0
  53. data/spec/support/mocks/error_resource_mocks.rb +21 -0
  54. data/spec/support/mocks/test_resource_mocks.rb +43 -0
  55. data/spec/support/requests/association_requests.rb +14 -0
  56. data/spec/support/requests/error_resource_requests.rb +25 -0
  57. data/spec/support/requests/test_resource_requests.rb +31 -0
  58. data/spec/support/test_resource.rb +64 -0
  59. metadata +334 -0
@@ -0,0 +1,121 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ include ApiResource
4
+
5
+ describe "Attributes" do
6
+
7
+ after(:all) do
8
+ TestResource.reload_class_attributes
9
+ end
10
+
11
+ context "Defining, getting, and setting attributes" do
12
+ it "should be able to define known attributes" do
13
+ TestResource.define_attributes :attr1, :attr2
14
+ TestResource.attribute?(:attr1).should be_true
15
+ TestResource.attribute?(:attr2).should be_true
16
+ end
17
+
18
+ it "should define methods for testing for reading and writing known attributes" do
19
+ TestResource.define_attributes :attr1, :attr2
20
+ tst = TestResource.new
21
+ tst.respond_to?(:attr1).should be_true
22
+ tst.respond_to?(:attr1=).should be_true
23
+ tst.respond_to?(:attr1?).should be_true
24
+ end
25
+
26
+ it "should be able to set and change attributes" do
27
+ TestResource.define_attributes :attr1, :attr2
28
+ tst = TestResource.new
29
+ tst.attr1.should be_nil
30
+ tst.attr1?.should be_false
31
+ tst.attr1 = "test"
32
+ tst.attr1.should eql("test")
33
+ tst.attr1?.should be_true
34
+ end
35
+
36
+ it "should be able to set multiple attributes at once" do
37
+ TestResource.define_attributes :attr1, :attr2, :attr3
38
+ tst = TestResource.new
39
+ tst.attr3 = "123"
40
+
41
+ tst.attributes = {:attr1 => "abc", :attr2 => "test"}
42
+ tst.attr1.should eql "abc"
43
+ tst.attr2.should eql "test"
44
+ tst.attr3.should eql "123"
45
+ end
46
+
47
+ end
48
+
49
+ context "Protected attributes" do
50
+ it "should allow protected attributes that cannot be changed" do
51
+ TestResource.define_protected_attributes :pattr3
52
+ lambda {
53
+ tst = TestResource.new
54
+ tst.pattr3 = "test"
55
+ }.should raise_error
56
+ end
57
+ end
58
+
59
+ context "Dirty tracking" do
60
+ context "Changes to attributes" do
61
+ it "should implement dirty tracking for attributes" do
62
+ TestResource.define_attributes :attr1, :attr2
63
+ tst = TestResource.new
64
+ tst.changed.should be_blank
65
+ tst.attr1 = "Hello"
66
+ tst.changed.include?("attr1").should be_true
67
+ tst.changes.should_not be_blank
68
+
69
+ # Set an attribute equal to itself
70
+ tst.attr2 = tst.attr2
71
+ tst.changes.include?("attr2").should be_false
72
+ end
73
+
74
+ end
75
+
76
+ context "Resetting and marking attributes current" do
77
+
78
+ before(:each) do
79
+ TestResource.define_attributes :attr1, :attr2
80
+ end
81
+
82
+ it "should be able to mark any list of attributes as current (unchanged)" do
83
+ tst = TestResource.new
84
+ tst.attr1 = "Hello"
85
+ tst.changed.should_not be_blank
86
+ tst.set_attributes_as_current :attr1, :attr2
87
+ tst.changed.should be_blank
88
+ end
89
+
90
+ it "should be able to mark all the attributes as current if none are given" do
91
+ tst = TestResource.new
92
+ tst.attr1 = "attr1"
93
+ tst.attr2 = "attr2"
94
+ tst.changed.should_not be_blank
95
+ tst.set_attributes_as_current
96
+ tst.changed.should be_blank
97
+ end
98
+
99
+ it "should be able to reset any list of attributes" do
100
+ tst = TestResource.new
101
+ tst.attr1 = "attr1"
102
+ tst.reset_attribute_changes :attr1
103
+ tst.attr1.should be_nil
104
+ tst.changed.should be_blank
105
+ end
106
+
107
+ it "should be able to reset all the attributes if none are given" do
108
+ tst = TestResource.new
109
+ tst.attr1 = "attr1"
110
+ tst.attr2 = "attr2"
111
+
112
+ tst.reset_attribute_changes
113
+ tst.attr1.should be_nil
114
+ tst.attr2.should be_nil
115
+ tst.changed.should be_blank
116
+ end
117
+ end
118
+
119
+ end
120
+
121
+ end
@@ -0,0 +1,504 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+ require 'json'
3
+
4
+ include ApiResource
5
+
6
+ describe "Base" do
7
+
8
+ after(:all) do
9
+ TestResource.reload_class_attributes
10
+ end
11
+
12
+ describe "Loading data from a hash" do
13
+
14
+ describe "Determining Attributes, Scopes, and Associations from the server" do
15
+
16
+ it "should determine it's attributes when the class loads" do
17
+ tst = TestResource.new
18
+ tst.attribute?(:name).should be_true
19
+ tst.attribute?(:age).should be_true
20
+ end
21
+
22
+ it "should determine it's associations when the class loads" do
23
+ tst = TestResource.new
24
+ tst.association?(:has_many_objects).should be_true
25
+ tst.association?(:belongs_to_object).should be_true
26
+ end
27
+
28
+ it "should be able to determine scopes when the class loads" do
29
+ tst = TestResource.new
30
+ tst.scope?(:paginate).should be_true
31
+ tst.scope?(:active).should be_true
32
+ end
33
+
34
+ end
35
+ context "Attributes" do
36
+ before(:all) do
37
+ TestResource.define_attributes :attr1, :attr2
38
+ TestResource.define_protected_attributes :attr3
39
+ end
40
+
41
+ it "should set attributes for the data loaded from a hash" do
42
+ tst = TestResource.new({:attr1 => "attr1", :attr2 => "attr2"})
43
+ tst.attr1?.should be_true
44
+ tst.attr1.should eql("attr1")
45
+ tst.attr1 = "test"
46
+ tst.attr1.should eql("test")
47
+ end
48
+
49
+ it "should create protected attributes for unknown attributes trying to be loaded" do
50
+ tst = TestResource.new({:attr1 => "attr1", :attr3 => "attr3"})
51
+ tst.attr3?.should be_true
52
+ tst.attr3.should eql("attr3")
53
+ lambda {
54
+ tst.attr3 = "test"
55
+ }.should raise_error
56
+ end
57
+ end
58
+
59
+ context "Associations" do
60
+ before(:all) do
61
+ TestResource.has_many :has_many_objects
62
+ TestResource.has_one :has_one_object
63
+ TestResource.belongs_to :belongs_to_object
64
+ end
65
+
66
+ after(:all) do
67
+ TestResource.related_objects.each do |key,val|
68
+ val.clear
69
+ end
70
+ end
71
+
72
+ context "MultiObjectProxy" do
73
+
74
+ it "should create a MultiObjectProxy for has_many associations" do
75
+ tst = TestResource.new({:has_many_objects => []})
76
+ tst.has_many_objects.should be_a(Associations::MultiObjectProxy)
77
+ end
78
+
79
+ it "should throw an error if a has many association is not nil or an array or a hash" do
80
+ TestResource.new({:has_many_objects => nil})
81
+ lambda {
82
+ TestResource.new({:has_many_objects => "invalid"})
83
+ }.should raise_error
84
+ end
85
+
86
+ it "should properly load the data from the provided array or hash" do
87
+ tst = TestResource.new({:has_many_objects => [{:service_uri => '/path'}]})
88
+ tst.has_many_objects.remote_path.should eql('/path')
89
+ tst = TestResource.new({:has_many_objects => {:service_uri => '/path'}})
90
+ tst.has_many_objects.remote_path.should eql('/path')
91
+ end
92
+
93
+ end
94
+
95
+ context "SingleObjectProxy" do
96
+
97
+ it "should create a SingleObjectProxy for belongs to and has_one associations" do
98
+ tst = TestResource.new(:belongs_to_object => {}, :has_one_object => {})
99
+ tst.belongs_to_object.should be_a(Associations::SingleObjectProxy)
100
+ tst.has_one_object.should be_a(Associations::SingleObjectProxy)
101
+ end
102
+
103
+ it "should throw an error if a belongs_to or has_many association is not a hash or nil" do
104
+ lambda {
105
+ TestResource.new(:belongs_to_object => [])
106
+ }.should raise_error
107
+ lambda {
108
+ TestResource.new(:has_one_object => [])
109
+ }.should raise_error
110
+ end
111
+
112
+ it "should properly load data from the provided hash" do
113
+ tst = TestResource.new(:has_one_object => {:service_uri => "/path"})
114
+ tst.has_one_object.remote_path.should eql('/path')
115
+ end
116
+
117
+ end
118
+ end
119
+ end
120
+
121
+ describe "Request parameters and paths" do
122
+
123
+ after(:each) do
124
+ TestResource.element_name = TestResource.model_name.element
125
+ TestResource.collection_name = TestResource.element_name.to_s.pluralize
126
+ end
127
+
128
+ it "should set the element name and collection name by default" do
129
+ TestResource.element_name.should eql("test_resource")
130
+ TestResource.collection_name.should eql("test_resources")
131
+ end
132
+
133
+ it "should inherit element name and collection name from its parent class if using SCI" do
134
+ ChildTestResource.ancestors.should include TestResource
135
+ ChildTestResource.collection_name.should eql "test_resources"
136
+ end
137
+
138
+ it "should be able to set the element and collection names to anything" do
139
+ TestResource.element_name = "element"
140
+ TestResource.collection_name = "elements"
141
+ TestResource.element_name.should eql("element")
142
+ TestResource.collection_name.should eql("elements")
143
+ end
144
+
145
+ it "should propery generate collection paths and element paths with the new names and the default format json" do
146
+ TestResource.element_name = "element"
147
+ TestResource.collection_name = "elements"
148
+ TestResource.new_element_path.should eql("/elements/new.json")
149
+ TestResource.collection_path.should eql("/elements.json")
150
+ TestResource.element_path(1).should eql("/elements/1.json")
151
+ TestResource.element_path(1, :active => true).should eql("/elements/1.json?active=true")
152
+ end
153
+
154
+ it "should be able to set the format" do
155
+ TestResource.format.extension.to_sym.should eql(:json)
156
+ TestResource.format = :xml
157
+ TestResource.format.extension.to_sym.should eql(:xml)
158
+ TestResource.format = :json
159
+ end
160
+
161
+ it "should be able to set an http timeout" do
162
+ TestResource.timeout = 5
163
+ TestResource.timeout.should eql(5)
164
+ TestResource.connection.timeout.should eql(5)
165
+ end
166
+
167
+ end
168
+
169
+ describe "Serialization" do
170
+
171
+ before(:all) do
172
+ TestResource.reload_class_attributes
173
+ TestResource.has_many :has_many_objects
174
+ TestResource.define_attributes :attr1, :attr2
175
+ TestResource.include_root_in_json = true
176
+ end
177
+
178
+ before(:each) do
179
+ TestResource.include_root_in_json = false
180
+ end
181
+
182
+ context "JSON" do
183
+
184
+ it "should be able to serialize itself without the root" do
185
+ TestResource.include_root_in_json = false
186
+ tst = TestResource.new({:attr1 => "attr1", :attr2 => "attr2"})
187
+ hash = JSON.parse(tst.to_json)
188
+ hash["attr1"].should eql("attr1")
189
+ hash["attr2"].should eql("attr2")
190
+ end
191
+
192
+ it "should be able to serialize itself with the root" do
193
+ TestResource.include_root_in_json = true
194
+ tst = TestResource.new({:attr1 => "attr1", :attr2 => "attr2"})
195
+ hash = JSON.parse(tst.to_json)
196
+ hash["test_resource"].should_not be_nil
197
+ end
198
+
199
+ it "should not include associations by default" do
200
+ tst = TestResource.new({:attr1 => "attr1", :attr2 => "attr2", :has_many_objects => []})
201
+ hash = JSON.parse(tst.to_json)
202
+ hash["has_many_objects"].should be_nil
203
+ end
204
+
205
+ it "should include associations passed given in the include_associations array" do
206
+ tst = TestResource.new({:attr1 => "attr1", :attr2 => "attr2", :has_many_objects => []})
207
+ hash = JSON.parse(tst.to_json(:include_associations => [:has_many_objects]))
208
+ hash["has_many_objects"].should_not be_nil
209
+ end
210
+
211
+ it "should not include unknown attributes unless they are passed in via the include_extras array" do
212
+ tst = TestResource.new({:attr1 => "attr1", :attr2 => "attr2", :attr3 => "attr3"})
213
+ hash = JSON.parse(tst.to_json)
214
+ hash["attr3"].should be_nil
215
+ hash = JSON.parse(tst.to_json(:include_extras => [:attr3]))
216
+ hash["attr3"].should_not be_nil
217
+ end
218
+
219
+ it "should ignore fields set under the except option" do
220
+ tst = TestResource.new({:attr1 => "attr1", :attr2 => "attr2", :attr3 => "attr3"})
221
+ hash = JSON.parse(tst.to_json(:except => [:attr1]))
222
+ hash["attr1"].should be_nil
223
+ end
224
+
225
+ context "Nested Objects" do
226
+ before(:all) do
227
+ TestResource.has_many(:has_many_objects)
228
+ end
229
+ after(:all) do
230
+ TestResource.reload_class_attributes
231
+ end
232
+
233
+ it "should include the id of nested objects in the serialization" do
234
+ tst = TestResource.new({:attr1 => "attr1", :attr2 => "attr2", :has_many_objects => [{:name => "123", :id => "1"}]})
235
+ hash = JSON.parse(tst.to_json(:include_associations => [:has_many_objects]))
236
+ hash["has_many_objects"].first["id"].should_not be nil
237
+ end
238
+ it "should include the id of nested objects in the serialization" do
239
+ tst = TestResource.new({:attr1 => "attr1", :attr2 => "attr2", :has_many_objects => [{:name => "123"}]})
240
+ hash = JSON.parse(tst.to_json(:include_associations => [:has_many_objects]))
241
+ hash["has_many_objects"].first.keys.should_not include "id"
242
+ end
243
+ end
244
+ end
245
+
246
+ context "XML" do
247
+
248
+ it "should only be able to serialize itself with the root" do
249
+ tst = TestResource.new({:attr1 => "attr1", :attr2 => "attr2"})
250
+ hash = Hash.from_xml(tst.to_xml)
251
+ hash["test_resource"].should_not be_nil
252
+ end
253
+
254
+ it "should properly serialize associations if they are included" do
255
+ tst = TestResource.new({:attr1 => "attr1", :attr2 => "attr2", :has_many_objects => []})
256
+ hash = Hash.from_xml(tst.to_xml(:include_associations => [:has_many_objects]))
257
+ hash["test_resource"]["has_many_objects"].should eql([])
258
+ end
259
+ end
260
+
261
+ end
262
+
263
+ describe "Finding Data" do
264
+
265
+ before(:all) do
266
+ TestResource.reload_class_attributes
267
+ end
268
+
269
+ it "should be able to find all" do
270
+ resources = TestResource.find(:all)
271
+ resources.size.should eql(5)
272
+ resources.each{|r| r.should be_a TestResource}
273
+ end
274
+
275
+ it "should be able to find first or last" do
276
+ res = TestResource.first
277
+ res.should be_a TestResource
278
+ res.name.should_not be_blank
279
+ res.age.should_not be_blank
280
+
281
+ res = TestResource.last
282
+ res.should be_a TestResource
283
+ res.name.should_not be_blank
284
+ res.age.should_not be_blank
285
+ end
286
+
287
+ it "should be able to find by id" do
288
+ res = TestResource.find(2)
289
+ res.should be_a TestResource
290
+ res.id.to_i.should eql(2)
291
+ end
292
+
293
+ end
294
+
295
+ describe "Saving Data" do
296
+
297
+ before(:all) do
298
+ TestResource.include_root_in_json = true
299
+ TestResource.reload_class_attributes
300
+ end
301
+
302
+ context "Creating new records" do
303
+
304
+ before(:all) do
305
+ TestResource.has_many :has_many_objects
306
+ end
307
+
308
+ it "should be able to post new data via the create method" do
309
+ tr = TestResource.create({:name => "Ethan", :age => 20})
310
+ tr.id.should_not be_blank
311
+ end
312
+
313
+ it "should be able to post new data via the save method" do
314
+ tr = TestResource.build({:name => "Ethan", :age => 20})
315
+ tr.save.should be_true
316
+ tr.id.should_not be_blank
317
+ end
318
+
319
+ context("Override create to return the json") do
320
+
321
+ before(:all) do
322
+ TestResource.send(:alias_method, :old_create, :create)
323
+ TestResource.send(:alias_method, :old_save, :save)
324
+
325
+ TestResource.send(:define_method, :create) do |*args|
326
+ opts = args.extract_options!
327
+ # When we create we should not include any blank attributes unless they are associations
328
+ except = self.class.include_blank_attributes_on_create ? {} : self.attributes.select{|k,v| v.blank?}
329
+ opts[:except] = opts[:except] ? opts[:except].concat(except.keys).uniq.symbolize_array : except.keys.symbolize_array
330
+ opts[:include_associations] = opts[:include_associations] ? opts[:include_associations].concat(args) : []
331
+ opts[:include_extras] ||= []
332
+ encode(opts)
333
+ end
334
+ TestResource.send(:define_method, :save) do |*args|
335
+ new? ? create(*args) : update(*args)
336
+ end
337
+ end
338
+
339
+ after(:all) do
340
+ TestResource.send(:alias_method, :create, :old_create)
341
+ TestResource.send(:alias_method, :save, :old_save)
342
+ end
343
+
344
+ it "should be able to include associations when saving if they are specified" do
345
+ tr = TestResource.build(:name => "Ethan", :age => 20)
346
+ hash = JSON.parse(tr.save)
347
+ hash['test_resource']['has_many_objects'].should be_nil
348
+ hash = JSON.parse(tr.save(:include_associations => [:has_many_objects]))
349
+ hash['test_resource']['has_many_objects'].should eql([])
350
+ end
351
+
352
+ it "should not include nil attributes when creating by default" do
353
+ tr = TestResource.build(:name => "Ethan")
354
+ hash = JSON.parse(tr.save)
355
+ hash['test_resource']['age'].should be_nil
356
+ hash['test_resource']['name'].should eql("Ethan")
357
+ end
358
+
359
+ it "should include nil attributes if they are passed in through the include_extras" do
360
+ tr = TestResource.build(:name => "Ethan")
361
+ hash = JSON.parse(tr.save(:include_extras => [:age]))
362
+ hash['test_resource'].key?('age').should be_true
363
+ end
364
+
365
+ it "should include nil attributes when creating if include_nil_attributes_on_create is true" do
366
+ TestResource.include_blank_attributes_on_create = true
367
+ tr = TestResource.build(:name => "Ethan")
368
+ hash = JSON.parse(tr.save)
369
+ hash['test_resource'].key?('age').should be_true
370
+ TestResource.include_blank_attributes_on_create = false
371
+ end
372
+ end
373
+ end
374
+
375
+ context "Updating old records" do
376
+ before(:all) do
377
+ TestResource.reload_class_attributes
378
+ TestResource.has_many :has_many_objects
379
+
380
+ TestResource.send(:alias_method, :old_update, :update)
381
+ TestResource.send(:alias_method, :old_save, :save)
382
+
383
+ TestResource.send(:define_method, :update) do |*args|
384
+ opts = args.extract_options!
385
+ # When we create we should not include any blank attributes
386
+ except = self.class.attribute_names - self.changed.symbolize_array
387
+ changed_associations = self.changed.symbolize_array.select{|item| self.association?(item)}
388
+ opts[:except] = opts[:except] ? opts[:except].concat(except).uniq.symbolize_array : except.symbolize_array
389
+ opts[:include_associations] = opts[:include_associations] ? opts[:include_associations].concat(args).concat(changed_associations).uniq : changed_associations.concat(args)
390
+ opts[:include_extras] ||= []
391
+ opts[:except] = [:id] if self.class.include_all_attributes_on_update
392
+ encode(opts)
393
+ end
394
+ TestResource.send(:define_method, :save) do |*args|
395
+ new? ? create(*args) : update(*args)
396
+ end
397
+ end
398
+
399
+ after(:all) do
400
+ TestResource.send(:alias_method, :update, :old_update)
401
+ TestResource.send(:alias_method, :save, :old_save)
402
+ end
403
+
404
+ it "should be able to put updated data via the update method" do
405
+ tr = TestResource.new(:id => 1, :name => "Ethan")
406
+ tr.should_not be_new
407
+ # Thus we know we are calling update
408
+ tr.age = 6
409
+ hash = JSON.parse(tr.update)
410
+ hash['test_resource']['age'].should eql(6)
411
+
412
+ hash = JSON.parse(tr.save)
413
+ hash['test_resource']['age'].should eql(6)
414
+ end
415
+
416
+ it "should only include changed attributes when updating" do
417
+ tr = TestResource.new(:id => 1, :name => "Ethan")
418
+ tr.should_not be_new
419
+ # Thus we know we are calling update
420
+ tr.age = 6
421
+ hash = JSON.parse(tr.save)
422
+ hash['test_resource']['name'].should be_nil
423
+ end
424
+
425
+ it "should include changed associations without specification" do
426
+ tr = TestResource.new(:id => 1, :name => "Ethan")
427
+ tr.has_many_objects = [HasManyObject.new]
428
+ hash = JSON.parse(tr.save)
429
+ hash['test_resource']['has_many_objects'].should_not be_blank
430
+ end
431
+
432
+ it "should include unchanged associations if they are specified" do
433
+ tr = TestResource.new(:id => 1, :name => "Ethan")
434
+ hash = JSON.parse(tr.save(:has_many_objects))
435
+ hash['test_resource']['has_many_objects'].should eql([])
436
+ end
437
+
438
+ it "should include all attributes if include_all_attributes_on_update is true" do
439
+ TestResource.include_all_attributes_on_update = true
440
+ tr = TestResource.new(:id => 1, :name => "Ethan")
441
+ hash = JSON.parse(tr.save)
442
+ hash['test_resource']['name'].should eql("Ethan")
443
+ hash['test_resource'].key?('age').should be_true
444
+ TestResource.include_all_attributes_on_update = false
445
+ end
446
+
447
+ it "should provide an update_attributes method to set attrs and save" do
448
+
449
+ tr = TestResource.new(:id => 1, :name => "Ethan")
450
+ hash = JSON.parse(tr.update_attributes(:name => "Dan"))
451
+ hash['test_resource']['name'].should eql "Dan"
452
+
453
+ end
454
+
455
+
456
+ end
457
+
458
+ end
459
+
460
+ describe "Deleting data" do
461
+ it "should be able to delete an id from the class method" do
462
+ TestResource.delete(1).should be_true
463
+ end
464
+
465
+ it "should be able to destroy itself as an instance" do
466
+ tr = TestResource.new(:id => 1, :name => "Ethan")
467
+ tr.destroy.should be_true
468
+ end
469
+ end
470
+
471
+ describe "Random methods" do
472
+
473
+ it "should know if it is persisted" do
474
+ tr = TestResource.new(:id => 1, :name => "Ethan")
475
+ tr.persisted?.should be_true
476
+ tr = TestResource.new(:name => "Ethan")
477
+ tr.persisted?.should be_false
478
+ end
479
+
480
+ end
481
+
482
+ describe "Inheritable Accessors" do
483
+
484
+ it "should copy the default values down to any level of subclass" do
485
+
486
+ class Child < TestResource
487
+ end
488
+
489
+ Child.site.should eql(TestResource.site)
490
+ Child.site.should_not be_blank
491
+ end
492
+
493
+ end
494
+
495
+ describe "Inflections" do
496
+
497
+ it "should be able to singularize and pluralize words ending in ess" do
498
+ "address".singularize.should eql("address")
499
+ "address".pluralize.should eql("addresses")
500
+ end
501
+
502
+ end
503
+
504
+ end