lookout-mongo_mapper 0.11.3

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 (176) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +33 -0
  3. data/UPGRADES +26 -0
  4. data/bin/mmconsole +59 -0
  5. data/examples/attr_accessible.rb +22 -0
  6. data/examples/attr_protected.rb +22 -0
  7. data/examples/cache_key.rb +24 -0
  8. data/examples/custom_types.rb +24 -0
  9. data/examples/identity_map.rb +33 -0
  10. data/examples/identity_map/automatic.rb +2 -0
  11. data/examples/keys.rb +40 -0
  12. data/examples/modifiers/set.rb +25 -0
  13. data/examples/plugins.rb +38 -0
  14. data/examples/querying.rb +35 -0
  15. data/examples/safe.rb +43 -0
  16. data/examples/scopes.rb +52 -0
  17. data/examples/validating/embedded_docs.rb +29 -0
  18. data/lib/mongo_mapper.rb +94 -0
  19. data/lib/mongo_mapper/connection.rb +96 -0
  20. data/lib/mongo_mapper/document.rb +42 -0
  21. data/lib/mongo_mapper/embedded_document.rb +32 -0
  22. data/lib/mongo_mapper/exceptions.rb +30 -0
  23. data/lib/mongo_mapper/extensions/array.rb +19 -0
  24. data/lib/mongo_mapper/extensions/binary.rb +22 -0
  25. data/lib/mongo_mapper/extensions/boolean.rb +44 -0
  26. data/lib/mongo_mapper/extensions/date.rb +25 -0
  27. data/lib/mongo_mapper/extensions/float.rb +14 -0
  28. data/lib/mongo_mapper/extensions/hash.rb +14 -0
  29. data/lib/mongo_mapper/extensions/integer.rb +19 -0
  30. data/lib/mongo_mapper/extensions/kernel.rb +9 -0
  31. data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
  32. data/lib/mongo_mapper/extensions/object.rb +26 -0
  33. data/lib/mongo_mapper/extensions/object_id.rb +32 -0
  34. data/lib/mongo_mapper/extensions/set.rb +20 -0
  35. data/lib/mongo_mapper/extensions/string.rb +18 -0
  36. data/lib/mongo_mapper/extensions/time.rb +28 -0
  37. data/lib/mongo_mapper/locale/en.yml +5 -0
  38. data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
  39. data/lib/mongo_mapper/plugins.rb +22 -0
  40. data/lib/mongo_mapper/plugins/accessible.rb +52 -0
  41. data/lib/mongo_mapper/plugins/active_model.rb +18 -0
  42. data/lib/mongo_mapper/plugins/associations.rb +90 -0
  43. data/lib/mongo_mapper/plugins/associations/base.rb +92 -0
  44. data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +54 -0
  45. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +34 -0
  46. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +52 -0
  47. data/lib/mongo_mapper/plugins/associations/collection.rb +27 -0
  48. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +44 -0
  49. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +133 -0
  50. data/lib/mongo_mapper/plugins/associations/many_association.rb +63 -0
  51. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  52. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +118 -0
  53. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +32 -0
  54. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +24 -0
  55. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +14 -0
  56. data/lib/mongo_mapper/plugins/associations/one_as_proxy.rb +22 -0
  57. data/lib/mongo_mapper/plugins/associations/one_association.rb +48 -0
  58. data/lib/mongo_mapper/plugins/associations/one_embedded_polymorphic_proxy.rb +30 -0
  59. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +44 -0
  60. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +95 -0
  61. data/lib/mongo_mapper/plugins/associations/proxy.rb +134 -0
  62. data/lib/mongo_mapper/plugins/associations/single_association.rb +46 -0
  63. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  64. data/lib/mongo_mapper/plugins/callbacks.rb +29 -0
  65. data/lib/mongo_mapper/plugins/clone.rb +22 -0
  66. data/lib/mongo_mapper/plugins/dirty.rb +60 -0
  67. data/lib/mongo_mapper/plugins/document.rb +41 -0
  68. data/lib/mongo_mapper/plugins/dynamic_querying.rb +45 -0
  69. data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +44 -0
  70. data/lib/mongo_mapper/plugins/embedded_callbacks.rb +56 -0
  71. data/lib/mongo_mapper/plugins/embedded_document.rb +53 -0
  72. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  73. data/lib/mongo_mapper/plugins/identity_map.rb +128 -0
  74. data/lib/mongo_mapper/plugins/indexes.rb +13 -0
  75. data/lib/mongo_mapper/plugins/inspect.rb +16 -0
  76. data/lib/mongo_mapper/plugins/keys.rb +313 -0
  77. data/lib/mongo_mapper/plugins/keys/key.rb +61 -0
  78. data/lib/mongo_mapper/plugins/logger.rb +18 -0
  79. data/lib/mongo_mapper/plugins/modifiers.rb +134 -0
  80. data/lib/mongo_mapper/plugins/pagination.rb +16 -0
  81. data/lib/mongo_mapper/plugins/persistence.rb +69 -0
  82. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  83. data/lib/mongo_mapper/plugins/querying.rb +165 -0
  84. data/lib/mongo_mapper/plugins/querying/decorator.rb +36 -0
  85. data/lib/mongo_mapper/plugins/rails.rb +58 -0
  86. data/lib/mongo_mapper/plugins/rails/active_record_association_adapter.rb +33 -0
  87. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  88. data/lib/mongo_mapper/plugins/sci.rb +36 -0
  89. data/lib/mongo_mapper/plugins/scopes.rb +27 -0
  90. data/lib/mongo_mapper/plugins/serialization.rb +109 -0
  91. data/lib/mongo_mapper/plugins/timestamps.rb +22 -0
  92. data/lib/mongo_mapper/plugins/touch.rb +18 -0
  93. data/lib/mongo_mapper/plugins/userstamps.rb +18 -0
  94. data/lib/mongo_mapper/plugins/validations.rb +86 -0
  95. data/lib/mongo_mapper/railtie.rb +48 -0
  96. data/lib/mongo_mapper/railtie/database.rake +65 -0
  97. data/lib/mongo_mapper/translation.rb +10 -0
  98. data/lib/mongo_mapper/version.rb +4 -0
  99. data/lib/rails/generators/mongo_mapper/config/config_generator.rb +24 -0
  100. data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +18 -0
  101. data/lib/rails/generators/mongo_mapper/model/model_generator.rb +23 -0
  102. data/lib/rails/generators/mongo_mapper/model/templates/model.rb +13 -0
  103. data/test/_NOTE_ON_TESTING +1 -0
  104. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +64 -0
  105. data/test/functional/associations/test_belongs_to_proxy.rb +238 -0
  106. data/test/functional/associations/test_in_array_proxy.rb +349 -0
  107. data/test/functional/associations/test_many_documents_as_proxy.rb +231 -0
  108. data/test/functional/associations/test_many_documents_proxy.rb +866 -0
  109. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +239 -0
  110. data/test/functional/associations/test_many_embedded_proxy.rb +289 -0
  111. data/test/functional/associations/test_many_polymorphic_proxy.rb +303 -0
  112. data/test/functional/associations/test_one_as_proxy.rb +491 -0
  113. data/test/functional/associations/test_one_embedded_polymorphic_proxy.rb +208 -0
  114. data/test/functional/associations/test_one_embedded_proxy.rb +100 -0
  115. data/test/functional/associations/test_one_proxy.rb +383 -0
  116. data/test/functional/test_accessible.rb +198 -0
  117. data/test/functional/test_associations.rb +46 -0
  118. data/test/functional/test_binary.rb +27 -0
  119. data/test/functional/test_caching.rb +77 -0
  120. data/test/functional/test_callbacks.rb +232 -0
  121. data/test/functional/test_dirty.rb +301 -0
  122. data/test/functional/test_document.rb +282 -0
  123. data/test/functional/test_dynamic_querying.rb +75 -0
  124. data/test/functional/test_embedded_document.rb +288 -0
  125. data/test/functional/test_equality.rb +20 -0
  126. data/test/functional/test_identity_map.rb +513 -0
  127. data/test/functional/test_indexes.rb +50 -0
  128. data/test/functional/test_logger.rb +20 -0
  129. data/test/functional/test_modifiers.rb +537 -0
  130. data/test/functional/test_pagination.rb +91 -0
  131. data/test/functional/test_protected.rb +201 -0
  132. data/test/functional/test_querying.rb +935 -0
  133. data/test/functional/test_safe.rb +76 -0
  134. data/test/functional/test_sci.rb +240 -0
  135. data/test/functional/test_scopes.rb +171 -0
  136. data/test/functional/test_timestamps.rb +62 -0
  137. data/test/functional/test_touch.rb +125 -0
  138. data/test/functional/test_userstamps.rb +44 -0
  139. data/test/functional/test_validations.rb +414 -0
  140. data/test/models.rb +261 -0
  141. data/test/support/railtie.rb +4 -0
  142. data/test/support/railtie/autoloaded.rb +2 -0
  143. data/test/support/railtie/not_autoloaded.rb +3 -0
  144. data/test/support/railtie/parent.rb +3 -0
  145. data/test/test_active_model_lint.rb +18 -0
  146. data/test/test_helper.rb +93 -0
  147. data/test/unit/associations/test_base.rb +146 -0
  148. data/test/unit/associations/test_belongs_to_association.rb +29 -0
  149. data/test/unit/associations/test_many_association.rb +63 -0
  150. data/test/unit/associations/test_one_association.rb +47 -0
  151. data/test/unit/associations/test_proxy.rb +100 -0
  152. data/test/unit/serializers/test_json_serializer.rb +216 -0
  153. data/test/unit/serializers/test_xml_serializer.rb +196 -0
  154. data/test/unit/test_clone.rb +69 -0
  155. data/test/unit/test_document.rb +249 -0
  156. data/test/unit/test_dynamic_finder.rb +125 -0
  157. data/test/unit/test_embedded_document.rb +682 -0
  158. data/test/unit/test_equality.rb +38 -0
  159. data/test/unit/test_exceptions.rb +12 -0
  160. data/test/unit/test_extensions.rb +380 -0
  161. data/test/unit/test_identity_map_middleware.rb +34 -0
  162. data/test/unit/test_inspect.rb +47 -0
  163. data/test/unit/test_key.rb +205 -0
  164. data/test/unit/test_keys.rb +65 -0
  165. data/test/unit/test_mongo_mapper.rb +143 -0
  166. data/test/unit/test_pagination.rb +11 -0
  167. data/test/unit/test_plugins.rb +89 -0
  168. data/test/unit/test_rails.rb +183 -0
  169. data/test/unit/test_rails_compatibility.rb +38 -0
  170. data/test/unit/test_rails_reflect_on_association.rb +118 -0
  171. data/test/unit/test_railtie.rb +66 -0
  172. data/test/unit/test_serialization.rb +166 -0
  173. data/test/unit/test_time_zones.rb +44 -0
  174. data/test/unit/test_translation.rb +27 -0
  175. data/test/unit/test_validations.rb +562 -0
  176. metadata +285 -0
