mongoid-locomotive 2.0.0.beta9

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 (274) hide show
  1. data/MIT_LICENSE +20 -0
  2. data/README.rdoc +47 -0
  3. data/lib/mongoid.rb +141 -0
  4. data/lib/mongoid/associations.rb +306 -0
  5. data/lib/mongoid/associations/embedded_in.rb +74 -0
  6. data/lib/mongoid/associations/embeds_many.rb +280 -0
  7. data/lib/mongoid/associations/embeds_one.rb +97 -0
  8. data/lib/mongoid/associations/foreign_key.rb +35 -0
  9. data/lib/mongoid/associations/meta_data.rb +38 -0
  10. data/lib/mongoid/associations/options.rb +62 -0
  11. data/lib/mongoid/associations/proxy.rb +33 -0
  12. data/lib/mongoid/associations/referenced_in.rb +59 -0
  13. data/lib/mongoid/associations/references_many.rb +245 -0
  14. data/lib/mongoid/associations/references_many_as_array.rb +78 -0
  15. data/lib/mongoid/associations/references_one.rb +99 -0
  16. data/lib/mongoid/atomicity.rb +55 -0
  17. data/lib/mongoid/attributes.rb +242 -0
  18. data/lib/mongoid/callbacks.rb +21 -0
  19. data/lib/mongoid/collection.rb +120 -0
  20. data/lib/mongoid/collections.rb +71 -0
  21. data/lib/mongoid/collections/cyclic_iterator.rb +34 -0
  22. data/lib/mongoid/collections/master.rb +29 -0
  23. data/lib/mongoid/collections/operations.rb +41 -0
  24. data/lib/mongoid/collections/slaves.rb +45 -0
  25. data/lib/mongoid/components.rb +34 -0
  26. data/lib/mongoid/config.rb +263 -0
  27. data/lib/mongoid/contexts.rb +24 -0
  28. data/lib/mongoid/contexts/enumerable.rb +156 -0
  29. data/lib/mongoid/contexts/ids.rb +25 -0
  30. data/lib/mongoid/contexts/mongo.rb +285 -0
  31. data/lib/mongoid/contexts/paging.rb +50 -0
  32. data/lib/mongoid/criteria.rb +248 -0
  33. data/lib/mongoid/criterion/complex.rb +21 -0
  34. data/lib/mongoid/criterion/exclusion.rb +65 -0
  35. data/lib/mongoid/criterion/inclusion.rb +110 -0
  36. data/lib/mongoid/criterion/optional.rb +189 -0
  37. data/lib/mongoid/cursor.rb +81 -0
  38. data/lib/mongoid/deprecation.rb +21 -0
  39. data/lib/mongoid/dirty.rb +252 -0
  40. data/lib/mongoid/document.rb +210 -0
  41. data/lib/mongoid/errors.rb +131 -0
  42. data/lib/mongoid/extensions.rb +115 -0
  43. data/lib/mongoid/extensions/array/accessors.rb +17 -0
  44. data/lib/mongoid/extensions/array/assimilation.rb +26 -0
  45. data/lib/mongoid/extensions/array/conversions.rb +23 -0
  46. data/lib/mongoid/extensions/array/parentization.rb +13 -0
  47. data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
  48. data/lib/mongoid/extensions/binary/conversions.rb +17 -0
  49. data/lib/mongoid/extensions/boolean/conversions.rb +27 -0
  50. data/lib/mongoid/extensions/date/conversions.rb +24 -0
  51. data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
  52. data/lib/mongoid/extensions/false_class/equality.rb +13 -0
  53. data/lib/mongoid/extensions/float/conversions.rb +20 -0
  54. data/lib/mongoid/extensions/hash/accessors.rb +42 -0
  55. data/lib/mongoid/extensions/hash/assimilation.rb +40 -0
  56. data/lib/mongoid/extensions/hash/conversions.rb +42 -0
  57. data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
  58. data/lib/mongoid/extensions/hash/scoping.rb +12 -0
  59. data/lib/mongoid/extensions/integer/conversions.rb +20 -0
  60. data/lib/mongoid/extensions/nil/assimilation.rb +17 -0
  61. data/lib/mongoid/extensions/object/conversions.rb +21 -0
  62. data/lib/mongoid/extensions/objectid/conversions.rb +15 -0
  63. data/lib/mongoid/extensions/proc/scoping.rb +12 -0
  64. data/lib/mongoid/extensions/set/conversions.rb +20 -0
  65. data/lib/mongoid/extensions/string/conversions.rb +15 -0
  66. data/lib/mongoid/extensions/string/inflections.rb +97 -0
  67. data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
  68. data/lib/mongoid/extensions/time_conversions.rb +35 -0
  69. data/lib/mongoid/extensions/true_class/equality.rb +13 -0
  70. data/lib/mongoid/extras.rb +61 -0
  71. data/lib/mongoid/factory.rb +20 -0
  72. data/lib/mongoid/field.rb +83 -0
  73. data/lib/mongoid/fields.rb +62 -0
  74. data/lib/mongoid/finders.rb +145 -0
  75. data/lib/mongoid/hierarchy.rb +74 -0
  76. data/lib/mongoid/identity.rb +47 -0
  77. data/lib/mongoid/indexes.rb +27 -0
  78. data/lib/mongoid/javascript.rb +21 -0
  79. data/lib/mongoid/javascript/functions.yml +37 -0
  80. data/lib/mongoid/logger.rb +19 -0
  81. data/lib/mongoid/matchers.rb +35 -0
  82. data/lib/mongoid/matchers/all.rb +11 -0
  83. data/lib/mongoid/matchers/default.rb +26 -0
  84. data/lib/mongoid/matchers/exists.rb +13 -0
  85. data/lib/mongoid/matchers/gt.rb +11 -0
  86. data/lib/mongoid/matchers/gte.rb +11 -0
  87. data/lib/mongoid/matchers/in.rb +11 -0
  88. data/lib/mongoid/matchers/lt.rb +11 -0
  89. data/lib/mongoid/matchers/lte.rb +11 -0
  90. data/lib/mongoid/matchers/ne.rb +11 -0
  91. data/lib/mongoid/matchers/nin.rb +11 -0
  92. data/lib/mongoid/matchers/size.rb +11 -0
  93. data/lib/mongoid/memoization.rb +33 -0
  94. data/lib/mongoid/named_scope.rb +37 -0
  95. data/lib/mongoid/paranoia.rb +106 -0
  96. data/lib/mongoid/paths.rb +61 -0
  97. data/lib/mongoid/persistence.rb +216 -0
  98. data/lib/mongoid/persistence/command.rb +39 -0
  99. data/lib/mongoid/persistence/insert.rb +48 -0
  100. data/lib/mongoid/persistence/insert_embedded.rb +44 -0
  101. data/lib/mongoid/persistence/remove.rb +39 -0
  102. data/lib/mongoid/persistence/remove_all.rb +38 -0
  103. data/lib/mongoid/persistence/remove_embedded.rb +50 -0
  104. data/lib/mongoid/persistence/update.rb +71 -0
  105. data/lib/mongoid/railtie.rb +67 -0
  106. data/lib/mongoid/railties/database.rake +60 -0
  107. data/lib/mongoid/scope.rb +75 -0
  108. data/lib/mongoid/state.rb +32 -0
  109. data/lib/mongoid/timestamps.rb +27 -0
  110. data/lib/mongoid/validations.rb +51 -0
  111. data/lib/mongoid/validations/associated.rb +32 -0
  112. data/lib/mongoid/validations/locale/en.yml +5 -0
  113. data/lib/mongoid/validations/uniqueness.rb +56 -0
  114. data/lib/mongoid/version.rb +4 -0
  115. data/lib/mongoid/versioning.rb +26 -0
  116. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
  117. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +24 -0
  118. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  119. data/lib/rails/generators/mongoid/model/templates/model.rb +15 -0
  120. data/lib/rails/generators/mongoid_generator.rb +61 -0
  121. data/spec/integration/mongoid/association_attributes_spec.rb +71 -0
  122. data/spec/integration/mongoid/associations_spec.rb +768 -0
  123. data/spec/integration/mongoid/attributes_spec.rb +59 -0
  124. data/spec/integration/mongoid/callback_spec.rb +33 -0
  125. data/spec/integration/mongoid/contexts/enumerable_spec.rb +33 -0
  126. data/spec/integration/mongoid/criteria_spec.rb +281 -0
  127. data/spec/integration/mongoid/dirty_spec.rb +85 -0
  128. data/spec/integration/mongoid/document_spec.rb +741 -0
  129. data/spec/integration/mongoid/extensions_spec.rb +22 -0
  130. data/spec/integration/mongoid/finders_spec.rb +119 -0
  131. data/spec/integration/mongoid/inheritance_spec.rb +171 -0
  132. data/spec/integration/mongoid/named_scope_spec.rb +58 -0
  133. data/spec/integration/mongoid/paranoia_spec.rb +44 -0
  134. data/spec/integration/mongoid/persistence/update_spec.rb +46 -0
  135. data/spec/integration/mongoid/persistence_spec.rb +311 -0
  136. data/spec/integration/mongoid/validations/uniqueness_spec.rb +206 -0
  137. data/spec/models/account.rb +5 -0
  138. data/spec/models/address.rb +40 -0
  139. data/spec/models/agent.rb +7 -0
  140. data/spec/models/animal.rb +15 -0
  141. data/spec/models/answer.rb +4 -0
  142. data/spec/models/callbacks.rb +47 -0
  143. data/spec/models/category.rb +13 -0
  144. data/spec/models/comment.rb +10 -0
  145. data/spec/models/country_code.rb +6 -0
  146. data/spec/models/employer.rb +5 -0
  147. data/spec/models/favorite.rb +8 -0
  148. data/spec/models/game.rb +9 -0
  149. data/spec/models/inheritance.rb +72 -0
  150. data/spec/models/location.rb +5 -0
  151. data/spec/models/login.rb +6 -0
  152. data/spec/models/mixed_drink.rb +4 -0
  153. data/spec/models/name.rb +13 -0
  154. data/spec/models/namespacing.rb +11 -0
  155. data/spec/models/paranoid_post.rb +18 -0
  156. data/spec/models/parents.rb +32 -0
  157. data/spec/models/patient.rb +15 -0
  158. data/spec/models/person.rb +106 -0
  159. data/spec/models/pet.rb +7 -0
  160. data/spec/models/pet_owner.rb +6 -0
  161. data/spec/models/phone.rb +7 -0
  162. data/spec/models/post.rb +25 -0
  163. data/spec/models/preference.rb +7 -0
  164. data/spec/models/question.rb +8 -0
  165. data/spec/models/survey.rb +6 -0
  166. data/spec/models/translation.rb +5 -0
  167. data/spec/models/user.rb +6 -0
  168. data/spec/models/user_accout.rb +5 -0
  169. data/spec/models/vet_visit.rb +5 -0
  170. data/spec/models/video.rb +5 -0
  171. data/spec/spec_helper.rb +33 -0
  172. data/spec/unit/mongoid/associations/embedded_in_spec.rb +193 -0
  173. data/spec/unit/mongoid/associations/embeds_many_spec.rb +626 -0
  174. data/spec/unit/mongoid/associations/embeds_one_spec.rb +287 -0
  175. data/spec/unit/mongoid/associations/foreign_key_spec.rb +90 -0
  176. data/spec/unit/mongoid/associations/meta_data_spec.rb +110 -0
  177. data/spec/unit/mongoid/associations/options_spec.rb +215 -0
  178. data/spec/unit/mongoid/associations/referenced_in_spec.rb +145 -0
  179. data/spec/unit/mongoid/associations/references_many_as_array_spec.rb +424 -0
  180. data/spec/unit/mongoid/associations/references_many_spec.rb +502 -0
  181. data/spec/unit/mongoid/associations/references_one_spec.rb +204 -0
  182. data/spec/unit/mongoid/associations_spec.rb +688 -0
  183. data/spec/unit/mongoid/atomicity_spec.rb +164 -0
  184. data/spec/unit/mongoid/attributes_spec.rb +646 -0
  185. data/spec/unit/mongoid/callbacks_spec.rb +85 -0
  186. data/spec/unit/mongoid/collection_spec.rb +187 -0
  187. data/spec/unit/mongoid/collections/cyclic_iterator_spec.rb +75 -0
  188. data/spec/unit/mongoid/collections/master_spec.rb +41 -0
  189. data/spec/unit/mongoid/collections/slaves_spec.rb +81 -0
  190. data/spec/unit/mongoid/collections_spec.rb +98 -0
  191. data/spec/unit/mongoid/config_spec.rb +298 -0
  192. data/spec/unit/mongoid/contexts/enumerable_spec.rb +447 -0
  193. data/spec/unit/mongoid/contexts/mongo_spec.rb +703 -0
  194. data/spec/unit/mongoid/contexts_spec.rb +25 -0
  195. data/spec/unit/mongoid/criteria_spec.rb +873 -0
  196. data/spec/unit/mongoid/criterion/complex_spec.rb +17 -0
  197. data/spec/unit/mongoid/criterion/exclusion_spec.rb +121 -0
  198. data/spec/unit/mongoid/criterion/inclusion_spec.rb +274 -0
  199. data/spec/unit/mongoid/criterion/optional_spec.rb +483 -0
  200. data/spec/unit/mongoid/cursor_spec.rb +80 -0
  201. data/spec/unit/mongoid/deprecation_spec.rb +24 -0
  202. data/spec/unit/mongoid/dirty_spec.rb +430 -0
  203. data/spec/unit/mongoid/document_spec.rb +623 -0
  204. data/spec/unit/mongoid/errors_spec.rb +154 -0
  205. data/spec/unit/mongoid/extensions/array/accessors_spec.rb +50 -0
  206. data/spec/unit/mongoid/extensions/array/assimilation_spec.rb +24 -0
  207. data/spec/unit/mongoid/extensions/array/conversions_spec.rb +52 -0
  208. data/spec/unit/mongoid/extensions/array/parentization_spec.rb +20 -0
  209. data/spec/unit/mongoid/extensions/big_decimal/conversions_spec.rb +36 -0
  210. data/spec/unit/mongoid/extensions/binary/conversions_spec.rb +22 -0
  211. data/spec/unit/mongoid/extensions/boolean/conversions_spec.rb +49 -0
  212. data/spec/unit/mongoid/extensions/date/conversions_spec.rb +145 -0
  213. data/spec/unit/mongoid/extensions/datetime/conversions_spec.rb +14 -0
  214. data/spec/unit/mongoid/extensions/false_class/equality_spec.rb +35 -0
  215. data/spec/unit/mongoid/extensions/float/conversions_spec.rb +61 -0
  216. data/spec/unit/mongoid/extensions/hash/accessors_spec.rb +184 -0
  217. data/spec/unit/mongoid/extensions/hash/assimilation_spec.rb +59 -0
  218. data/spec/unit/mongoid/extensions/hash/conversions_spec.rb +35 -0
  219. data/spec/unit/mongoid/extensions/hash/criteria_helpers_spec.rb +17 -0
  220. data/spec/unit/mongoid/extensions/hash/scoping_spec.rb +14 -0
  221. data/spec/unit/mongoid/extensions/integer/conversions_spec.rb +61 -0
  222. data/spec/unit/mongoid/extensions/nil/assimilation_spec.rb +29 -0
  223. data/spec/unit/mongoid/extensions/object/conversions_spec.rb +44 -0
  224. data/spec/unit/mongoid/extensions/objectid/conversions_spec.rb +22 -0
  225. data/spec/unit/mongoid/extensions/proc/scoping_spec.rb +34 -0
  226. data/spec/unit/mongoid/extensions/set/conversions_spec.rb +21 -0
  227. data/spec/unit/mongoid/extensions/string/conversions_spec.rb +28 -0
  228. data/spec/unit/mongoid/extensions/string/inflections_spec.rb +208 -0
  229. data/spec/unit/mongoid/extensions/symbol/inflections_spec.rb +107 -0
  230. data/spec/unit/mongoid/extensions/time_conversions_spec.rb +186 -0
  231. data/spec/unit/mongoid/extensions/true_class/equality_spec.rb +35 -0
  232. data/spec/unit/mongoid/extras_spec.rb +102 -0
  233. data/spec/unit/mongoid/factory_spec.rb +31 -0
  234. data/spec/unit/mongoid/field_spec.rb +169 -0
  235. data/spec/unit/mongoid/fields_spec.rb +181 -0
  236. data/spec/unit/mongoid/finders_spec.rb +439 -0
  237. data/spec/unit/mongoid/hierarchy_spec.rb +68 -0
  238. data/spec/unit/mongoid/identity_spec.rb +109 -0
  239. data/spec/unit/mongoid/indexes_spec.rb +99 -0
  240. data/spec/unit/mongoid/javascript_spec.rb +48 -0
  241. data/spec/unit/mongoid/logger_spec.rb +38 -0
  242. data/spec/unit/mongoid/matchers/all_spec.rb +27 -0
  243. data/spec/unit/mongoid/matchers/default_spec.rb +27 -0
  244. data/spec/unit/mongoid/matchers/exists_spec.rb +56 -0
  245. data/spec/unit/mongoid/matchers/gt_spec.rb +39 -0
  246. data/spec/unit/mongoid/matchers/gte_spec.rb +49 -0
  247. data/spec/unit/mongoid/matchers/in_spec.rb +27 -0
  248. data/spec/unit/mongoid/matchers/lt_spec.rb +39 -0
  249. data/spec/unit/mongoid/matchers/lte_spec.rb +49 -0
  250. data/spec/unit/mongoid/matchers/ne_spec.rb +27 -0
  251. data/spec/unit/mongoid/matchers/nin_spec.rb +27 -0
  252. data/spec/unit/mongoid/matchers/size_spec.rb +27 -0
  253. data/spec/unit/mongoid/matchers_spec.rb +329 -0
  254. data/spec/unit/mongoid/memoization_spec.rb +75 -0
  255. data/spec/unit/mongoid/named_scope_spec.rb +123 -0
  256. data/spec/unit/mongoid/paranoia_spec.rb +108 -0
  257. data/spec/unit/mongoid/paths_spec.rb +272 -0
  258. data/spec/unit/mongoid/persistence/insert_embedded_spec.rb +154 -0
  259. data/spec/unit/mongoid/persistence/insert_spec.rb +144 -0
  260. data/spec/unit/mongoid/persistence/remove_all_spec.rb +82 -0
  261. data/spec/unit/mongoid/persistence/remove_embedded_spec.rb +152 -0
  262. data/spec/unit/mongoid/persistence/remove_spec.rb +89 -0
  263. data/spec/unit/mongoid/persistence/update_spec.rb +177 -0
  264. data/spec/unit/mongoid/persistence_spec.rb +452 -0
  265. data/spec/unit/mongoid/scope_spec.rb +240 -0
  266. data/spec/unit/mongoid/serialization_spec.rb +43 -0
  267. data/spec/unit/mongoid/state_spec.rb +94 -0
  268. data/spec/unit/mongoid/timestamps_spec.rb +30 -0
  269. data/spec/unit/mongoid/validations/associated_spec.rb +103 -0
  270. data/spec/unit/mongoid/validations/uniqueness_spec.rb +201 -0
  271. data/spec/unit/mongoid/validations_spec.rb +43 -0
  272. data/spec/unit/mongoid/versioning_spec.rb +41 -0
  273. data/spec/unit/mongoid_spec.rb +46 -0
  274. metadata +433 -0
