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,196 @@
1
+ require 'test_helper'
2
+
3
+ class XmlSerializationTest < Test::Unit::TestCase
4
+ class Tag
5
+ include MongoMapper::EmbeddedDocument
6
+ key :name, String
7
+ end
8
+
9
+ class Contact
10
+ include MongoMapper::Document
11
+ key :name, String
12
+ key :age, Integer
13
+ key :created_at, Time
14
+ key :awesome, Boolean
15
+ key :preferences, Hash
16
+
17
+ many :tags, :class_name => 'XmlSerializationTest::Tag'
18
+ end
19
+
20
+ def setup
21
+ Kernel.const_set('TopLevelContact', Doc('TopLevelContact'))
22
+ TopLevelContact.key :name, String
23
+
24
+ Contact.include_root_in_json = false
25
+ @contact = Contact.new(
26
+ :name => 'Konata Izumi',
27
+ :age => 16,
28
+ :created_at => Time.utc(2006, 8, 1),
29
+ :awesome => true,
30
+ :preferences => { :shows => 'anime' }
31
+ )
32
+ @top_level_contact = TopLevelContact.new(
33
+ :name => 'Konata Izumi'
34
+ )
35
+ end
36
+
37
+ def teardown
38
+ Kernel.send(:remove_const, 'TopLevelContact') if Object.const_defined?('TopLevelContact')
39
+ end
40
+
41
+ should "include root for class with no module" do
42
+ assert_match %r{<top-level-contact>}, @top_level_contact.to_xml
43
+ end
44
+
45
+ should "include demodulized root" do
46
+ assert_match %r{<contact>}, @contact.to_xml
47
+ end
48
+
49
+ should "encode all encodable attributes" do
50
+ xml = @contact.to_xml
51
+
52
+ assert_no_match %r{_id}, xml
53
+ assert_match %r{<id>#{@contact.id}</id>}, xml
54
+ assert_match %r{<name>Konata Izumi</name>}, xml
55
+ assert_match %r{<age.*>16</age>}, xml
56
+ assert_match %r(<created-at type="datetime">), xml
57
+ assert_match %r{<awesome type="boolean">true</awesome>}, xml
58
+ assert_match %r{<preferences>}, xml
59
+ assert_match %r{<shows>anime</shows>}, xml
60
+ end
61
+
62
+ should "allow attribute filtering with only" do
63
+ xml = @contact.to_xml(:only => [:name, :age])
64
+
65
+ assert_no_match %r{<id>}, xml
66
+ assert_match %r{<name>Konata Izumi</name>}, xml
67
+ assert_match %r{<age type="integer">16</age>}, xml
68
+ assert_no_match %r{awesome}, xml
69
+ assert_no_match %r{created-at}, xml
70
+ assert_no_match %r{preferences}, xml
71
+ end
72
+
73
+ should "allow attribute filtering with except" do
74
+ xml = @contact.to_xml(:except => [:name, :age])
75
+
76
+ assert_no_match %r{<name>Konata Izumi</name>}, xml
77
+ assert_no_match %r{<age type="integer">16</age>}, xml
78
+ assert_match %r{<id>}, xml
79
+ assert_match %r{awesome}, xml
80
+ assert_match %r{created-at}, xml
81
+ assert_match %r{preferences}, xml
82
+ end
83
+
84
+ context "_id key" do
85
+ should "not be included by default" do
86
+ assert_no_match %r{_id}, @contact.to_xml
87
+ end
88
+
89
+ should "not be included even if :except is used" do
90
+ assert_no_match %r{_id}, @contact.to_xml(:except => :name)
91
+ end
92
+ end
93
+
94
+ context "id method" do
95
+ setup do
96
+ def @contact.label; "Has cheezburger"; end
97
+ def @contact.favorite_quote; "Constraints are liberating"; end
98
+ end
99
+
100
+ should "be included by default" do
101
+ assert_match %r{<id>#{@contact.id}</id>}, @contact.to_xml
102
+ end
103
+
104
+ should "be included when single method included" do
105
+ xml = @contact.to_xml(:methods => :label)
106
+ assert_match %r{<id>}, xml
107
+ assert_match %r{<label>Has cheezburger</label>}, xml
108
+ assert_match %r{<name>Konata Izumi</name>}, xml
109
+ assert_no_match %r{favorite_quote}, xml
110
+ end
111
+
112
+ should "be included when multiple methods included" do
113
+ xml = @contact.to_xml(:methods => [:label, :favorite_quote])
114
+ assert_match %r{<id>}, xml
115
+ assert_match %r{<label>Has cheezburger</label>}, xml
116
+ assert_match %r{<name>Konata Izumi</name>}, xml
117
+ assert_match %r{<favorite-quote>Constraints are liberating</favorite-quote>}, xml
118
+ end
119
+
120
+ should "not be included if :only is present" do
121
+ assert_no_match %r{<id}, @contact.to_xml(:only => :name)
122
+ end
123
+
124
+ should "be represented by a string" do
125
+ assert_match %r{<id>}, @contact.to_xml
126
+ end
127
+ end
128
+
129
+ context "including methods" do
130
+ setup do
131
+ def @contact.label; "Has cheezburger"; end
132
+ def @contact.favorite_quote; "Constraints are liberating"; end
133
+ end
134
+
135
+ should "include single method" do
136
+ assert_match %r{<label>Has cheezburger</label>}, @contact.to_xml(:methods => :label)
137
+ end
138
+
139
+ should "include multiple methods" do
140
+ xml = @contact.to_xml(:only => :name, :methods => [:label, :favorite_quote])
141
+ assert_match %r{<label>Has cheezburger</label>}, xml
142
+ assert_match %r{<favorite-quote>Constraints are liberating</favorite-quote>}, xml
143
+ assert_match %r{<name>Konata Izumi</name>}, xml
144
+ assert_no_match %r{age}, xml
145
+ assert_no_match %r{awesome}, xml
146
+ assert_no_match %r{created-at}, xml
147
+ assert_no_match %r{preferences}, xml
148
+
149
+ # Assert only one tag is created
150
+ xml.scan(/favorite-quote/).size.should == 2
151
+ end
152
+ end
153
+
154
+ context "array of records" do
155
+ setup do
156
+ @contacts = [
157
+ Contact.new(:name => 'David', :age => 39),
158
+ Contact.new(:name => 'Mary', :age => 14)
159
+ ]
160
+ end
161
+
162
+ should "allow attribute filtering with only" do
163
+ xml = @contacts.to_xml(:only => :name)
164
+ assert_match %r{<name>David</name>}, xml
165
+ assert_match %r{<name>Mary</name>}, xml
166
+ end
167
+
168
+ should "allow attribute filtering with except" do
169
+ xml = @contacts.to_xml(:except => [:name, :preferences, :awesome, :created_at, :updated_at])
170
+ assert_match %r{<age type="integer">39</age>}, xml
171
+ assert_match %r{<age type="integer">14</age>}, xml
172
+ assert_no_match %r{name}, xml
173
+ assert_no_match %r{preferences}, xml
174
+ assert_no_match %r{awesome}, xml
175
+ assert_no_match %r{created-at}, xml
176
+ assert_no_match %r{updated-at}, xml
177
+ end
178
+ end
179
+
180
+ should "include embedded attributes" do
181
+ contact = Contact.new(:name => 'John', :age => 27)
182
+ contact.tags = [Tag.new(:name => 'awesome'), Tag.new(:name => 'ruby')]
183
+ xml = contact.to_xml
184
+ assert_match %r{<tags type="array">}, xml
185
+ assert_match %r{<id>#{contact.tags[0].id}</id>}, xml
186
+ assert_match %r{<id>#{contact.tags[1].id}</id>}, xml
187
+ assert_match %r{<name>awesome</name>}, xml
188
+ assert_match %r{<name>ruby</name>}, xml
189
+ end
190
+
191
+ should "include dynamic attributes" do
192
+ contact = Contact.new(:name => 'John', :age => 27, :foo => 'bar')
193
+ contact['smell'] = 'stinky'
194
+ assert_match %r{<smell>stinky</smell>}, contact.to_xml
195
+ end
196
+ end
@@ -0,0 +1,69 @@
1
+ require 'test_helper'
2
+
3
+ class CloneTest < Test::Unit::TestCase
4
+ context "Document" do
5
+ setup do
6
+ @document = Doc()
7
+ @embedded = EDoc()
8
+ @document.many :widgets, :class => @embedded
9
+ @tags = ['red', 'green', 'blue']
10
+ @doc = @document.create({
11
+ :name => "foo",
12
+ :age => 27,
13
+ :tags => @tags,
14
+ :widgets => [@embedded.new, @embedded.new],
15
+ })
16
+ end
17
+
18
+ context "#clone" do
19
+ should "be new" do
20
+ @doc.clone.should be_new
21
+ end
22
+
23
+ should "copy the attributes" do
24
+ clone = @doc.clone
25
+ clone.name.should == "foo"
26
+ clone.age.should == 27
27
+ end
28
+
29
+ should "clone duplicable attributes" do
30
+ @doc.clone.tags.should_not equal(@tags)
31
+ end
32
+
33
+ should "clone many embedded documents" do
34
+ @doc.clone.widgets.object_id.should_not equal(@doc.widgets.object_id)
35
+ end
36
+
37
+ should "not be destroyed" do
38
+ @doc.destroy
39
+ @doc.clone.should_not be_destroyed
40
+ end
41
+ end
42
+ end
43
+
44
+ context "EmbeddedDocument" do
45
+ setup do
46
+ @document = EDoc do
47
+ key :name, String
48
+ key :age, Integer
49
+ end
50
+ end
51
+
52
+ context "#clone" do
53
+ should "regenerate the id" do
54
+ doc = @document.new(:name => "foo", :age => 27)
55
+ doc_id = doc.id
56
+ clone = doc.clone
57
+ clone_id = clone.id
58
+ clone_id.should_not == doc_id
59
+ end
60
+
61
+ should "copy the attributes" do
62
+ doc = @document.new(:name => "foo", :age => 27)
63
+ clone = doc.clone
64
+ clone.name.should == "foo"
65
+ clone.age.should == 27
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,249 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class DocumentTest < Test::Unit::TestCase
5
+ context "The Document Class" do
6
+ setup do
7
+ @document = Doc()
8
+ end
9
+
10
+ should "return false for embeddable" do
11
+ Doc().embeddable?.should be_false
12
+ end
13
+
14
+ should "have logger method" do
15
+ @document.logger.should == MongoMapper.logger
16
+ @document.logger.should be_instance_of(Logger)
17
+ end
18
+
19
+ should "use default database by default" do
20
+ @document.database.should == MongoMapper.database
21
+ end
22
+
23
+ should "have a connection" do
24
+ @document.connection.should be_instance_of(Mongo::Connection)
25
+ end
26
+
27
+ should "allow setting different connection without affecting the default" do
28
+ conn = Mongo::Connection.new
29
+ @document.connection conn
30
+ @document.connection.should == conn
31
+ @document.connection.should_not == MongoMapper.connection
32
+ end
33
+
34
+ should "allow setting a different database without affecting the default" do
35
+ @document.set_database_name 'test2'
36
+ @document.database_name.should == 'test2'
37
+ @document.database.name.should == 'test2'
38
+
39
+ another_document = Doc()
40
+ another_document.database.should == MongoMapper.database
41
+ end
42
+
43
+ should "allow setting the collection name" do
44
+ @document.set_collection_name('foobar')
45
+ @document.collection.name.should == 'foobar'
46
+ end
47
+
48
+ context ".collection" do
49
+ should "default collection name to class name tableized" do
50
+ class ::Item
51
+ include MongoMapper::Document
52
+ end.collection.name.should == 'items'
53
+ end
54
+
55
+ should "default collection name of namespaced class to tableized with dot separation" do
56
+ module ::BloggyPoo
57
+ class Post
58
+ include MongoMapper::Document
59
+ end.collection.name.should == 'bloggy_poo.posts'
60
+ end
61
+ end
62
+
63
+ should "be an instance of a Mongo::Collection" do
64
+ @document.collection.should be_instance_of(Mongo::Collection)
65
+ end
66
+ end
67
+ end # Document class
68
+
69
+ context "Documents that inherit from other documents" do
70
+ should "default collection name to inherited class" do
71
+ Message.collection_name.should == 'messages'
72
+ Enter.collection_name.should == 'messages'
73
+ Exit.collection_name.should == 'messages'
74
+ Chat.collection_name.should == 'messages'
75
+ end
76
+
77
+ should "default associations to inherited class" do
78
+ Message.associations.keys.should include(:room)
79
+ Enter.associations.keys.should include(:room)
80
+ Exit.associations.keys.should include(:room)
81
+ Chat.associations.keys.should include(:room)
82
+ end
83
+ end
84
+
85
+ context "descendants" do
86
+ should "default to an empty array" do
87
+ Enter.descendants.should == []
88
+ end
89
+
90
+ should "be recorded" do
91
+ Message.descendants.should == [Enter, Exit, Chat]
92
+ end
93
+ end
94
+
95
+ context "An instance of a document" do
96
+ setup do
97
+ @document = Doc do
98
+ key :name, String
99
+ key :age, Integer
100
+ end
101
+ end
102
+
103
+ should "respond to cache_key" do
104
+ @document.new.should respond_to(:cache_key)
105
+ end
106
+
107
+ should "create id during initialization" do
108
+ @document.new._id.should be_instance_of(BSON::ObjectId)
109
+ end
110
+
111
+ should "have access to logger" do
112
+ doc = @document.new
113
+ doc.logger.should == @document.logger
114
+ doc.logger.should be_instance_of(Logger)
115
+ end
116
+
117
+ should "have access to the class's collection" do
118
+ doc = @document.new
119
+ doc.collection.name.should == @document.collection.name
120
+ end
121
+
122
+ should "use default values if defined for keys" do
123
+ @document.key :active, Boolean, :default => true
124
+
125
+ @document.new.active.should be_true
126
+ @document.new(:active => false).active.should be_false
127
+ end
128
+
129
+ should "use default values if defined even when custom data type" do
130
+ @document.key :window, WindowSize, :default => WindowSize.new(600, 480)
131
+
132
+ doc = @document.new
133
+ doc.window.should == WindowSize.new(600, 480)
134
+ end
135
+
136
+ context "root document" do
137
+ should "set self to the root document on embedded documents" do
138
+ klass = Doc()
139
+ pets = EDoc()
140
+
141
+ klass.many :pets, :class => pets
142
+
143
+ doc = klass.new(:pets => [{}])
144
+ doc.pets.first._root_document.should == doc
145
+ end
146
+ end
147
+
148
+ context "new?" do
149
+ should "be true if no id" do
150
+ @document.new.new?.should be_true
151
+ end
152
+
153
+ should "be true if id but using custom id and not saved yet" do
154
+ @document.key :_id, String
155
+ doc = silence_stderr { @document.new }
156
+ doc.id = '1234'
157
+ doc.new?.should be_true
158
+ end
159
+ end
160
+
161
+ context "equality" do
162
+ setup do
163
+ @oid = BSON::ObjectId.new
164
+ end
165
+
166
+ should "delegate hash to _id" do
167
+ doc = @document.new
168
+ doc.hash.should == doc._id.hash
169
+ end
170
+
171
+ should "delegate eql to ==" do
172
+ doc = @document.new
173
+ other = @document.new
174
+ doc.eql?(other).should == (doc == other)
175
+ doc.eql?(doc).should == (doc == doc)
176
+ end
177
+
178
+ should "know if same object as another" do
179
+ doc = @document.new
180
+ doc.should equal(doc)
181
+ doc.should_not equal(@document.new)
182
+ end
183
+
184
+ should "allow set operations on array of documents" do
185
+ @document.key :parent_id, ObjectId
186
+ @document.belongs_to :parent, :class => @document
187
+
188
+ parent = @document.create
189
+ child = @document.create(:parent => parent)
190
+
191
+ ([child.parent] & [parent]).should == [parent]
192
+ end
193
+
194
+ should "be equal if id and class are the same" do
195
+ (@document.new('_id' => @oid) == @document.new('_id' => @oid)).should be(true)
196
+ end
197
+
198
+ should "not be equal if class same but id different" do
199
+ (@document.new('_id' => @oid) == @document.new('_id' => BSON::ObjectId.new)).should be(false)
200
+ end
201
+
202
+ should "not be equal if id same but class different" do
203
+ another_document = Doc()
204
+ (@document.new('_id' => @oid) == another_document.new('_id' => @oid)).should be(false)
205
+ end
206
+ end
207
+
208
+ context "nil attributes" do
209
+
210
+ should "list all the keys and default non nil attributes" do
211
+ doc = @document.new
212
+ doc.keys.keys.sort.should == ['_id', 'age', 'name']
213
+ doc.attributes.keys.sort.should == ['_id']
214
+ end
215
+
216
+ should "list all the keys and non nil attributes" do
217
+ doc = @document.new(:name => "John")
218
+ doc.keys.keys.sort.should == ['_id', 'age', 'name']
219
+ doc.attributes.keys.sort.should == ['_id','name']
220
+ end
221
+
222
+ should "list all the keys and pickup changed nil attributes" do
223
+ doc = @document.new(:name => "John")
224
+ doc.keys.keys.sort.should == ['_id', 'age', 'name']
225
+ doc.attributes.keys.sort.should == ['_id','name']
226
+
227
+ doc.name = nil
228
+
229
+ doc.keys.keys.sort.should == ['_id', 'age', 'name']
230
+ doc.attributes.keys.sort.should == ['_id']
231
+ end
232
+
233
+ should "list all the keys and pickup changed nil and non-nil attributes" do
234
+ doc = @document.new(:name => "John")
235
+ doc.keys.keys.sort.should == ['_id', 'age', 'name']
236
+ doc.attributes.keys.sort.should == ['_id','name']
237
+
238
+ doc.name = nil
239
+ doc.age = 12
240
+
241
+ doc.keys.keys.sort.should == ['_id', 'age', 'name']
242
+ doc.attributes.keys.sort.should == ['_id','age']
243
+ end
244
+
245
+ end
246
+
247
+ end # instance of a document
248
+ end # DocumentTest
249
+