@@ -0,0 +1,208 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class OneEmbeddedPolymorhpicProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ @post_class = Doc('Post') do
7
+ key :title, String
8
+ end
9
+ end
10
+
11
+ should "default to nil" do
12
+ @post_class.one :author, :polymorphic => true, :class => Robot
13
+ @post_class.new.author.should be_nil
14
+ end
15
+
16
+ should "return nil instead of a proxy" do
17
+ @post_class.one :author, :polymorphic => true, :class => Robot
18
+ nil.should === @post_class.new.author
19
+ end
20
+
21
+ should "be able to build" do
22
+ @post_class.one :author, :polymorphic => true, :class => Robot
23
+ post = @post_class.create
24
+ author = post.build_author(:serial_number => "1B")
25
+ post.author.should be_instance_of(Robot)
26
+ post.author.should be_new
27
+ post.author.serial_number.should == '1B'
28
+ post.author.should == author
29
+ post.author.post.should == post
30
+ end
31
+
32
+ should "allow assignment of associated document using a hash" do
33
+ @post_class.one :author, :polymorphic => :true, :class => Robot
34
+
35
+ post = @post_class.new('author' => { 'name' => 'Frank', '_type' => 'Human' })
36
+ post.author.name.should == 'Frank'
37
+ post.author.class.should == Human
38
+
39
+ post.save.should be_true
40
+ post.reload
41
+
42
+ post.author.name.should == 'Frank'
43
+ post.author.class.should == Human
44
+ end
45
+
46
+ context "replacing the association" do
47
+ context "with an object" do
48
+ setup do
49
+ @post_class.one :author, :polymorphic => true, :class => Robot
50
+ @post = @post_class.create
51
+ @human = Human.new(:name => 'Frank')
52
+ end
53
+
54
+ should "work" do
55
+ @post.author = @human
56
+ @post.save
57
+ @post.reload
58
+
59
+ @post.author.should == @human
60
+ @post.author.nil?.should be_false
61
+ @post.author.class.should == Human
62
+
63
+ new_human = Human.new(:name => 'Emily')
64
+ @post.author = new_human
65
+ @post.author.should == new_human
66
+ end
67
+
68
+ should "generate a new proxy instead of modifying the existing one" do
69
+ @post.author = @human
70
+ @post.save
71
+ @post.reload
72
+
73
+ @post.author.should == @human
74
+ @post.author.nil?.should be_false
75
+
76
+ original_author = @post.author
77
+ original_author.name.should == 'Frank'
78
+ new_human = Human.new(:name => 'Emily')
79
+ @post.author = new_human
80
+ @post.author.should == new_human
81
+
82
+ original_author.name.should == 'Frank'
83
+ end
84
+
85
+ should "assign _type" do
86
+ @post.author = @human
87
+ @post.author._type.should == "Human"
88
+ end
89
+ end
90
+
91
+ context "with a Hash" do
92
+ setup do
93
+ @post_class.one :author, :polymorphic => true, :class => Robot
94
+ @post = @post_class.create
95
+ end
96
+
97
+ should "convert to an object of the class and work" do
98
+ @post.author = {'serial_number' => '1B'}
99
+ @post.save
100
+ @post.reload
101
+
102
+ @post.author.serial_number.should == '1B'
103
+ @post.author.nil?.should be_false
104
+
105
+ @post.author = {'serial_number' => '2C'}
106
+ @post.author.serial_number.should == '2C'
107
+ end
108
+
109
+ should "convert to an object of _type if given" do
110
+ @post.author = {'name' => 'Frank', '_type' => 'Human'}
111
+ @post.author.name.should == 'Frank'
112
+ @post.author.class.should == Human
113
+ @post.save
114
+ @post.reload
115
+
116
+ @post.author.name.should == 'Frank'
117
+ @post.author.class.should == Human
118
+ end
119
+
120
+ should "assign _type" do
121
+ @post.author = {'name' => 'Frank', '_type' => 'Human'}
122
+ @post.save
123
+ @post.reload
124
+ @post.author._type.should == "Human"
125
+ end
126
+ end
127
+ end
128
+
129
+ should "unset the association" do
130
+ @post_class.one :author, :polymorphic => true, :class => Robot
131
+ post = @post_class.create
132
+ human = Human.new
133
+ post.update_attributes!(:author => human)
134
+ post.reload
135
+ post.author = nil
136
+ post.author.should == nil
137
+ end
138
+
139
+ should "set modularized associated models correctly" do
140
+ @post_class.one :author, :polymorphic => true, :class => Robot
141
+
142
+ post = @post_class.new('author' => {'_type' => 'TrModels::Ambulance', 'license_plate' => 'GGG123', 'icu' => true})
143
+
144
+ post.author.class.should == TrModels::Ambulance
145
+ post.author.license_plate.should == 'GGG123'
146
+ post.author.icu.should be_true
147
+ post.save.should be_true
148
+
149
+ post = post.reload
150
+ post.author.class.should == TrModels::Ambulance
151
+ post.author.license_plate.should == 'GGG123'
152
+ post.author.icu.should be_true
153
+ end
154
+
155
+ should "not have problem loading root document if embedded one is nil" do
156
+ @post_class.one :author, :polymorphic => true, :class => Robot
157
+ post = @post_class.create
158
+
159
+ lambda {
160
+ @post_class.find(post.id)
161
+ }.should_not raise_error
162
+ end
163
+
164
+ should "load the parent and root documents for nested embedded documents" do
165
+ @address_class = EDoc('Address') do
166
+ key :city, String
167
+ key :state, String
168
+ end
169
+ @author_class = EDoc('EmbeddedAuthor')
170
+ @author_class.one :address, :polymorphic => true, :class => @address_class
171
+ @post_class.one :author, :polymorphic => true, :class => @author_class
172
+
173
+ post = @post_class.create(:title => 'Post Title', :author => { :name => 'Frank', :address => { :city => 'Boston', :state => 'MA' } })
174
+
175
+ post.author.address._parent_document.should == post.author
176
+ post.author.address._root_document.should == post
177
+ end
178
+
179
+ should "have boolean method for testing presence" do
180
+ @post_class.one :author, :polymorphic => true, :class => Robot
181
+
182
+ post = @post_class.new
183
+ post.author?.should be_false
184
+
185
+ post.author = Human.new(:name => 'Frank')
186
+ post.author?.should be_true
187
+ end
188
+
189
+ should "initialize id for nested embedded document created from hash" do
190
+ @address_class = EDoc('Address') do
191
+ key :city, String
192
+ key :state, String
193
+ end
194
+ @author_class = EDoc('EmbeddedAuthor')
195
+ @author_class.one :address, :polymorphic => true, :class => @address_class
196
+ @post_class.one :author, :polymorphic => true, :class => @author_class
197
+
198
+ post = @post_class.create(:title => 'Post Title', :author => {
199
+ :name => 'Frank',
200
+ :address => {
201
+ :city => 'Boston',
202
+ :state => 'MA'
203
+ }
204
+ })
205
+
206
+ post.author.address.id.should_not be_nil
207
+ end
208
+ end
@@ -0,0 +1,100 @@
1
+ require 'test_helper'
2
+
3
+ class OneEmbeddedProxyTest < Test::Unit::TestCase
4
+ def setup
5
+ @post_class = Doc('Post') do
6
+ key :title, String
7
+ end
8
+ @author_class = EDoc('Author') do
9
+ key :name, String
10
+ embedded_in :post
11
+ end
12
+ end
13
+
14
+ should "default to nil" do
15
+ @post_class.one :author, :class => @author_class
16
+ @post_class.new.author.should be_nil
17
+ end
18
+
19
+ should "be able to build" do
20
+ @post_class.one :author, :class => @author_class
21
+
22
+ post = @post_class.create
23
+ author = post.build_author(:name => "John")
24
+ post.author.should be_instance_of(@author_class)
25
+ post.author.should be_new
26
+ post.author.name.should == 'John'
27
+ post.author.should == author
28
+ post.author.post.should == post
29
+ end
30
+
31
+ should "be able to replace the association" do
32
+ @post_class.one :author, :class => @author_class
33
+
34
+ post = @post_class.new
35
+ author = @author_class.new(:name => 'Frank')
36
+ post.author = author
37
+ post.save
38
+ post.reload
39
+
40
+ post.author.should == author
41
+ post.author.nil?.should be_false
42
+
43
+ new_author = @author_class.new(:name => 'Emily')
44
+ post.author = new_author
45
+ post.author.should == new_author
46
+ end
47
+
48
+ should "not have problem loading root document if embedded one is nil" do
49
+ @post_class.one :author, :class => @author_class
50
+ post = @post_class.create
51
+
52
+ lambda {
53
+ @post_class.find(post.id)
54
+ }.should_not raise_error
55
+ end
56
+
57
+ should "load the parent and root documents for nested embedded documents" do
58
+ @address_class = EDoc('Address') do
59
+ key :city, String
60
+ key :state, String
61
+ end
62
+ @author_class.one :address, :class => @address_class
63
+ @post_class.one :author, :class => @author_class
64
+
65
+ post = @post_class.create(:title => 'Post Title', :author => { :name => 'Frank', :address => { :city => 'Boston', :state => 'MA' } })
66
+
67
+ post.author.address._parent_document.should == post.author
68
+ post.author.address._root_document.should == post
69
+ end
70
+
71
+ should "have boolean method for testing presence" do
72
+ @post_class.one :author, :class => @author_class
73
+
74
+ post = @post_class.new
75
+ post.author?.should be_false
76
+
77
+ post.author = @author_class.new(:name => 'Frank')
78
+ post.author?.should be_true
79
+ end
80
+
81
+ should "initialize id for nested embedded document created from hash" do
82
+ @address_class = EDoc('Address') do
83
+ key :city, String
84
+ key :state, String
85
+ end
86
+ @author_class.one(:address, :class => @address_class)
87
+ @post_class.one(:author, :class => @author_class)
88
+
89
+ post = @post_class.create(:title => 'Post Title', :author => {
90
+ :name => 'Frank',
91
+ :address => {
92
+ :city => 'Boston',
93
+ :state => 'MA'
94
+ }
95
+ })
96
+
97
+ post.author.address.id.should_not be_nil
98
+ end
99
+
100
+ end
@@ -0,0 +1,383 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class OneProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ @post_class = Doc('Post')
7
+ @author_class = Doc do
8
+ key :post_id, ObjectId
9
+ end
10
+ end
11
+
12
+ should "default to nil" do
13
+ @post_class.one :author, :class => @author_class
14
+ @post_class.new.author.nil?.should be_true
15
+ end
16
+
17
+ should "return nil instead of a proxy" do
18
+ @post_class.one :author, :class => @author_class
19
+ nil.should === @post_class.new.author
20
+ end
21
+
22
+ should "allow assignment of associated document using a hash" do
23
+ @post_class.one :author, :class => @author_class
24
+
25
+ post = @post_class.new('author' => { 'name' => 'Frank' })
26
+ post.author.name.should == 'Frank'
27
+
28
+ post.save.should be_true
29
+ post.reload
30
+
31
+ post.author.name.should == 'Frank'
32
+ end
33
+
34
+ context "replacing the association" do
35
+ context "with an object of the class" do
36
+ should "work" do
37
+ @post_class.one :author, :class => @author_class
38
+
39
+ post = @post_class.new
40
+ author = @author_class.new(:name => 'Frank')
41
+ post.author = author
42
+ post.reload
43
+
44
+ post.author.should == author
45
+ post.author.nil?.should be_false
46
+
47
+ new_author = @author_class.new(:name => 'Emily')
48
+ post.author = new_author
49
+ post.author.should == new_author
50
+ end
51
+
52
+ should "generate a new proxy instead of modifying the existing one" do
53
+ @post_class.one :author, :class => @author_class
54
+
55
+ post = @post_class.new
56
+ author = @author_class.new(:name => 'Frank')
57
+ post.author = author
58
+ post.reload
59
+
60
+ post.author.should == author
61
+ post.author.nil?.should be_false
62
+
63
+ original_author = post.author
64
+ original_author.name.should == 'Frank'
65
+ new_author = @author_class.new(:name => 'Emily')
66
+ post.author = new_author
67
+ post.author.should == new_author
68
+
69
+ original_author.name.should == 'Frank'
70
+ end
71
+ end
72
+
73
+ context "with a Hash" do
74
+ should "convert to an object of the class and work" do
75
+ @post_class.one :author, :class => @author_class
76
+
77
+ post = @post_class.new
78
+ post.author = {'name' => 'Frank'}
79
+ post.reload
80
+
81
+ post.author.name.should == 'Frank'
82
+ post.author.nil?.should be_false
83
+
84
+ post.author = {'name' => 'Emily'}
85
+ post.author.name.should == 'Emily'
86
+ end
87
+ end
88
+
89
+ context "with :dependent" do
90
+ context "=> delete" do
91
+ setup do
92
+ @post_class.one :author, :class => @author_class, :dependent => :delete
93
+
94
+ @post = @post_class.create
95
+ @author = @author_class.new
96
+ @post.author = @author
97
+ end
98
+
99
+ should "call delete on the existing document" do
100
+ @author_class.any_instance.expects(:delete).once
101
+ @post.author = @author_class.new
102
+ end
103
+
104
+ should "remove the existing document from the database" do
105
+ @post.author = @author_class.new
106
+ lambda { @author.reload }.should raise_error(MongoMapper::DocumentNotFound)
107
+ end
108
+
109
+ should "do nothing if it's the same document" do
110
+ @author_class.any_instance.expects(:delete).never
111
+ @post.author = @author
112
+ end
113
+ end
114
+
115
+ context "=> destory" do
116
+ setup do
117
+ @post_class.one :author, :class => @author_class, :dependent => :destroy
118
+
119
+ @post = @post_class.create
120
+ @author = @author_class.new
121
+ @post.author = @author
122
+ end
123
+
124
+ should "call destroy the existing document" do
125
+ @author_class.any_instance.expects(:destroy).once
126
+ @post.author = @author_class.new
127
+ end
128
+
129
+ should "remove the existing document from the database" do
130
+ @post.author = @author_class.new
131
+ lambda { @author.reload }.should raise_error(MongoMapper::DocumentNotFound)
132
+ end
133
+
134
+ should "do nothing if it's the same document" do
135
+ @author_class.any_instance.expects(:destroy).never
136
+ @post.author = @author
137
+ end
138
+ end
139
+
140
+ context "=> nullify" do
141
+ setup do
142
+ @post_class.one :author, :class => @author_class, :dependent => :nullify
143
+
144
+ @post = @post_class.create
145
+ @author = @author_class.new
146
+ @post.author = @author
147
+ end
148
+
149
+ should "nullify the existing document" do
150
+ @author.reload
151
+ @author.post_id.should == @post.id
152
+
153
+ @post.author = @author_class.new
154
+
155
+ @author.reload
156
+ @author.post_id.should be_nil
157
+ end
158
+
159
+ should "work when it's the same document" do
160
+ old_author = @post.author
161
+ @post.author = @author
162
+ old_author.should == @post.author
163
+ end
164
+ end
165
+
166
+ context "unspecified" do
167
+ should "nullify the existing document" do
168
+ @post_class.one :author, :class => @author_class
169
+
170
+ post = @post_class.create
171
+ author = @author_class.new
172
+ post.author = author
173
+ author.reload
174
+ author.post_id.should == post.id
175
+
176
+ post.author = @author_class.new
177
+
178
+ author.reload
179
+ author.post_id.should be_nil
180
+ end
181
+ end
182
+ end
183
+
184
+ context "with nil" do
185
+ setup do
186
+ @post_class.one :author, :class => @author_class
187
+
188
+ @post = @post_class.new
189
+ @author = @author_class.new(:name => 'Frank')
190
+ @post.author = @author
191
+ end
192
+
193
+ should "nullify the existing document" do
194
+ @post.author = nil
195
+ @author.reload
196
+ @author.post_id.should be_nil
197
+ end
198
+
199
+ should "set the target to nil" do
200
+ @post.author = nil
201
+ @post.author.should == nil
202
+ end
203
+ end
204
+ end
205
+
206
+ should "have boolean method for testing presence" do
207
+ @post_class.one :author, :class => @author_class
208
+
209
+ post = @post_class.new
210
+ post.author?.should be_false
211
+
212
+ post.author = @author_class.new(:name => 'Frank')
213
+ post.author?.should be_true
214
+ end
215
+
216
+ should "work with criteria" do
217
+ @post_class.one :primary_author, :class => @author_class, :primary => true
218
+ @post_class.one :author, :class => @author_class, :primary => false
219
+
220
+ post = @post_class.create
221
+ author = @author_class.create(:name => 'Frank', :primary => false, :post_id => post.id)
222
+ primary = @author_class.create(:name => 'Bill', :primary => true, :post_id => post.id)
223
+ post.reload
224
+ post.author.should == author
225
+ post.primary_author.should == primary
226
+ end
227
+
228
+ should "unset the association" do
229
+ @post_class.one :author, :class => @author_class
230
+ post = @post_class.create
231
+ author = @author_class.create
232
+ post.update_attributes!(:author => author)
233
+ post.reload
234
+ post.author = nil
235
+ post.author.nil?.should be_true
236
+ end
237
+
238
+ context "destroying parent with :dependent" do
239
+ context "=> destroy" do
240
+ setup do
241
+ @post_class.one :author, :class => @author_class, :dependent => :destroy
242
+
243
+ @post = @post_class.create
244
+ @author = @author_class.new
245
+ @post.author = @author
246
+ end
247
+
248
+ should "should call destroy on the associated documents" do
249
+ @author_class.any_instance.expects(:destroy).once
250
+ @post.destroy
251
+ end
252
+
253
+ should "should remove the associated documents" do
254
+ @author_class.count.should == 1
255
+ @post.destroy
256
+ @post.author.should == nil
257
+ @author_class.count.should == 0
258
+ end
259
+ end
260
+
261
+ context "=> delete" do
262
+ setup do
263
+ @post_class.one :author, :class => @author_class, :dependent => :delete
264
+
265
+ @post = @post_class.create
266
+ @author = @author_class.new
267
+ @post.author = @author
268
+ end
269
+
270
+ should "should call delete the associated documents" do
271
+ @author_class.any_instance.expects(:delete).once
272
+ @post.destroy
273
+ end
274
+
275
+ should "remove the associated documents" do
276
+ @author_class.count.should == 1
277
+ @post.destroy
278
+ @post.author.should == nil
279
+ @author_class.count.should == 0
280
+ end
281
+ end
282
+
283
+ context "=> nullify" do
284
+ should "should nullify the relationship but not destroy the associated document" do
285
+ @post_class.one :author, :class => @author_class, :dependent => :nullify
286
+
287
+ post = @post_class.create
288
+ author = @author_class.new
289
+ post.author = author
290
+
291
+ @author_class.count.should == 1
292
+ post.destroy
293
+ post.author.should == nil
294
+ @author_class.count.should == 1
295
+
296
+ @author_class.first.should == author
297
+ author.post_id.should == nil
298
+ end
299
+ end
300
+
301
+ context "unspecified" do
302
+ should "should nullify the relationship but not destroy the associated document" do
303
+ @post_class.one :author, :class => @author_class
304
+
305
+ post = @post_class.create
306
+ author = @author_class.new
307
+ post.author = author
308
+
309
+ @author_class.count.should == 1
310
+ post.destroy
311
+ post.author.should == nil
312
+ @author_class.count.should == 1
313
+
314
+ @author_class.first.should == author
315
+ author.post_id.should == nil
316
+ end
317
+ end
318
+ end
319
+
320
+
321
+ should "be able to build" do
322
+ @post_class.one :author, :class => @author_class
323
+
324
+ post = @post_class.create
325
+ author = post.build_author(:name => 'John')
326
+ post.author.should be_instance_of(@author_class)
327
+ post.author.should be_new
328
+ post.author.name.should == 'John'
329
+ post.author.should == author
330
+ post.author.post_id.should == post.id
331
+ end
332
+
333
+ should "be able to create" do
334
+ @post_class.one :author, :class => @author_class
335
+
336
+ post = @post_class.create
337
+ author = post.create_author(:name => 'John')
338
+ post.author.should be_instance_of(@author_class)
339
+ post.author.should_not be_new
340
+ post.author.name.should == 'John'
341
+ post.author.should == author
342
+ post.author.post_id.should == post.id
343
+ end
344
+
345
+ context "#create!" do
346
+ setup do
347
+ @author_class.key :name, String, :required => true
348
+ @post_class.one :author, :class => @author_class
349
+ end
350
+
351
+ should "raise exception if invalid" do
352
+ post = @post_class.create
353
+ assert_raises(MongoMapper::DocumentNotValid) do
354
+ post.create_author!
355
+ end
356
+ end
357
+
358
+ should "work if valid" do
359
+ post = @post_class.create
360
+ author = post.create_author!(:name => 'John')
361
+ post.author.should be_instance_of(@author_class)
362
+ post.author.should_not be_new
363
+ post.author.name.should == 'John'
364
+ post.author.should == author
365
+ post.author.post_id.should == post.id
366
+ end
367
+ end
368
+
369
+ context "namespaced foreign keys" do
370
+ setup do
371
+ News::Paper.one :article, :class_name => 'News::Article'
372
+ News::Article.belongs_to :paper, :class_name => 'News::Paper'
373
+
374
+ @paper = News::Paper.create
375
+ end
376
+
377
+ should "properly infer the foreign key" do
378
+ article = @paper.create_article
379
+ article.should respond_to(:paper_id)
380
+ article.paper_id.should == @paper.id
381
+ end
382
+ end
383
+ end