@@ -0,0 +1,204 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Associations::ReferencesOne do
4
+
5
+ let(:document) { stub(:id => "1") }
6
+ let(:block) do
7
+ Proc.new do
8
+ def extension
9
+ "Testing"
10
+ end
11
+ end
12
+ end
13
+ let(:options) do
14
+ Mongoid::Associations::Options.new(:name => :game, :extend => block, :foreign_key => "person_id")
15
+ end
16
+
17
+ describe "#build" do
18
+
19
+ before do
20
+ @parent = stub(:id => "5", :class => Person)
21
+ Game.expects(:first).returns(nil)
22
+ @association = Mongoid::Associations::ReferencesOne.new(@parent, options)
23
+ end
24
+
25
+ it "adds a new object to the association" do
26
+ @association.build(:score => 100)
27
+ @association.score.should == 100
28
+ end
29
+
30
+ it "sets the parent object id on the child" do
31
+ @association.build(:score => 100)
32
+ @association.person_id.should == @parent.id
33
+ end
34
+
35
+ it "sets the parent object reference on the child" do
36
+ @association.build(:score => 100)
37
+ @association.person.should == @parent
38
+ end
39
+
40
+ end
41
+
42
+ describe "#create" do
43
+
44
+ before do
45
+ @parent = stub(:id => "5", :class => Person)
46
+ @insert = stub
47
+ Game.expects(:first).returns(nil)
48
+ Mongoid::Persistence::Insert.expects(:new).returns(@insert)
49
+ @insert.expects(:persist).returns(Person.new)
50
+ @association = Mongoid::Associations::ReferencesOne.new(@parent, options)
51
+ end
52
+
53
+ it "adds a new object to the association" do
54
+ @association.create(:score => 100)
55
+ @association.score.should == 100
56
+ end
57
+
58
+ it "sets the parent object id on the child" do
59
+ @association.create(:score => 100)
60
+ @association.person_id.should == @parent.id
61
+ end
62
+
63
+ it "returns the new document" do
64
+ @association.create(:score => 100).should be_a_kind_of(Game)
65
+ end
66
+
67
+ end
68
+
69
+ describe "#id" do
70
+
71
+ before do
72
+ @parent = stub(:id => "5", :class => Person)
73
+ @game = Game.new
74
+ Game.expects(:first).returns(@game)
75
+ @association = Mongoid::Associations::ReferencesOne.new(@parent, options)
76
+ end
77
+
78
+ it "delegates to the proxied document" do
79
+ @association.id.should == @game.id
80
+ end
81
+
82
+ end
83
+
84
+ describe ".initialize" do
85
+
86
+ before do
87
+ @person = Person.new
88
+ @game = stub
89
+ end
90
+
91
+ it "finds the association game by the parent key" do
92
+ Game.expects(:first).with(:conditions => { "person_id"=> @person.id }).returns(@game)
93
+ @person.game.should == @game
94
+ end
95
+
96
+ context "when the options have an extension" do
97
+
98
+ before do
99
+ @parent = stub(:id => "5", :class => Person)
100
+ @game = Game.new
101
+ Game.expects(:first).returns(@game)
102
+ @association = Mongoid::Associations::ReferencesOne.new(@parent, options)
103
+ end
104
+
105
+ it "adds the extension to the module" do
106
+ @association.extension.should == "Testing"
107
+ end
108
+
109
+ end
110
+
111
+ end
112
+
113
+ describe ".instantiate" do
114
+
115
+ it "delegates to new" do
116
+ Mongoid::Associations::ReferencesOne.expects(:new).with(document, options, nil)
117
+ Mongoid::Associations::ReferencesOne.instantiate(document, options)
118
+ end
119
+
120
+ end
121
+
122
+ describe "#method_missing" do
123
+
124
+ before do
125
+ @person = Person.new
126
+ @game = stub
127
+ end
128
+
129
+ it "delegates to the documet" do
130
+ Game.expects(:first).with(:conditions => { "person_id"=> @person.id }).returns(@game)
131
+ @game.expects(:strange_method)
132
+ association = Mongoid::Associations::ReferencesOne.instantiate(@person, options)
133
+ association.strange_method
134
+ end
135
+
136
+ end
137
+
138
+ describe "#nested_build" do
139
+
140
+ before do
141
+ @parent = stub(:id => "5", :class => Person)
142
+ @game = Game.new
143
+ Game.expects(:first).returns(@game)
144
+ end
145
+
146
+ context "when attributes provided" do
147
+
148
+ before do
149
+ @association = Mongoid::Associations::ReferencesOne.new(@parent, options)
150
+ end
151
+
152
+ it "replaces the existing has_one" do
153
+ game = @association.nested_build({ :score => 200 })
154
+ game.score.should == 200
155
+ end
156
+
157
+ end
158
+
159
+ end
160
+
161
+ describe ".macro" do
162
+
163
+ it "returns :references_one" do
164
+ Mongoid::Associations::ReferencesOne.macro.should == :references_one
165
+ end
166
+
167
+ end
168
+
169
+ describe "#nil?" do
170
+
171
+ before do
172
+ @person = Person.new
173
+ @game = stub
174
+ Game.expects(:first).with(:conditions => { "person_id"=> @person.id }).returns(nil)
175
+ end
176
+
177
+ it "delegates to the document" do
178
+ association = Mongoid::Associations::ReferencesOne.instantiate(@person, options)
179
+ association.should be_nil
180
+ end
181
+
182
+ end
183
+
184
+ describe ".update" do
185
+
186
+ before do
187
+ @person = Person.new
188
+ @game = stub
189
+ end
190
+
191
+ it "sets the parent on the child association" do
192
+ @game.expects(:person=).with(@person)
193
+ Mongoid::Associations::ReferencesOne.update(@game, @person, options)
194
+ end
195
+
196
+ it "returns the proxy" do
197
+ @game.expects(:person=).with(@person)
198
+ @proxy = Mongoid::Associations::ReferencesOne.update(@game, @person, options)
199
+ @proxy.target.should == @game
200
+ end
201
+
202
+ end
203
+
204
+ end
@@ -0,0 +1,688 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Associations do
4
+
5
+ before do
6
+ @collection = stub(:name => "people")
7
+ @database = stub(:collection => @collection)
8
+ Mongoid.stubs(:database).returns(@database)
9
+ end
10
+
11
+ describe "#association=" do
12
+
13
+ context "when child is a has one" do
14
+
15
+ before do
16
+ @person = Person.new(:title => "Sir", :age => 30)
17
+ @name = Name.new(:first_name => "Test", :last_name => "User")
18
+ @person.name = @name
19
+ end
20
+
21
+ it "parentizes the association" do
22
+ @name._parent.should == @person
23
+ end
24
+
25
+ it "sets the child attributes on the parent" do
26
+ @person.attributes[:name].should ==
27
+ { "_id" => "test-user", "first_name" => "Test", "last_name" => "User" }
28
+ end
29
+
30
+ end
31
+
32
+ context "when child and parent are namespaced" do
33
+
34
+ before do
35
+ @patient = Medical::Patient.new(:name => "Ridley")
36
+ @prescription = Medical::Prescription.new(:name => "Zoloft")
37
+ @patient.prescriptions << @prescription
38
+ @second = @patient.prescriptions.build(:name => "Codeine")
39
+ end
40
+
41
+ it "sets the correct association classes" do
42
+ @patient.prescriptions.first.should == @prescription
43
+ @patient.prescriptions.last.should == @second
44
+ end
45
+
46
+ end
47
+
48
+ context "when setting a parent" do
49
+
50
+ context "when the child is one level deep" do
51
+
52
+ before do
53
+ @person = Person.new(:title => "Mr")
54
+ @address = Address.new(:street => "Picadilly Circus")
55
+ @address.addressable = @person
56
+ end
57
+
58
+ it "re-parentizes the association" do
59
+ @address._parent.should == @person
60
+ end
61
+
62
+ it "adds the child attributes to the parent" do
63
+ @person.attributes[:addresses].should ==
64
+ [{ "_id" => "picadilly-circus", "street" => "Picadilly Circus" }]
65
+ end
66
+
67
+ end
68
+
69
+ context "when the child is multiple levels deep" do
70
+
71
+ before do
72
+ @person = Person.new(:title => "Mr")
73
+ @phone = Phone.new(:number => "415-555-1212")
74
+ @person.phone_numbers = [@phone]
75
+ @country_code = CountryCode.new(:code => 1)
76
+ @phone.country_code = @country_code
77
+ end
78
+
79
+ it "properly decorates all parent references" do
80
+ @country_code.phone_number.should == @phone
81
+ @phone.person.should == @person
82
+ @country_code.phone_number.person.should == @person
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ describe "#associations" do
92
+
93
+ before do
94
+ @person = Person.new
95
+ end
96
+
97
+ it "is a hash with name keys and meta data values" do
98
+ @person.associations["addresses"].should be_a_kind_of(Mongoid::Associations::MetaData)
99
+ end
100
+ end
101
+
102
+ describe ".embedded?" do
103
+
104
+ context "when the class is embedded" do
105
+
106
+ it "returns true" do
107
+ Address.embedded?.should be_true
108
+ end
109
+ end
110
+
111
+ context "when the class is not embedded" do
112
+
113
+ it "returns false" do
114
+ Person.embedded?.should be_false
115
+ end
116
+ end
117
+ end
118
+
119
+ describe "#embedded?" do
120
+
121
+ context "when the class is embedded" do
122
+
123
+ it "returns true" do
124
+ Address.new.embedded?.should be_true
125
+ end
126
+ end
127
+
128
+ context "when the class is not embedded" do
129
+
130
+ it "returns false" do
131
+ Person.new.embedded?.should be_false
132
+ end
133
+ end
134
+ end
135
+
136
+ describe "#embedded_many?" do
137
+ context "when the class is embedded" do
138
+
139
+ context "within an embeds_many" do
140
+ it "returns true" do
141
+ Address.new(:addressable => Person.new).embedded_many?.should be_true
142
+ end
143
+ end
144
+
145
+ context "within an embeds_one" do
146
+ it "returns false" do
147
+ Name.new(:namable => Person.new).embedded_many?.should be_false
148
+ end
149
+ end
150
+ end
151
+
152
+ context "when the class is not embedded" do
153
+
154
+ it "returns false" do
155
+ Person.new.embedded_many?.should be_false
156
+ end
157
+ end
158
+
159
+ end
160
+
161
+ describe ".embedded_in" do
162
+
163
+ it "creates a reader for the association" do
164
+ address = Address.new
165
+ address.should respond_to(:addressable)
166
+ end
167
+
168
+ it "creates a writer for the association" do
169
+ address = Address.new
170
+ address.should respond_to(:addressable=)
171
+ end
172
+
173
+ it "allows the parent to be any type of class" do
174
+ phone_number = Phone.new(:number => "415-555-1212")
175
+ code = CountryCode.new(:code => 1)
176
+ phone_number.country_code = code
177
+ code.phone_number.should == phone_number
178
+ end
179
+
180
+ context "when adding an anonymous extension" do
181
+
182
+ before do
183
+ @person = Person.new(:title => "Dr")
184
+ @address = Address.new(:street => "Clarkenwell Road")
185
+ @person.addresses << @address
186
+ end
187
+
188
+ it "defines the method on the association" do
189
+ @address.addressable.extension.should == "Testing"
190
+ end
191
+
192
+ end
193
+
194
+ context "when inverse_of not supplied" do
195
+
196
+ it "raises an error" do
197
+ lambda { Person.class_eval { embedded_in :nothing } }.should raise_error
198
+ end
199
+
200
+ end
201
+
202
+ context "when navigating the graph" do
203
+
204
+ before do
205
+ @person = Person.new(:title => "Mr")
206
+ @name = Name.new(:first_name => "Mason")
207
+ @address = Address.new(:street => "King St.")
208
+ @person.name = @name
209
+ @person.addresses << @address
210
+ end
211
+
212
+ it "allows referencing another child through the parent" do
213
+ @name.namable.addresses.first.should == @address
214
+ end
215
+
216
+ end
217
+
218
+ end
219
+
220
+ describe "#build_*" do
221
+
222
+ before do
223
+ @canvas = Canvas.new
224
+ end
225
+
226
+ context "when type is passed in" do
227
+
228
+ before do
229
+ @writer = @canvas.build_writer(:speed => 250, :_type => "HtmlWriter")
230
+ end
231
+
232
+ it "returns a new document" do
233
+ @writer.should_not be_nil
234
+ end
235
+
236
+ it "returns the properly typed document" do
237
+ @writer.should be_a_kind_of(HtmlWriter)
238
+ end
239
+
240
+ it "sets the appropriate attributes" do
241
+ @writer.speed.should == 250
242
+ end
243
+
244
+ end
245
+
246
+ context "when type is not passed in" do
247
+
248
+ before do
249
+ @writer = @canvas.build_writer(:speed => 250)
250
+ end
251
+
252
+ it "returns a new document" do
253
+ @writer.should_not be_nil
254
+ end
255
+
256
+ it "returns the properly typed document" do
257
+ @writer.should be_a_kind_of(Writer)
258
+ end
259
+
260
+ it "sets the appropriate attributes" do
261
+ @writer.speed.should == 250
262
+ end
263
+
264
+ end
265
+
266
+ context "when attributes are nil" do
267
+
268
+ before do
269
+ @writer = @canvas.build_writer(nil)
270
+ end
271
+
272
+ it "defaults them to empty" do
273
+ @writer.should be_a_kind_of(Writer)
274
+ end
275
+
276
+ end
277
+
278
+ end
279
+
280
+ describe "#create_*" do
281
+
282
+ before do
283
+ @canvas = Canvas.new
284
+ end
285
+
286
+ context "when type is passed in" do
287
+
288
+ before do
289
+ @insert = stub
290
+ Mongoid::Persistence::Insert.expects(:new).returns(@insert)
291
+ @insert.expects(:persist).returns(HtmlWriter.new(:speed => 250))
292
+ @writer = @canvas.create_writer(:speed => 250, :_type => "HtmlWriter")
293
+ end
294
+
295
+ it "returns a new document" do
296
+ @writer.should_not be_nil
297
+ end
298
+
299
+ it "returns the properly typed document" do
300
+ @writer.should be_a_kind_of(HtmlWriter)
301
+ end
302
+
303
+ it "sets the appropriate attributes" do
304
+ @writer.speed.should == 250
305
+ end
306
+
307
+ end
308
+
309
+ context "when type is not passed in" do
310
+
311
+ before do
312
+ @insert = stub
313
+ Mongoid::Persistence::Insert.expects(:new).returns(@insert)
314
+ @insert.expects(:persist).returns(HtmlWriter.new(:speed => 250))
315
+ @writer = @canvas.create_writer(:speed => 250, :_type => "HtmlWriter")
316
+ end
317
+
318
+ it "returns a new document" do
319
+ @writer.should_not be_nil
320
+ end
321
+
322
+ it "returns the properly typed document" do
323
+ @writer.should be_a_kind_of(Writer)
324
+ end
325
+
326
+ it "sets the appropriate attributes" do
327
+ @writer.speed.should == 250
328
+ end
329
+
330
+ end
331
+
332
+ end
333
+
334
+ describe ".embeds_many" do
335
+
336
+ it "adds a new Association to the collection" do
337
+ person = Person.new
338
+ person.addresses.should_not be_nil
339
+ end
340
+
341
+ it "creates a reader for the association" do
342
+ person = Person.new
343
+ person.should respond_to(:addresses)
344
+ end
345
+
346
+ it "creates a writer for the association" do
347
+ person = Person.new
348
+ person.should respond_to(:addresses=)
349
+ end
350
+
351
+ context "when adding an anonymous extension" do
352
+
353
+ it "defines the method on the association" do
354
+ person = Person.new
355
+ person.addresses.extension.should == "Testing"
356
+ end
357
+
358
+ end
359
+
360
+ context "when setting the association directly" do
361
+
362
+ before do
363
+ @attributes = { :title => "Sir",
364
+ :addresses => [
365
+ { :street => "Street 1" },
366
+ { :street => "Street 2" } ] }
367
+ @person = Person.new(@attributes)
368
+ end
369
+
370
+ it "sets the attributes for the association" do
371
+ address = Address.new(:street => "New Street")
372
+ @person.addresses = [address]
373
+ @person.addresses.first.street.should == "New Street"
374
+ end
375
+
376
+ end
377
+
378
+ context "when a class_name is supplied" do
379
+
380
+ before do
381
+ @attributes = { :title => "Sir",
382
+ :phone_numbers => [ { :number => "404-555-1212" } ]
383
+ }
384
+ @person = Person.new(@attributes)
385
+ end
386
+
387
+ it "sets the association name" do
388
+ @person.phone_numbers.first.should == Phone.new(:number => "404-555-1212")
389
+ end
390
+
391
+ end
392
+
393
+ context "when updating objects internally" do
394
+
395
+ before do
396
+ @address = Address.new(:street => "Bourke Street")
397
+ @person = Person.new(:title => "Sir")
398
+ @person.addresses << @address
399
+ @person.update_addresses
400
+ end
401
+
402
+ it "retains its references to the original objects" do
403
+ @address.street.should == "Updated Address"
404
+ end
405
+
406
+ end
407
+
408
+ end
409
+
410
+ describe ".embeds_one" do
411
+
412
+ before do
413
+ @person = Person.new
414
+ end
415
+
416
+ it "adds a new Association to the document" do
417
+ @person.name.should be_nil
418
+ end
419
+
420
+ it "creates a reader for the association" do
421
+ @person.should respond_to(:name)
422
+ end
423
+
424
+ it "creates a writer for the association" do
425
+ @person.should respond_to(:name=)
426
+ end
427
+
428
+ it "creates a builder for the association" do
429
+ @person.should respond_to(:build_name)
430
+ end
431
+
432
+ it "creates a creator for the association" do
433
+ @person.should respond_to(:create_name)
434
+ end
435
+
436
+ context "when adding an anonymous extension" do
437
+
438
+ it "defines the method on the association" do
439
+ @person.name = Name.new(:first_name => "Richard")
440
+ @person.name.extension.should == "Testing"
441
+ end
442
+
443
+ end
444
+
445
+ context "when setting the association directly" do
446
+
447
+ before do
448
+ @attributes = { :title => "Sir",
449
+ :name => { :first_name => "Test" } }
450
+ @person = Person.new(@attributes)
451
+ end
452
+
453
+ it "sets the attributes for the association" do
454
+ name = Name.new(:first_name => "New Name")
455
+ @person.name = name
456
+ @person.name.first_name.should == "New Name"
457
+ end
458
+
459
+ end
460
+
461
+ context "when a class_name is supplied" do
462
+
463
+ before do
464
+ @attributes = { :title => "Sir",
465
+ :pet => { :name => "Fido" }
466
+ }
467
+ @person = Person.new(@attributes)
468
+ end
469
+
470
+ it "sets the association name" do
471
+ @person.pet.should == Animal.new(:name => "Fido")
472
+ end
473
+
474
+ end
475
+
476
+ end
477
+
478
+ describe ".reflect_on_association" do
479
+
480
+ it "returns the association class for the name" do
481
+ Person.reflect_on_association(:addresses).should == :embeds_many
482
+ end
483
+
484
+ end
485
+
486
+ describe ".referenced_in" do
487
+
488
+ before do
489
+ @game = Game.new
490
+ end
491
+
492
+ it "creates an id field for the relationship" do
493
+ @game.should respond_to(:person_id)
494
+ end
495
+
496
+ it "creates a getter for the parent" do
497
+ @game.should respond_to(:person)
498
+ end
499
+
500
+ it "defaults the foreign_key option to the name_id" do
501
+ @game.associations["person"].foreign_key.should == "person_id"
502
+ end
503
+
504
+ context "when document is root level" do
505
+
506
+ it "puts an index on the foreign key" do
507
+ Game.expects(:index).with("person_id")
508
+ Game.referenced_in :person
509
+ end
510
+
511
+ end
512
+
513
+ context "when using object ids" do
514
+
515
+ before do
516
+ Mongoid.use_object_ids = true
517
+ end
518
+
519
+ after do
520
+ Mongoid.use_object_ids = false
521
+ end
522
+
523
+ it "sets the foreign key as an object id" do
524
+ Game.expects(:field).with("person_id", :type => BSON::ObjectID)
525
+ Game.referenced_in :person
526
+ end
527
+ end
528
+
529
+ end
530
+
531
+ describe ".references_one" do
532
+
533
+ before do
534
+ @person = Person.new
535
+ @game = Game.new
536
+ @person.game = @game
537
+ end
538
+
539
+ it "creates a getter for the relationship" do
540
+ @person.should respond_to(:game)
541
+ end
542
+
543
+ it "creates a setter for the relationship" do
544
+ @person.should respond_to(:game=)
545
+ end
546
+
547
+ context "when adding an anonymous extension" do
548
+
549
+ it "defines the method on the association" do
550
+ @person.game.extension.should == "Testing"
551
+ end
552
+
553
+ end
554
+
555
+ end
556
+
557
+ describe ".references_many" do
558
+
559
+ it "creates a getter for the association" do
560
+ Person.new.should respond_to(:posts)
561
+ end
562
+
563
+ it "creates a setter for the association" do
564
+ Person.new.should respond_to(:posts=)
565
+ end
566
+
567
+ context "when adding an anonymous extension" do
568
+
569
+ before do
570
+ @person = Person.new
571
+ end
572
+
573
+ it "defines the method on the association" do
574
+ @person.posts.extension.should == "Testing"
575
+ end
576
+
577
+ end
578
+
579
+ context "with a stored_as option provided" do
580
+
581
+ context "when stored_as is :array" do
582
+
583
+ it "creates a getter for the association" do
584
+ Person.allocate.should respond_to(:preferences)
585
+ end
586
+
587
+ it "creates a setter for the association" do
588
+ Person.allocate.should respond_to(:preferences=)
589
+ end
590
+
591
+ it "sets the association as a references many as array" do
592
+ metadata = Person.associations["preferences"]
593
+ metadata.association.should == Mongoid::Associations::ReferencesManyAsArray
594
+ end
595
+
596
+ it "creates the association_ids field" do
597
+ Person.allocate.should respond_to(:preference_ids)
598
+ end
599
+ end
600
+ end
601
+ end
602
+
603
+ describe "#update_foreign_keys" do
604
+
605
+ before do
606
+ @game = Game.new(:score => 1)
607
+ @person = Person.new(:title => "Sir", :game => @game)
608
+ end
609
+
610
+ it "updates blank foreign keys" do
611
+ @game.update_foreign_keys
612
+ @game.person_id.should == @person.id
613
+ end
614
+
615
+ end
616
+
617
+ describe "#update_associations" do
618
+
619
+ context "when associations exist" do
620
+
621
+ context "when the document is a new record" do
622
+
623
+ before do
624
+ @related = stub(:id => "100", :person= => true)
625
+ @person = Person.new
626
+ @person.posts = [@related]
627
+ end
628
+
629
+ it "saves each association" do
630
+ @related.expects(:save).returns(@related)
631
+ @person.update_associations(:posts)
632
+ end
633
+
634
+ end
635
+
636
+ context "when the document is not new" do
637
+
638
+ before do
639
+ @related = stub(:id => "100", :person= => true)
640
+ @person = Person.new
641
+ @person.instance_variable_set(:@new_record, false)
642
+ @person.posts = [@related]
643
+ end
644
+
645
+ it "does not save each association" do
646
+ @person.update_associations(:posts)
647
+ end
648
+
649
+ end
650
+
651
+ end
652
+
653
+ context "when no associations exist" do
654
+
655
+ before do
656
+ @person = Person.new
657
+ end
658
+
659
+ it "does nothing" do
660
+ Post.expects(:find).returns([])
661
+ @person.update_associations(:posts)
662
+ @person.posts.first.should be_nil
663
+ end
664
+
665
+ end
666
+
667
+ end
668
+
669
+ describe "#update_association" do
670
+
671
+ context "when the association exists" do
672
+
673
+ before do
674
+ @related = stub(:id => "100", :person= => true)
675
+ @person = Person.new
676
+ @person.game = @related
677
+ end
678
+
679
+ it "saves each association" do
680
+ @related.expects(:save).returns(@related)
681
+ @person.update_association(:game)
682
+ end
683
+
684
+ end
685
+
686
+ end
687
+
688
+ end