api_resource 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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