humanoid 1.2.7

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 (210) hide show
  1. data/.gitignore +6 -0
  2. data/.watchr +29 -0
  3. data/HISTORY +342 -0
  4. data/MIT_LICENSE +20 -0
  5. data/README.rdoc +56 -0
  6. data/Rakefile +53 -0
  7. data/VERSION +1 -0
  8. data/caliper.yml +4 -0
  9. data/humanoid.gemspec +374 -0
  10. data/lib/humanoid.rb +111 -0
  11. data/lib/humanoid/associations.rb +258 -0
  12. data/lib/humanoid/associations/belongs_to.rb +64 -0
  13. data/lib/humanoid/associations/belongs_to_related.rb +62 -0
  14. data/lib/humanoid/associations/has_many.rb +180 -0
  15. data/lib/humanoid/associations/has_many_related.rb +109 -0
  16. data/lib/humanoid/associations/has_one.rb +95 -0
  17. data/lib/humanoid/associations/has_one_related.rb +81 -0
  18. data/lib/humanoid/associations/options.rb +57 -0
  19. data/lib/humanoid/associations/proxy.rb +31 -0
  20. data/lib/humanoid/attributes.rb +184 -0
  21. data/lib/humanoid/callbacks.rb +23 -0
  22. data/lib/humanoid/collection.rb +118 -0
  23. data/lib/humanoid/collections/cyclic_iterator.rb +34 -0
  24. data/lib/humanoid/collections/master.rb +28 -0
  25. data/lib/humanoid/collections/mimic.rb +46 -0
  26. data/lib/humanoid/collections/operations.rb +41 -0
  27. data/lib/humanoid/collections/slaves.rb +44 -0
  28. data/lib/humanoid/commands.rb +182 -0
  29. data/lib/humanoid/commands/create.rb +21 -0
  30. data/lib/humanoid/commands/delete.rb +16 -0
  31. data/lib/humanoid/commands/delete_all.rb +23 -0
  32. data/lib/humanoid/commands/deletion.rb +18 -0
  33. data/lib/humanoid/commands/destroy.rb +19 -0
  34. data/lib/humanoid/commands/destroy_all.rb +23 -0
  35. data/lib/humanoid/commands/save.rb +27 -0
  36. data/lib/humanoid/components.rb +24 -0
  37. data/lib/humanoid/config.rb +84 -0
  38. data/lib/humanoid/contexts.rb +25 -0
  39. data/lib/humanoid/contexts/enumerable.rb +117 -0
  40. data/lib/humanoid/contexts/ids.rb +25 -0
  41. data/lib/humanoid/contexts/mongo.rb +224 -0
  42. data/lib/humanoid/contexts/paging.rb +42 -0
  43. data/lib/humanoid/criteria.rb +259 -0
  44. data/lib/humanoid/criterion/complex.rb +21 -0
  45. data/lib/humanoid/criterion/exclusion.rb +65 -0
  46. data/lib/humanoid/criterion/inclusion.rb +91 -0
  47. data/lib/humanoid/criterion/optional.rb +128 -0
  48. data/lib/humanoid/cursor.rb +82 -0
  49. data/lib/humanoid/document.rb +300 -0
  50. data/lib/humanoid/enslavement.rb +38 -0
  51. data/lib/humanoid/errors.rb +77 -0
  52. data/lib/humanoid/extensions.rb +84 -0
  53. data/lib/humanoid/extensions/array/accessors.rb +17 -0
  54. data/lib/humanoid/extensions/array/aliasing.rb +4 -0
  55. data/lib/humanoid/extensions/array/assimilation.rb +26 -0
  56. data/lib/humanoid/extensions/array/conversions.rb +29 -0
  57. data/lib/humanoid/extensions/array/parentization.rb +13 -0
  58. data/lib/humanoid/extensions/boolean/conversions.rb +16 -0
  59. data/lib/humanoid/extensions/date/conversions.rb +15 -0
  60. data/lib/humanoid/extensions/datetime/conversions.rb +17 -0
  61. data/lib/humanoid/extensions/float/conversions.rb +16 -0
  62. data/lib/humanoid/extensions/hash/accessors.rb +38 -0
  63. data/lib/humanoid/extensions/hash/assimilation.rb +30 -0
  64. data/lib/humanoid/extensions/hash/conversions.rb +15 -0
  65. data/lib/humanoid/extensions/hash/criteria_helpers.rb +20 -0
  66. data/lib/humanoid/extensions/hash/scoping.rb +12 -0
  67. data/lib/humanoid/extensions/integer/conversions.rb +16 -0
  68. data/lib/humanoid/extensions/nil/assimilation.rb +13 -0
  69. data/lib/humanoid/extensions/object/conversions.rb +33 -0
  70. data/lib/humanoid/extensions/proc/scoping.rb +12 -0
  71. data/lib/humanoid/extensions/string/conversions.rb +15 -0
  72. data/lib/humanoid/extensions/string/inflections.rb +97 -0
  73. data/lib/humanoid/extensions/symbol/inflections.rb +36 -0
  74. data/lib/humanoid/extensions/time/conversions.rb +18 -0
  75. data/lib/humanoid/factory.rb +19 -0
  76. data/lib/humanoid/field.rb +39 -0
  77. data/lib/humanoid/fields.rb +62 -0
  78. data/lib/humanoid/finders.rb +224 -0
  79. data/lib/humanoid/identity.rb +39 -0
  80. data/lib/humanoid/indexes.rb +30 -0
  81. data/lib/humanoid/matchers.rb +36 -0
  82. data/lib/humanoid/matchers/all.rb +11 -0
  83. data/lib/humanoid/matchers/default.rb +26 -0
  84. data/lib/humanoid/matchers/exists.rb +13 -0
  85. data/lib/humanoid/matchers/gt.rb +11 -0
  86. data/lib/humanoid/matchers/gte.rb +11 -0
  87. data/lib/humanoid/matchers/in.rb +11 -0
  88. data/lib/humanoid/matchers/lt.rb +11 -0
  89. data/lib/humanoid/matchers/lte.rb +11 -0
  90. data/lib/humanoid/matchers/ne.rb +11 -0
  91. data/lib/humanoid/matchers/nin.rb +11 -0
  92. data/lib/humanoid/matchers/size.rb +11 -0
  93. data/lib/humanoid/memoization.rb +27 -0
  94. data/lib/humanoid/named_scope.rb +40 -0
  95. data/lib/humanoid/scope.rb +75 -0
  96. data/lib/humanoid/timestamps.rb +30 -0
  97. data/lib/humanoid/versioning.rb +28 -0
  98. data/perf/benchmark.rb +77 -0
  99. data/spec/integration/humanoid/associations_spec.rb +301 -0
  100. data/spec/integration/humanoid/attributes_spec.rb +22 -0
  101. data/spec/integration/humanoid/commands_spec.rb +216 -0
  102. data/spec/integration/humanoid/contexts/enumerable_spec.rb +33 -0
  103. data/spec/integration/humanoid/criteria_spec.rb +224 -0
  104. data/spec/integration/humanoid/document_spec.rb +587 -0
  105. data/spec/integration/humanoid/extensions_spec.rb +26 -0
  106. data/spec/integration/humanoid/finders_spec.rb +119 -0
  107. data/spec/integration/humanoid/inheritance_spec.rb +137 -0
  108. data/spec/integration/humanoid/named_scope_spec.rb +46 -0
  109. data/spec/models/address.rb +39 -0
  110. data/spec/models/animal.rb +6 -0
  111. data/spec/models/comment.rb +8 -0
  112. data/spec/models/country_code.rb +6 -0
  113. data/spec/models/employer.rb +5 -0
  114. data/spec/models/game.rb +6 -0
  115. data/spec/models/inheritance.rb +56 -0
  116. data/spec/models/location.rb +5 -0
  117. data/spec/models/mixed_drink.rb +4 -0
  118. data/spec/models/name.rb +13 -0
  119. data/spec/models/namespacing.rb +11 -0
  120. data/spec/models/patient.rb +4 -0
  121. data/spec/models/person.rb +98 -0
  122. data/spec/models/pet.rb +7 -0
  123. data/spec/models/pet_owner.rb +6 -0
  124. data/spec/models/phone.rb +7 -0
  125. data/spec/models/post.rb +15 -0
  126. data/spec/models/translation.rb +5 -0
  127. data/spec/models/vet_visit.rb +5 -0
  128. data/spec/spec.opts +3 -0
  129. data/spec/spec_helper.rb +31 -0
  130. data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +141 -0
  131. data/spec/unit/mongoid/associations/belongs_to_spec.rb +193 -0
  132. data/spec/unit/mongoid/associations/has_many_related_spec.rb +387 -0
  133. data/spec/unit/mongoid/associations/has_many_spec.rb +471 -0
  134. data/spec/unit/mongoid/associations/has_one_related_spec.rb +179 -0
  135. data/spec/unit/mongoid/associations/has_one_spec.rb +282 -0
  136. data/spec/unit/mongoid/associations/options_spec.rb +191 -0
  137. data/spec/unit/mongoid/associations_spec.rb +545 -0
  138. data/spec/unit/mongoid/attributes_spec.rb +484 -0
  139. data/spec/unit/mongoid/callbacks_spec.rb +55 -0
  140. data/spec/unit/mongoid/collection_spec.rb +171 -0
  141. data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
  142. data/spec/unit/mongoid/collections/master_spec.rb +41 -0
  143. data/spec/unit/mongoid/collections/mimic_spec.rb +43 -0
  144. data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
  145. data/spec/unit/mongoid/commands/create_spec.rb +30 -0
  146. data/spec/unit/mongoid/commands/delete_all_spec.rb +58 -0
  147. data/spec/unit/mongoid/commands/delete_spec.rb +35 -0
  148. data/spec/unit/mongoid/commands/destroy_all_spec.rb +23 -0
  149. data/spec/unit/mongoid/commands/destroy_spec.rb +44 -0
  150. data/spec/unit/mongoid/commands/save_spec.rb +105 -0
  151. data/spec/unit/mongoid/commands_spec.rb +282 -0
  152. data/spec/unit/mongoid/config_spec.rb +165 -0
  153. data/spec/unit/mongoid/contexts/enumerable_spec.rb +374 -0
  154. data/spec/unit/mongoid/contexts/mongo_spec.rb +505 -0
  155. data/spec/unit/mongoid/contexts_spec.rb +25 -0
  156. data/spec/unit/mongoid/criteria_spec.rb +769 -0
  157. data/spec/unit/mongoid/criterion/complex_spec.rb +19 -0
  158. data/spec/unit/mongoid/criterion/exclusion_spec.rb +91 -0
  159. data/spec/unit/mongoid/criterion/inclusion_spec.rb +211 -0
  160. data/spec/unit/mongoid/criterion/optional_spec.rb +329 -0
  161. data/spec/unit/mongoid/cursor_spec.rb +74 -0
  162. data/spec/unit/mongoid/document_spec.rb +986 -0
  163. data/spec/unit/mongoid/enslavement_spec.rb +63 -0
  164. data/spec/unit/mongoid/errors_spec.rb +103 -0
  165. data/spec/unit/mongoid/extensions/array/accessors_spec.rb +50 -0
  166. data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +24 -0
  167. data/spec/unit/mongoid/extensions/array/conversions_spec.rb +35 -0
  168. data/spec/unit/mongoid/extensions/array/parentization_spec.rb +20 -0
  169. data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +49 -0
  170. data/spec/unit/mongoid/extensions/date/conversions_spec.rb +102 -0
  171. data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +70 -0
  172. data/spec/unit/mongoid/extensions/float/conversions_spec.rb +61 -0
  173. data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +184 -0
  174. data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +46 -0
  175. data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +21 -0
  176. data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +17 -0
  177. data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +14 -0
  178. data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +61 -0
  179. data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +24 -0
  180. data/spec/unit/mongoid/extensions/object/conversions_spec.rb +43 -0
  181. data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +34 -0
  182. data/spec/unit/mongoid/extensions/string/conversions_spec.rb +17 -0
  183. data/spec/unit/mongoid/extensions/string/inflections_spec.rb +208 -0
  184. data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +91 -0
  185. data/spec/unit/mongoid/extensions/time/conversions_spec.rb +70 -0
  186. data/spec/unit/mongoid/factory_spec.rb +31 -0
  187. data/spec/unit/mongoid/field_spec.rb +81 -0
  188. data/spec/unit/mongoid/fields_spec.rb +158 -0
  189. data/spec/unit/mongoid/finders_spec.rb +368 -0
  190. data/spec/unit/mongoid/identity_spec.rb +88 -0
  191. data/spec/unit/mongoid/indexes_spec.rb +93 -0
  192. data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
  193. data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
  194. data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
  195. data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
  196. data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
  197. data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
  198. data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
  199. data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
  200. data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
  201. data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
  202. data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
  203. data/spec/unit/mongoid/matchers_spec.rb +329 -0
  204. data/spec/unit/mongoid/memoization_spec.rb +75 -0
  205. data/spec/unit/mongoid/named_scope_spec.rb +123 -0
  206. data/spec/unit/mongoid/scope_spec.rb +240 -0
  207. data/spec/unit/mongoid/timestamps_spec.rb +25 -0
  208. data/spec/unit/mongoid/versioning_spec.rb +41 -0
  209. data/spec/unit/mongoid_spec.rb +37 -0
  210. metadata +431 -0
@@ -0,0 +1,484 @@
1
+ require "spec_helper"
2
+
3
+ describe Humanoid::Attributes do
4
+
5
+ describe ".accepts_nested_attributes_for" do
6
+
7
+ before do
8
+ @person = Person.new
9
+ end
10
+
11
+ it "adds a setter for the association attributes" do
12
+ @person.should respond_to(:addresses_attributes=)
13
+ end
14
+
15
+ describe "#association_attributes=" do
16
+
17
+ context "on a has many association" do
18
+
19
+ context "when a reject block supplied" do
20
+
21
+ before do
22
+ @attributes = {
23
+ "0" => { "city" => "San Francisco" }
24
+ }
25
+ @person.addresses_attributes = @attributes
26
+ end
27
+
28
+ it "removes the attributes that match" do
29
+ @person.addresses.should be_empty
30
+ end
31
+
32
+ end
33
+
34
+ context "when association is empty" do
35
+
36
+ before do
37
+ @attributes = {
38
+ "0" => { "street" => "Folsom", "city" => "San Francisco" }
39
+ }
40
+ @person.addresses_attributes = @attributes
41
+ end
42
+
43
+ it "adds a new document to the association" do
44
+ address = @person.addresses.first
45
+ address.street.should == "Folsom"
46
+ address.city.should == "San Francisco"
47
+ end
48
+
49
+ end
50
+
51
+ context "when association is not empty" do
52
+
53
+ before do
54
+ @person = Person.new
55
+ @person.addresses.build(:street => "Broadway", :city => "New York")
56
+ @attributes = {
57
+ "0" => { "street" => "Folsom", "city" => "San Francisco" }
58
+ }
59
+ @person.addresses_attributes = @attributes
60
+ end
61
+
62
+ it "updates the existing attributes on the association" do
63
+ @person.addresses.size.should == 2
64
+ end
65
+
66
+ end
67
+
68
+ end
69
+
70
+ context "on a has one association" do
71
+
72
+ before do
73
+ @person = Person.new
74
+ @attributes = {
75
+ "first_name" => "Fernando", "last_name" => "Torres"
76
+ }
77
+ @person.name_attributes = @attributes
78
+ end
79
+
80
+ it "replaces the document on the association" do
81
+ name = @person.name
82
+ name.first_name.should == "Fernando"
83
+ name.last_name.should == "Torres"
84
+ end
85
+
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+
92
+ describe "#_id" do
93
+
94
+ before do
95
+ @person = Person.new
96
+ end
97
+
98
+ it "delegates to #id" do
99
+ @person._id.should == @person.id
100
+ end
101
+
102
+ end
103
+
104
+ describe "#_id=" do
105
+
106
+ before do
107
+ @person = Person.new
108
+ end
109
+
110
+ it "delegates to #id=" do
111
+ @id = Mongo::ObjectID.new.to_s
112
+ @person._id = @id
113
+ @person.id.should == @id
114
+ end
115
+
116
+ end
117
+
118
+ describe "#method_missing" do
119
+
120
+ before do
121
+ Humanoid.configure.allow_dynamic_fields = true
122
+ @attributes = {
123
+ :testing => "Testing"
124
+ }
125
+ @person = Person.new(@attributes)
126
+ end
127
+
128
+ context "when an attribute exists" do
129
+
130
+ it "allows the getter" do
131
+ @person.testing.should == "Testing"
132
+ end
133
+
134
+ it "allows the setter" do
135
+ @person.testing = "Test"
136
+ @person.testing.should == "Test"
137
+ end
138
+
139
+ end
140
+
141
+ end
142
+
143
+ describe "#process" do
144
+
145
+ context "when attributes dont have fields defined" do
146
+
147
+ before do
148
+ @attributes = {
149
+ :nofieldstring => "Testing",
150
+ :nofieldint => 5,
151
+ :employer => Employer.new
152
+ }
153
+ end
154
+
155
+ context "when allowing dynamic fields" do
156
+
157
+ before do
158
+ Humanoid.configure.allow_dynamic_fields = true
159
+ @person = Person.new(@attributes)
160
+ end
161
+
162
+ context "when attribute is a string" do
163
+
164
+ it "adds the string to the attributes" do
165
+ @person.attributes[:nofieldstring].should == "Testing"
166
+ end
167
+
168
+ end
169
+
170
+ context "when attribute is not a string" do
171
+
172
+ it "adds a cast value to the attributes" do
173
+ @person.attributes[:nofieldint].should == 5
174
+ end
175
+
176
+ end
177
+
178
+ end
179
+
180
+ context "when not allowing dynamic fields" do
181
+
182
+ before do
183
+ Humanoid.configure.allow_dynamic_fields = false
184
+ Person.fields.delete(:nofieldstring)
185
+ @attributes = {
186
+ :nofieldstring => "Testing"
187
+ }
188
+ end
189
+
190
+ after do
191
+ Humanoid.configure.allow_dynamic_fields = true
192
+ end
193
+
194
+ it "raises an error" do
195
+ lambda { Person.new(@attributes) }.should raise_error
196
+ end
197
+
198
+ end
199
+
200
+ end
201
+
202
+ context "when supplied hash has values" do
203
+
204
+ before do
205
+ @attributes = {
206
+ :_id => "1",
207
+ :title => "value",
208
+ :age => "30",
209
+ :terms => "true",
210
+ :score => "",
211
+ :name => {
212
+ :_id => "2", :first_name => "Test", :last_name => "User"
213
+ },
214
+ :addresses => [
215
+ { :_id => "3", :street => "First Street" },
216
+ { :_id => "4", :street => "Second Street" }
217
+ ]
218
+ }
219
+ end
220
+
221
+ it "returns properly cast attributes" do
222
+ attrs = Person.new(@attributes).attributes
223
+ attrs[:age].should == 30
224
+ attrs[:terms].should == true
225
+ attrs[:_id].should == "1"
226
+ attrs[:score].should be_nil
227
+ end
228
+
229
+ end
230
+
231
+ context "when associations provided in the attributes" do
232
+
233
+ context "when association is a has_one" do
234
+
235
+ before do
236
+ @name = Name.new(:first_name => "Testy")
237
+ @attributes = {
238
+ :name => @name
239
+ }
240
+ @person = Person.new(@attributes)
241
+ end
242
+
243
+ it "sets the associations" do
244
+ @person.name.should == @name
245
+ end
246
+
247
+ end
248
+
249
+ context "when association is a belongs_to" do
250
+
251
+ before do
252
+ @person = Person.new
253
+ @name = Name.new(:first_name => "Tyler", :person => @person)
254
+ end
255
+
256
+ it "sets the association" do
257
+ @name.person.should == @person
258
+ end
259
+
260
+ end
261
+
262
+ end
263
+
264
+ context "when non-associations provided in the attributes" do
265
+
266
+ before do
267
+ @employer = Employer.new
268
+ @attributes = { :employer_id => @employer.id, :title => "Sir" }
269
+ @person = Person.new(@attributes)
270
+ end
271
+
272
+ it "calls the setter for the association" do
273
+ @person.employer_id.should == "1"
274
+ end
275
+
276
+ end
277
+
278
+ context "when an empty array is provided in the attributes" do
279
+
280
+ before do
281
+ @attributes = {
282
+ :aliases => []
283
+ }
284
+ @person = Person.new(@attributes)
285
+ end
286
+
287
+ it "sets the empty array" do
288
+ @person.aliases.should == []
289
+ end
290
+
291
+ end
292
+
293
+ context "when an empty hash is provided in the attributes" do
294
+
295
+ before do
296
+ @attributes = {
297
+ :map => {}
298
+ }
299
+ @person = Person.new(@attributes)
300
+ end
301
+
302
+ it "sets the empty hash" do
303
+ @person.map.should == {}
304
+ end
305
+
306
+ end
307
+
308
+ end
309
+
310
+ context "updating when attributes already exist" do
311
+
312
+ before do
313
+ @person = Person.new(:title => "Sir")
314
+ @attributes = { :dob => "2000-01-01" }
315
+ end
316
+
317
+ it "only overwrites supplied attributes" do
318
+ @person.process(@attributes)
319
+ @person.title.should == "Sir"
320
+ end
321
+
322
+ end
323
+
324
+ describe "#read_attribute" do
325
+
326
+ context "when attribute does not exist" do
327
+
328
+ before do
329
+ @person = Person.new
330
+ end
331
+
332
+ it "returns the default value" do
333
+ @person.age.should == 100
334
+ @person.pets.should == false
335
+ end
336
+
337
+ end
338
+
339
+ end
340
+
341
+ describe "#remove_attribute" do
342
+
343
+ context "when the attribute exists" do
344
+
345
+ it "removes the attribute" do
346
+ person = Person.new(:title => "Sir")
347
+ person.remove_attribute(:title)
348
+ person.title.should be_nil
349
+ end
350
+
351
+ end
352
+
353
+ context "when the attribute does not exist" do
354
+
355
+ it "does nothing" do
356
+ person = Person.new
357
+ person.remove_attribute(:title)
358
+ person.title.should be_nil
359
+ end
360
+
361
+ end
362
+
363
+ end
364
+
365
+ describe "#write_attribute" do
366
+
367
+ context "when attribute does not exist" do
368
+
369
+ before do
370
+ @person = Person.new
371
+ end
372
+
373
+ it "returns the default value" do
374
+ @person.age = nil
375
+ @person.age.should == 100
376
+ end
377
+
378
+ end
379
+
380
+ context "when field has a default value" do
381
+
382
+ before do
383
+ @person = Person.new
384
+ end
385
+
386
+ it "should allow overwriting of the default value" do
387
+ @person.terms = true
388
+ @person.terms.should be_true
389
+ end
390
+
391
+ end
392
+
393
+ end
394
+
395
+ describe "#attributes=" do
396
+ it 'should be a alias of write_attributes' do
397
+
398
+ end
399
+ end
400
+
401
+ [:attributes=, :write_attributes].each do |method|
402
+ describe "##{method}" do
403
+
404
+ context "typecasting" do
405
+
406
+ before do
407
+ @person = Person.new
408
+ @attributes = { :age => "50" }
409
+ end
410
+
411
+ it "properly casts values" do
412
+ @person.send(method, @attributes)
413
+ @person.age.should == 50
414
+ end
415
+
416
+ it "allows passing of nil" do
417
+ @person.send(method, nil)
418
+ @person.age.should == 100
419
+ end
420
+
421
+ end
422
+
423
+ context "on a parent document" do
424
+
425
+ context "when the parent has a has many through a has one" do
426
+
427
+ before do
428
+ @owner = PetOwner.new(:title => "Mr")
429
+ @pet = Pet.new(:name => "Fido")
430
+ @owner.pet = @pet
431
+ @vet_visit = VetVisit.new(:date => Date.today)
432
+ @pet.vet_visits = [@vet_visit]
433
+ end
434
+
435
+ it "does not overwrite child attributes if not in the hash" do
436
+ @owner.send(method, { :pet => { :name => "Bingo" } })
437
+ @owner.pet.name.should == "Bingo"
438
+ @owner.pet.vet_visits.size.should == 1
439
+ end
440
+
441
+ end
442
+
443
+ end
444
+
445
+ context "on a child document" do
446
+
447
+ context "when child is part of a has one" do
448
+
449
+ before do
450
+ @person = Person.new(:title => "Sir", :age => 30)
451
+ @name = Name.new(:first_name => "Test", :last_name => "User")
452
+ @person.name = @name
453
+ end
454
+
455
+ it "sets the child attributes on the parent" do
456
+ @name.send(method, :first_name => "Test2", :last_name => "User2")
457
+ @person.attributes[:name].should ==
458
+ { "_id" => "test-user", "first_name" => "Test2", "last_name" => "User2", "_type" => "Name" }
459
+ end
460
+
461
+ end
462
+
463
+ context "when child is part of a has many" do
464
+
465
+ before do
466
+ @person = Person.new(:title => "Sir")
467
+ @address = Address.new(:street => "Test")
468
+ @person.addresses << @address
469
+ end
470
+
471
+ it "updates the child attributes on the parent" do
472
+ @address.send(method, "street" => "Test2")
473
+ @person.attributes[:addresses].should ==
474
+ [ { "_id" => "test", "street" => "Test2", "_type" => "Address" } ]
475
+ end
476
+
477
+ end
478
+
479
+ end
480
+ end
481
+
482
+ end
483
+
484
+ end