mongo_mapper 0.6.10 → 0.7.0

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 (106) hide show
  1. data/README.rdoc +5 -14
  2. data/Rakefile +1 -1
  3. data/VERSION +1 -1
  4. data/lib/mongo_mapper.rb +48 -56
  5. data/lib/mongo_mapper/document.rb +136 -164
  6. data/lib/mongo_mapper/embedded_document.rb +29 -354
  7. data/lib/mongo_mapper/plugins.rb +31 -0
  8. data/lib/mongo_mapper/plugins/associations.rb +105 -0
  9. data/lib/mongo_mapper/plugins/associations/base.rb +123 -0
  10. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
  11. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
  12. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  13. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +50 -0
  14. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
  15. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  16. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
  17. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  18. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  19. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  20. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  21. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  22. data/lib/mongo_mapper/plugins/callbacks.rb +65 -0
  23. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  24. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  25. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  26. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  27. data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
  28. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  29. data/lib/mongo_mapper/plugins/keys.rb +324 -0
  30. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  31. data/lib/mongo_mapper/plugins/pagination.rb +24 -0
  32. data/lib/mongo_mapper/plugins/pagination/proxy.rb +68 -0
  33. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  34. data/lib/mongo_mapper/plugins/rails.rb +45 -0
  35. data/lib/mongo_mapper/plugins/serialization.rb +105 -0
  36. data/lib/mongo_mapper/plugins/validations.rb +46 -0
  37. data/lib/mongo_mapper/query.rb +130 -0
  38. data/lib/mongo_mapper/support.rb +40 -17
  39. data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
  40. data/lib/mongo_mapper/support/find.rb +77 -0
  41. data/mongo_mapper.gemspec +55 -38
  42. data/performance/read_write.rb +52 -0
  43. data/specs.watchr +23 -2
  44. data/test/functional/associations/test_belongs_to_proxy.rb +12 -10
  45. data/test/functional/associations/test_many_documents_as_proxy.rb +4 -21
  46. data/test/functional/associations/test_many_documents_proxy.rb +2 -8
  47. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +59 -39
  48. data/test/functional/associations/test_many_embedded_proxy.rb +145 -81
  49. data/test/functional/associations/test_many_polymorphic_proxy.rb +2 -40
  50. data/test/functional/associations/test_one_proxy.rb +25 -10
  51. data/test/functional/test_binary.rb +2 -8
  52. data/test/functional/test_callbacks.rb +1 -5
  53. data/test/functional/test_dirty.rb +27 -23
  54. data/test/functional/test_document.rb +224 -165
  55. data/test/functional/test_embedded_document.rb +72 -82
  56. data/test/functional/test_identity_map.rb +508 -0
  57. data/test/functional/test_modifiers.rb +15 -5
  58. data/test/functional/test_pagination.rb +1 -3
  59. data/test/functional/test_protected.rb +155 -0
  60. data/test/functional/test_string_id_compatibility.rb +7 -12
  61. data/test/functional/test_validations.rb +26 -58
  62. data/test/models.rb +0 -39
  63. data/test/test_helper.rb +37 -3
  64. data/test/unit/associations/test_base.rb +5 -5
  65. data/test/unit/associations/test_proxy.rb +8 -6
  66. data/test/unit/test_descendant_appends.rb +71 -0
  67. data/test/unit/test_document.rb +71 -76
  68. data/test/unit/test_dynamic_finder.rb +27 -29
  69. data/test/unit/test_embedded_document.rb +555 -601
  70. data/test/unit/{test_key.rb → test_keys.rb} +2 -5
  71. data/test/unit/test_mongo_mapper.rb +69 -9
  72. data/test/unit/test_pagination.rb +40 -32
  73. data/test/unit/test_plugins.rb +50 -0
  74. data/test/unit/{test_finder_options.rb → test_query.rb} +74 -65
  75. data/test/unit/test_rails.rb +123 -0
  76. data/test/unit/{test_serializations.rb → test_serialization.rb} +1 -2
  77. data/test/unit/test_support.rb +23 -7
  78. data/test/unit/test_time_zones.rb +3 -4
  79. data/test/unit/test_validations.rb +58 -17
  80. metadata +53 -36
  81. data/lib/mongo_mapper/associations.rb +0 -78
  82. data/lib/mongo_mapper/associations/base.rb +0 -119
  83. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +0 -26
  84. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +0 -21
  85. data/lib/mongo_mapper/associations/collection.rb +0 -19
  86. data/lib/mongo_mapper/associations/in_array_proxy.rb +0 -137
  87. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +0 -26
  88. data/lib/mongo_mapper/associations/many_documents_proxy.rb +0 -115
  89. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +0 -31
  90. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +0 -54
  91. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +0 -11
  92. data/lib/mongo_mapper/associations/one_proxy.rb +0 -64
  93. data/lib/mongo_mapper/associations/proxy.rb +0 -116
  94. data/lib/mongo_mapper/callbacks.rb +0 -61
  95. data/lib/mongo_mapper/dirty.rb +0 -117
  96. data/lib/mongo_mapper/dynamic_finder.rb +0 -74
  97. data/lib/mongo_mapper/finder_options.rb +0 -145
  98. data/lib/mongo_mapper/key.rb +0 -36
  99. data/lib/mongo_mapper/mongo_mapper.rb +0 -125
  100. data/lib/mongo_mapper/pagination.rb +0 -66
  101. data/lib/mongo_mapper/rails_compatibility/document.rb +0 -15
  102. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +0 -28
  103. data/lib/mongo_mapper/serialization.rb +0 -54
  104. data/lib/mongo_mapper/serializers/json_serializer.rb +0 -48
  105. data/lib/mongo_mapper/validations.rb +0 -39
  106. data/test/functional/test_rails_compatibility.rb +0 -25
@@ -1,125 +1,123 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class DynamicFinderTest < Test::Unit::TestCase
4
- include MongoMapper
5
-
6
4
  should "initialize with method" do
7
- finder = DynamicFinder.new(:foobar)
5
+ finder = MongoMapper::Support::Find::DynamicFinder.new(:foobar)
8
6
  finder.method.should == :foobar
9
7
  end
10
8
 
11
9
  context "found?" do
12
10
  should "be true for find_by" do
13
- DynamicFinder.new(:find_by_foo).found?.should be_true
11
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo).found?.should be_true
14
12
  end
15
13
 
16
14
  should "be true for find_by with !" do
17
- DynamicFinder.new(:find_by_foo!).found?.should be_true
15
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo!).found?.should be_true
18
16
  end
19
17
 
20
18
  should "be true for find_all_by" do
21
- DynamicFinder.new(:find_all_by_foo).found?.should be_true
19
+ MongoMapper::Support::Find::DynamicFinder.new(:find_all_by_foo).found?.should be_true
22
20
  end
23
21
 
24
22
  should "be true for find_or_initialize_by" do
25
- DynamicFinder.new(:find_or_initialize_by_foo).found?.should be_true
23
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_initialize_by_foo).found?.should be_true
26
24
  end
27
25
 
28
26
  should "be true for find_or_create_by" do
29
- DynamicFinder.new(:find_or_create_by_foo).found?.should be_true
27
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_create_by_foo).found?.should be_true
30
28
  end
31
29
 
32
30
  should "be false for anything else" do
33
31
  [:foobar, :bazwick].each do |method|
34
- DynamicFinder.new(method).found?.should be_false
32
+ MongoMapper::Support::Find::DynamicFinder.new(method).found?.should be_false
35
33
  end
36
34
  end
37
35
  end
38
36
 
39
37
  context "find_all_by" do
40
38
  should "parse one attribute" do
41
- DynamicFinder.new(:find_all_by_foo).attributes.should == %w(foo)
39
+ MongoMapper::Support::Find::DynamicFinder.new(:find_all_by_foo).attributes.should == %w(foo)
42
40
  end
43
41
 
44
42
  should "parse multiple attributes" do
45
- DynamicFinder.new(:find_all_by_foo_and_bar).attributes.should == %w(foo bar)
46
- DynamicFinder.new(:find_all_by_foo_and_bar_and_baz).attributes.should == %w(foo bar baz)
43
+ MongoMapper::Support::Find::DynamicFinder.new(:find_all_by_foo_and_bar).attributes.should == %w(foo bar)
44
+ MongoMapper::Support::Find::DynamicFinder.new(:find_all_by_foo_and_bar_and_baz).attributes.should == %w(foo bar baz)
47
45
  end
48
46
 
49
47
  should "set finder to :all" do
50
- DynamicFinder.new(:find_all_by_foo_and_bar).finder.should == :all
48
+ MongoMapper::Support::Find::DynamicFinder.new(:find_all_by_foo_and_bar).finder.should == :all
51
49
  end
52
50
  end
53
51
 
54
52
  context "find_by" do
55
53
  should "parse one attribute" do
56
- DynamicFinder.new(:find_by_foo).attributes.should == %w(foo)
54
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo).attributes.should == %w(foo)
57
55
  end
58
56
 
59
57
  should "parse multiple attributes" do
60
- DynamicFinder.new(:find_by_foo_and_bar).attributes.should == %w(foo bar)
58
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo_and_bar).attributes.should == %w(foo bar)
61
59
  end
62
60
 
63
61
  should "set finder to :first" do
64
- DynamicFinder.new(:find_by_foo).finder.should == :first
62
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo).finder.should == :first
65
63
  end
66
64
 
67
65
  should "set bang to false" do
68
- DynamicFinder.new(:find_by_foo).bang.should be_false
66
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo).bang.should be_false
69
67
  end
70
68
  end
71
69
 
72
70
  context "find_by with !" do
73
71
  should "parse one attribute" do
74
- DynamicFinder.new(:find_by_foo!).attributes.should == %w(foo)
72
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo!).attributes.should == %w(foo)
75
73
  end
76
74
 
77
75
  should "parse multiple attributes" do
78
- DynamicFinder.new(:find_by_foo_and_bar!).attributes.should == %w(foo bar)
76
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo_and_bar!).attributes.should == %w(foo bar)
79
77
  end
80
78
 
81
79
  should "set finder to :first" do
82
- DynamicFinder.new(:find_by_foo!).finder.should == :first
80
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo!).finder.should == :first
83
81
  end
84
82
 
85
83
  should "set bang to true" do
86
- DynamicFinder.new(:find_by_foo!).bang.should be_true
84
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo!).bang.should be_true
87
85
  end
88
86
  end
89
87
 
90
88
  context "find_or_initialize_by" do
91
89
  should "parse one attribute" do
92
- DynamicFinder.new(:find_or_initialize_by_foo).attributes.should == %w(foo)
90
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_initialize_by_foo).attributes.should == %w(foo)
93
91
  end
94
92
 
95
93
  should "parse multiple attributes" do
96
- DynamicFinder.new(:find_or_initialize_by_foo_and_bar).attributes.should == %w(foo bar)
94
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_initialize_by_foo_and_bar).attributes.should == %w(foo bar)
97
95
  end
98
96
 
99
97
  should "set finder to :first" do
100
- DynamicFinder.new(:find_or_initialize_by_foo).finder.should == :first
98
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_initialize_by_foo).finder.should == :first
101
99
  end
102
100
 
103
101
  should "set instantiator to new" do
104
- DynamicFinder.new(:find_or_initialize_by_foo).instantiator.should == :new
102
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_initialize_by_foo).instantiator.should == :new
105
103
  end
106
104
  end
107
105
 
108
106
  context "find_or_create_by" do
109
107
  should "parse one attribute" do
110
- DynamicFinder.new(:find_or_create_by_foo).attributes.should == %w(foo)
108
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_create_by_foo).attributes.should == %w(foo)
111
109
  end
112
110
 
113
111
  should "parse multiple attributes" do
114
- DynamicFinder.new(:find_or_create_by_foo_and_bar).attributes.should == %w(foo bar)
112
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_create_by_foo_and_bar).attributes.should == %w(foo bar)
115
113
  end
116
114
 
117
115
  should "set finder to :first" do
118
- DynamicFinder.new(:find_or_create_by_foo).finder.should == :first
116
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_create_by_foo).finder.should == :first
119
117
  end
120
118
 
121
119
  should "set instantiator to new" do
122
- DynamicFinder.new(:find_or_create_by_foo).instantiator.should == :create
120
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_create_by_foo).instantiator.should == :create
123
121
  end
124
122
  end
125
123
  end
@@ -1,709 +1,663 @@
1
1
  require 'test_helper'
2
2
 
3
- class Grandparent
4
- include MongoMapper::EmbeddedDocument
5
- key :grandparent, String
6
- end
7
-
8
- class Parent < Grandparent
9
- include MongoMapper::EmbeddedDocument
10
- key :parent, String
11
- end
12
-
13
- class Child < Parent
14
- include MongoMapper::EmbeddedDocument
15
- key :child, String
16
- end
17
-
18
3
  module KeyOverride
19
4
  def other_child
20
- read_attribute(:other_child) || "special result"
5
+ self[:other_child] || "special result"
21
6
  end
22
-
7
+
23
8
  def other_child=(value)
24
9
  super(value + " modified")
25
10
  end
26
11
  end
27
12
 
28
- class OtherChild < Parent
29
- include MongoMapper::EmbeddedDocument
30
- include KeyOverride
31
-
32
- key :other_child, String
33
- end
34
-
35
- class EmbeddedDocumentTest < Test::Unit::TestCase
36
- context "Including MongoMapper::EmbeddedDocument in a class" do
13
+ class EmbeddedDocumentTest < Test::Unit::TestCase
14
+ context "" do
37
15
  setup do
38
- @klass = Class.new do
16
+ class ::Grandparent
39
17
  include MongoMapper::EmbeddedDocument
18
+ key :grandparent, String
40
19
  end
41
- end
42
-
43
- should "give class access to logger" do
44
- @klass.logger.should == MongoMapper.logger
45
- @klass.logger.should be_instance_of(Logger)
46
- end
47
-
48
- should "add _id key" do
49
- @klass.keys['_id'].should_not be_nil
50
- end
51
-
52
- should "know it is using object id" do
53
- @klass.using_object_id?.should be_true
54
- end
55
-
56
- should "know it is not using object id if _id type is changed" do
57
- @klass.key :_id, String
58
- @klass.using_object_id?.should be_false
59
- end
60
-
61
- context "#to_mongo" do
62
- should "be nil if nil" do
63
- @klass.to_mongo(nil).should be_nil
64
- end
65
-
66
- should "convert to_mongo for other values" do
67
- doc = @klass.new(:foo => 'bar')
68
- to_mongo = @klass.to_mongo(doc)
69
- to_mongo.is_a?(Hash).should be_true
70
- to_mongo['foo'].should == 'bar'
71
- end
72
- end
73
-
74
- context "#from_mongo" do
75
- should "be nil if nil" do
76
- @klass.from_mongo(nil).should be_nil
77
- end
78
-
79
- should "be instance if instance of class" do
80
- doc = @klass.new
81
- @klass.from_mongo(doc).should == doc
82
- end
83
-
84
- should "be instance if hash of attributes" do
85
- doc = @klass.from_mongo({:foo => 'bar'})
86
- doc.instance_of?(@klass).should be_true
87
- doc.foo.should == 'bar'
88
- end
89
- end
90
- end
91
-
92
- context "looking up type constants" do
93
- should "not raise an error" do
94
- klass = Class.new do
95
- include MongoMapper::EmbeddedDocument
96
- key :file, Binary
97
- end
98
- end
99
- end
100
-
101
- context "parent_model" do
102
- should "be nil if none of parents ancestors include EmbeddedDocument" do
103
- parent = Class.new
104
- document = Class.new(parent) do
105
- include MongoMapper::EmbeddedDocument
106
- end
107
- document.parent_model.should be_nil
108
- end
109
20
 
110
- should "work when other modules have been included" do
111
- grandparent = Class.new
112
- parent = Class.new grandparent do
21
+ class ::Parent < ::Grandparent
113
22
  include MongoMapper::EmbeddedDocument
23
+ key :parent, String
114
24
  end
115
-
116
- example_module = Module.new
117
- document = Class.new(parent) do
118
- include MongoMapper::EmbeddedDocument
119
- include example_module
120
- end
121
-
122
- document.parent_model.should == parent
123
- end
124
-
125
- should "find parent" do
126
- Parent.parent_model.should == Grandparent
127
- Child.parent_model.should == Parent
128
- end
129
- end
130
-
131
- context "defining a key" do
132
- setup do
133
- @document = Class.new do
25
+
26
+ class ::Child < ::Parent
134
27
  include MongoMapper::EmbeddedDocument
28
+ key :child, String
135
29
  end
136
- end
137
-
138
- should "work with name" do
139
- key = @document.key(:name)
140
- key.name.should == 'name'
141
- end
142
-
143
- should "work with name and type" do
144
- key = @document.key(:name, String)
145
- key.name.should == 'name'
146
- key.type.should == String
147
- end
148
-
149
- should "work with name, type and options" do
150
- key = @document.key(:name, String, :required => true)
151
- key.name.should == 'name'
152
- key.type.should == String
153
- key.options[:required].should be_true
154
- end
155
-
156
- should "work with name and options" do
157
- key = @document.key(:name, :required => true)
158
- key.name.should == 'name'
159
- key.options[:required].should be_true
160
- end
161
-
162
- should "be tracked per document" do
163
- @document.key(:name, String)
164
- @document.key(:age, Integer)
165
- @document.keys['name'].name.should == 'name'
166
- @document.keys['name'].type.should == String
167
- @document.keys['age'].name.should == 'age'
168
- @document.keys['age'].type.should == Integer
169
- end
170
-
171
- should "be redefinable" do
172
- @document.key(:foo, String)
173
- @document.keys['foo'].type.should == String
174
- @document.key(:foo, Integer)
175
- @document.keys['foo'].type.should == Integer
176
- end
177
-
178
- should "create reader method" do
179
- @document.new.should_not respond_to(:foo)
180
- @document.key(:foo, String)
181
- @document.new.should respond_to(:foo)
182
- end
183
-
184
- should "create reader before typecast method" do
185
- @document.new.should_not respond_to(:foo_before_typecast)
186
- @document.key(:foo, String)
187
- @document.new.should respond_to(:foo_before_typecast)
188
- end
189
-
190
- should "create writer method" do
191
- @document.new.should_not respond_to(:foo=)
192
- @document.key(:foo, String)
193
- @document.new.should respond_to(:foo=)
194
- end
195
-
196
- should "create boolean method" do
197
- @document.new.should_not respond_to(:foo?)
198
- @document.key(:foo, String)
199
- @document.new.should respond_to(:foo?)
200
- end
201
- end
202
-
203
- context "keys" do
204
- should "be inherited" do
205
- Grandparent.keys.keys.sort.should == ['_id', 'grandparent']
206
- Parent.keys.keys.sort.should == ['_id', 'grandparent', 'parent']
207
- Child.keys.keys.sort.should == ['_id', 'child', 'grandparent', 'parent']
208
- end
209
-
210
- should "propogate to subclasses if key added after class definition" do
211
- Grandparent.key :_type, String
212
-
213
- Grandparent.keys.keys.sort.should == ['_id', '_type', 'grandparent']
214
- Parent.keys.keys.sort.should == ['_id', '_type', 'grandparent', 'parent']
215
- Child.keys.keys.sort.should == ['_id', '_type', 'child', 'grandparent', 'parent']
216
- end
217
-
218
- should "not add anonymous objects to the ancestor tree" do
219
- OtherChild.ancestors.any? { |a| a.name.blank? }.should be_false
220
- end
221
30
 
222
- should "not include descendant keys" do
223
- lambda { Parent.new.other_child }.should raise_error
224
- end
225
- end
31
+ class ::OtherChild < ::Parent
32
+ include MongoMapper::EmbeddedDocument
33
+ include KeyOverride
226
34
 
227
- context "#inspect" do
228
- setup do
229
- @document = Class.new do
230
- include MongoMapper::Document
231
- key :animals
35
+ key :other_child, String
232
36
  end
233
37
  end
234
38
 
235
- should "call inspect on the document's attributes instead of to_s" do
236
- doc = @document.new
237
- doc.animals = %w(dog cat)
238
- doc.inspect.should include(%(animals: ["dog", "cat"]))
239
- end
240
- end
241
-
242
- context "subclasses" do
243
- should "default to nil" do
244
- Child.subclasses.should be_nil
245
- end
246
-
247
- should "be recorded" do
248
- Grandparent.subclasses.should == [Parent]
249
- Parent.subclasses.should == [Child, OtherChild]
250
- end
251
- end
252
-
253
- context "Applying default values for keys" do
254
- setup do
255
- @document = Class.new do
256
- include MongoMapper::EmbeddedDocument
257
-
258
- key :name, String, :default => 'foo'
259
- key :age, Integer, :default => 20
260
- key :net_worth, Float, :default => 100.00
261
- key :active, Boolean, :default => true
262
- key :smart, Boolean, :default => false
263
- key :skills, Array, :default => [1]
264
- key :options, Hash, :default => {'foo' => 'bar'}
265
- end
266
-
267
- @doc = @document.new
268
- end
269
-
270
- should "work for strings" do
271
- @doc.name.should == 'foo'
272
- end
273
-
274
- should "work for integers" do
275
- @doc.age.should == 20
276
- end
277
-
278
- should "work for floats" do
279
- @doc.net_worth.should == 100.00
39
+ teardown do
40
+ Object.send :remove_const, 'Grandparent' if defined?(::Grandparent)
41
+ Object.send :remove_const, 'Parent' if defined?(::Parent)
42
+ Object.send :remove_const, 'Child' if defined?(::Child)
43
+ Object.send :remove_const, 'OtherChild' if defined?(::OtherChild)
280
44
  end
281
45
 
282
- should "work for booleans" do
283
- @doc.active.should == true
284
- @doc.smart.should == false
285
- end
286
-
287
- should "work for arrays" do
288
- @doc.skills.should == [1]
289
- @doc.skills << 2
290
- @doc.skills.should == [1, 2]
291
- end
292
-
293
- should "work for hashes" do
294
- @doc.options['foo'].should == 'bar'
295
- @doc.options['baz'] = 'wick'
296
- @doc.options['baz'].should == 'wick'
297
- end
298
- end
299
-
300
- context "An instance of an embedded document" do
301
- setup do
302
- @document = Class.new do
303
- include MongoMapper::EmbeddedDocument
46
+ context "Including MongoMapper::EmbeddedDocument in a class" do
47
+ setup do
48
+ @klass = EDoc()
49
+ end
304
50
 
305
- key :name, String
306
- key :age, Integer
51
+ should "add _id key" do
52
+ @klass.keys['_id'].should_not be_nil
307
53
  end
308
- end
309
-
310
- should "have to_param that is string representation of id" do
311
- doc = @document.new
312
- doc.to_param.should == doc.id.to_s
313
- doc.to_param.should be_instance_of(String)
314
- end
315
-
316
- should "have access to class logger" do
317
- doc = @document.new
318
- doc.logger.should == @document.logger
319
- doc.logger.should be_instance_of(Logger)
320
- end
321
-
322
- should "automatically have an _id key" do
323
- @document.keys.keys.should include('_id')
324
- end
325
-
326
- should "have id method returns _id" do
327
- id = Mongo::ObjectID.new
328
- doc = @document.new(:_id => id)
329
- doc.id.should == id
330
- end
331
-
332
- context "assigning id with _id ObjectId type" do
333
- should "not set custom id flag" do
334
- doc = @document.new
335
- doc.using_custom_id?.should be_false
336
- doc.id = Mongo::ObjectID.new
337
- doc.using_custom_id?.should be_false
54
+
55
+ should "know it is using object id" do
56
+ @klass.using_object_id?.should be_true
338
57
  end
339
-
340
- should "convert string object id to mongo object id" do
341
- id = Mongo::ObjectID.new
342
- doc = @document.new(:id => id.to_s)
343
- doc._id.should == id
344
- doc.id.should == id
345
- doc.using_custom_id?.should be_false
58
+
59
+ should "know it is not using object id if _id type is changed" do
60
+ @klass.key :_id, String
61
+ @klass.using_object_id?.should be_false
346
62
  end
347
63
  end
348
64
 
349
- context "setting custom id" do
350
- should "set _id" do
351
- @document.key :_id, String
352
- doc = @document.new(:id => '1234')
353
- doc._id.should == '1234'
65
+ context "Class Methods" do
66
+ should "include logger" do
67
+ @klass = EDoc()
68
+ @klass.logger.should == MongoMapper.logger
69
+ @klass.logger.should be_instance_of(Logger)
354
70
  end
355
-
356
- should "know that custom id is set" do
357
- @document.key :_id, String
358
- doc = @document.new
359
- doc.using_custom_id?.should be_false
360
- doc.id = '1234'
361
- doc.using_custom_id?.should be_true
71
+
72
+ should "return false for embeddable" do
73
+ EDoc().embeddable?.should be_true
362
74
  end
363
- end
364
75
 
365
- should "have a nil _root_document" do
366
- @document.new._root_document.should be_nil
367
- end
76
+ context "#to_mongo" do
77
+ setup { @klass = EDoc() }
368
78
 
369
- context "being initialized" do
370
- should "accept a hash that sets keys and values" do
371
- doc = @document.new(:name => 'John', :age => 23)
372
- doc.attributes.keys.sort.should == ['_id', 'age', 'name']
373
- doc.attributes['name'].should == 'John'
374
- doc.attributes['age'].should == 23
375
- end
376
-
377
- should "be able to assign keys dynamically" do
378
- doc = @document.new(:name => 'John', :skills => ['ruby', 'rails'])
379
- doc.name.should == 'John'
380
- doc.skills.should == ['ruby', 'rails']
79
+ should "be nil if nil" do
80
+ @klass.to_mongo(nil).should be_nil
81
+ end
82
+
83
+ should "convert to_mongo for other values" do
84
+ doc = @klass.new(:foo => 'bar')
85
+ to_mongo = @klass.to_mongo(doc)
86
+ to_mongo.is_a?(Hash).should be_true
87
+ to_mongo['foo'].should == 'bar'
88
+ end
381
89
  end
382
90
 
383
- should "set the root on embedded documents" do
384
- document = Class.new(@document) do
385
- many :children
91
+ context "#from_mongo" do
92
+ setup { @klass = EDoc() }
93
+
94
+ should "be nil if nil" do
95
+ @klass.from_mongo(nil).should be_nil
386
96
  end
387
97
 
388
- doc = document.new :_root_document => 'document', 'children' => [{}]
389
- doc.children.first._root_document.should == 'document'
390
- end
98
+ should "be instance if instance of class" do
99
+ doc = @klass.new
100
+ @klass.from_mongo(doc).should == doc
101
+ end
391
102
 
392
- should "not throw error if initialized with nil" do
393
- lambda {
394
- @document.new(nil)
395
- }.should_not raise_error
396
- end
397
- end
398
-
399
- context "initialized when _type key present" do
400
- setup do
401
- ::FooBar = Class.new do
402
- include MongoMapper::EmbeddedDocument
403
- key :_type, String
103
+ should "be instance if hash of attributes" do
104
+ doc = @klass.from_mongo({:foo => 'bar'})
105
+ doc.instance_of?(@klass).should be_true
106
+ doc.foo.should == 'bar'
404
107
  end
405
108
  end
406
-
407
- teardown do
408
- Object.send(:remove_const, :FooBar)
409
- end
410
109
 
411
- should "set _type to class name" do
412
- FooBar.new._type.should == 'FooBar'
413
- end
414
-
415
- should "not change _type if already set" do
416
- FooBar.new(:_type => 'Foo')._type.should == 'Foo'
417
- end
418
- end
110
+ context "defining a key" do
111
+ setup do
112
+ @document = EDoc()
113
+ end
419
114
 
420
- context "mass assigning keys" do
421
- should "update values for keys provided" do
422
- doc = @document.new(:name => 'foobar', :age => 10)
423
- doc.attributes = {:name => 'new value', :age => 5}
424
- doc.attributes[:name].should == 'new value'
425
- doc.attributes[:age].should == 5
426
- end
115
+ should "work with name" do
116
+ key = @document.key(:name)
117
+ key.name.should == 'name'
118
+ end
119
+
120
+ should "work with name and type" do
121
+ key = @document.key(:name, String)
122
+ key.name.should == 'name'
123
+ key.type.should == String
124
+ end
125
+
126
+ should "work with name, type and options" do
127
+ key = @document.key(:name, String, :required => true)
128
+ key.name.should == 'name'
129
+ key.type.should == String
130
+ key.options[:required].should be_true
131
+ end
132
+
133
+ should "work with name and options" do
134
+ key = @document.key(:name, :required => true)
135
+ key.name.should == 'name'
136
+ key.options[:required].should be_true
137
+ end
138
+
139
+ should "be tracked per document" do
140
+ @document.key(:name, String)
141
+ @document.key(:age, Integer)
142
+ @document.keys['name'].name.should == 'name'
143
+ @document.keys['name'].type.should == String
144
+ @document.keys['age'].name.should == 'age'
145
+ @document.keys['age'].type.should == Integer
146
+ end
147
+
148
+ should "be redefinable" do
149
+ @document.key(:foo, String)
150
+ @document.keys['foo'].type.should == String
151
+ @document.key(:foo, Integer)
152
+ @document.keys['foo'].type.should == Integer
153
+ end
154
+
155
+ should "create reader method" do
156
+ @document.new.should_not respond_to(:foo)
157
+ @document.key(:foo, String)
158
+ @document.new.should respond_to(:foo)
159
+ end
160
+
161
+ should "create reader before typecast method" do
162
+ @document.new.should_not respond_to(:foo_before_typecast)
163
+ @document.key(:foo, String)
164
+ @document.new.should respond_to(:foo_before_typecast)
165
+ end
427
166
 
428
- should "not update values for keys that were not provided" do
429
- doc = @document.new(:name => 'foobar', :age => 10)
430
- doc.attributes = {:name => 'new value'}
431
- doc.attributes[:name].should == 'new value'
432
- doc.attributes[:age].should == 10
167
+ should "create writer method" do
168
+ @document.new.should_not respond_to(:foo=)
169
+ @document.key(:foo, String)
170
+ @document.new.should respond_to(:foo=)
171
+ end
172
+
173
+ should "create boolean method" do
174
+ @document.new.should_not respond_to(:foo?)
175
+ @document.key(:foo, String)
176
+ @document.new.should respond_to(:foo?)
177
+ end
433
178
  end
434
179
 
435
- should "not ignore keys that have methods defined" do
436
- @document.class_eval do
437
- attr_writer :password
180
+ context "keys" do
181
+ should "be inherited" do
182
+ Grandparent.keys.keys.sort.should == ['_id', 'grandparent']
183
+ Parent.keys.keys.sort.should == ['_id', 'grandparent', 'parent']
184
+ Child.keys.keys.sort.should == ['_id', 'child', 'grandparent', 'parent']
185
+ end
438
186
 
439
- def passwd
440
- @password
441
- end
187
+ should "propogate to descendants if key added after class definition" do
188
+ Grandparent.key :_type, String
189
+
190
+ Grandparent.keys.keys.sort.should == ['_id', '_type', 'grandparent']
191
+ Parent.keys.keys.sort.should == ['_id', '_type', 'grandparent', 'parent']
192
+ Child.keys.keys.sort.should == ['_id', '_type', 'child', 'grandparent', 'parent']
193
+ end
194
+
195
+ should "not add anonymous objects to the ancestor tree" do
196
+ OtherChild.ancestors.any? { |a| a.name.blank? }.should be_false
442
197
  end
443
198
 
444
- doc = @document.new(:name => 'foobar', :password => 'secret')
445
- doc.passwd.should == 'secret'
199
+ should "not include descendant keys" do
200
+ lambda { Parent.new.other_child }.should raise_error
201
+ end
446
202
  end
447
203
 
448
- should "typecast key values" do
449
- doc = @document.new(:name => 1234, :age => '21')
450
- doc.name.should == '1234'
451
- doc.age.should == 21
204
+ context "descendants" do
205
+ should "default to nil" do
206
+ Child.descendants.should be_nil
207
+ end
208
+
209
+ should "be recorded" do
210
+ Grandparent.descendants.should == [Parent]
211
+ Parent.descendants.should == [Child, OtherChild]
212
+ end
452
213
  end
453
214
  end
454
215
 
455
- context "attributes" do
456
- should "default to hash with all keys" do
457
- doc = @document.new
458
- doc.attributes.keys.sort.should == ['_id', 'age', 'name']
216
+ context "An instance of an embedded document" do
217
+ setup do
218
+ @document = EDoc do
219
+ key :name, String
220
+ key :age, Integer
221
+ end
459
222
  end
460
223
 
461
- should "return all keys with values" do
462
- doc = @document.new(:name => 'string', :age => nil)
463
- doc.attributes.keys.sort.should == ['_id', 'age', 'name']
464
- doc.attributes.values.should include('string')
465
- doc.attributes.values.should include(nil)
224
+ should "have to_param that is string representation of id" do
225
+ doc = @document.new
226
+ doc.to_param.should == doc.id.to_s
227
+ doc.to_param.should be_instance_of(String)
466
228
  end
467
- end
468
-
469
- context "to_mongo" do
470
- should "default to hash with _id key" do
229
+
230
+ should "have access to class logger" do
471
231
  doc = @document.new
472
- doc.to_mongo.keys.should == ['_id']
232
+ doc.logger.should == @document.logger
233
+ doc.logger.should be_instance_of(Logger)
473
234
  end
474
-
475
- should "return all keys with non nil values" do
476
- doc = @document.new(:name => 'string', :age => nil)
477
- doc.to_mongo.keys.sort.should == ['_id', 'name']
478
- doc.to_mongo.values.should include('string')
479
- doc.to_mongo.values.should_not include(nil)
235
+
236
+ should "automatically have an _id key" do
237
+ @document.keys.keys.should include('_id')
480
238
  end
481
- end
482
-
483
- should "convert dates into times" do
484
- document = Class.new(@document) do
485
- key :start_date, Date
239
+
240
+ should "create id during initialization" do
241
+ @document.new._id.should be_instance_of(Mongo::ObjectID)
486
242
  end
487
- doc = document.new :start_date => "12/05/2009"
488
- doc.start_date.should == Date.new(2009, 12, 05)
489
- end
490
243
 
491
- context "clone" do
492
- should "regenerate the id" do
493
- doc = @document.new(:name => "foo", :age => 27)
494
- doc_id = doc.id
495
- clone = doc.clone
496
- clone_id = clone.id
497
- clone_id.should_not == doc_id
244
+ should "have id method returns _id" do
245
+ id = Mongo::ObjectID.new
246
+ doc = @document.new(:_id => id)
247
+ doc.id.should == id
498
248
  end
499
249
 
500
- should "copy the attributes" do
501
- doc = @document.new(:name => "foo", :age => 27)
502
- clone = doc.clone
503
- clone.name.should == "foo"
504
- clone.age.should == 27
250
+ should "convert string object id to mongo object id when assigning id with _id object id type" do
251
+ id = Mongo::ObjectID.new
252
+
253
+ doc = @document.new(:id => id.to_s)
254
+ doc._id.should == id
255
+ doc.id.should == id
256
+
257
+ doc = @document.new(:_id => id.to_s)
258
+ doc._id.should == id
259
+ doc.id.should == id
505
260
  end
506
- end
507
-
508
- context "key shorcut access" do
509
- context "[]" do
510
- should "work when key found" do
511
- doc = @document.new(:name => 'string')
512
- doc[:name].should == 'string'
261
+
262
+ context "_root_document" do
263
+ should "default to nil" do
264
+ @document.new._root_document.should be_nil
513
265
  end
514
-
515
- should "raise exception when key not found" do
516
- doc = @document.new(:name => 'string')
517
- lambda {
518
- doc[:not_here]
519
- }.should raise_error(MongoMapper::KeyNotFound)
266
+
267
+ should "allow setting when initialized" do
268
+ root = Doc().new
269
+ doc = @document.new :_root_document => root
270
+
271
+ doc._root_document.should be(root)
272
+ end
273
+
274
+ should "also be set on many embedded documents" do
275
+ root = Doc().new
276
+ klass = EDoc { many :children }
277
+ doc = klass.new(:_root_document => root, :children => [{}])
278
+
279
+ doc.children.first._root_document.should == root
520
280
  end
521
281
  end
522
-
523
- context "[]=" do
524
- should "write key value for existing key" do
525
- doc = @document.new
526
- doc[:name] = 'string'
527
- doc[:name].should == 'string'
282
+
283
+ context "being initialized" do
284
+ should "accept a hash that sets keys and values" do
285
+ doc = @document.new(:name => 'John', :age => 23)
286
+ doc.attributes.keys.sort.should == ['_id', 'age', 'name']
287
+ doc.attributes['name'].should == 'John'
288
+ doc.attributes['age'].should == 23
528
289
  end
529
-
530
- should "create key and write value for missing key" do
531
- doc = @document.new
532
- doc[:foo] = 'string'
533
- doc.metaclass.keys.include?('foo').should be_true
534
- doc[:foo].should == 'string'
290
+
291
+ should "be able to assign keys dynamically" do
292
+ doc = @document.new(:name => 'John', :skills => ['ruby', 'rails'])
293
+ doc.name.should == 'John'
294
+ doc.skills.should == ['ruby', 'rails']
535
295
  end
536
296
 
537
- should "not share the new key" do
538
- doc = @document.new
539
- doc[:foo] = 'string'
540
- @document.keys.should_not include('foo')
541
- end
542
- end
543
- end
544
-
545
- context "indifferent access" do
546
- should "be enabled for keys" do
547
- doc = @document.new(:name => 'string')
548
- doc.attributes[:name].should == 'string'
549
- doc.attributes['name'].should == 'string'
297
+ should "not throw error if initialized with nil" do
298
+ assert_nothing_raised { @document.new(nil) }
299
+ end
550
300
  end
551
- end
552
301
 
553
- context "reading an attribute" do
554
- should "work for defined keys" do
555
- doc = @document.new(:name => 'string')
556
- doc.name.should == 'string'
557
- end
302
+ context "initialized when _type key present" do
303
+ setup do
304
+ @klass = EDoc('FooBar') { key :_type, String }
305
+ end
558
306
 
559
- should "raise no method error for undefined keys" do
560
- doc = @document.new
561
- lambda { doc.fart }.should raise_error(NoMethodError)
307
+ should "set _type to class name" do
308
+ @klass.new._type.should == 'FooBar'
309
+ end
310
+
311
+ should "not change _type if already set" do
312
+ @klass.new(:_type => 'Foo')._type.should == 'Foo'
313
+ end
562
314
  end
563
315
 
564
- should "be accessible for use in the model" do
565
- @document.class_eval do
566
- def name_and_age
567
- "#{read_attribute(:name)} (#{read_attribute(:age)})"
316
+ context "attributes=" do
317
+ should "update values for keys provided" do
318
+ doc = @document.new(:name => 'foobar', :age => 10)
319
+ doc.attributes = {:name => 'new value', :age => 5}
320
+ doc.attributes[:name].should == 'new value'
321
+ doc.attributes[:age].should == 5
322
+ end
323
+
324
+ should "not update values for keys that were not provided" do
325
+ doc = @document.new(:name => 'foobar', :age => 10)
326
+ doc.attributes = {:name => 'new value'}
327
+ doc.attributes[:name].should == 'new value'
328
+ doc.attributes[:age].should == 10
329
+ end
330
+
331
+ should "work with pre-defined methods" do
332
+ @document.class_eval do
333
+ attr_writer :password
334
+
335
+ def passwd
336
+ @password
337
+ end
568
338
  end
339
+
340
+ doc = @document.new(:name => 'foobar', :password => 'secret')
341
+ doc.passwd.should == 'secret'
569
342
  end
570
343
 
571
- doc = @document.new(:name => 'John', :age => 27)
572
- doc.name_and_age.should == 'John (27)'
344
+ should "typecast key values" do
345
+ doc = @document.new(:name => 1234, :age => '21')
346
+ doc.name.should == '1234'
347
+ doc.age.should == 21
348
+ end
573
349
  end
574
-
575
- should "set instance variable" do
576
- @document.key :foo, Array
577
- doc = @document.new
578
- doc.instance_variable_get("@foo").should be_nil
579
- doc.foo
580
- doc.instance_variable_get("@foo").should == []
581
- end
582
-
583
- should "be overrideable by modules" do
584
- @document = Class.new do
585
- include MongoMapper::Document
586
- key :other_child, String
587
- end
588
-
589
- child = @document.new
590
- child.other_child.should be_nil
591
-
592
- @document.send :include, KeyOverride
593
-
594
- overriden_child = @document.new
595
- overriden_child.other_child.should == 'special result'
350
+
351
+ context "attributes" do
352
+ should "default to hash with all keys" do
353
+ doc = @document.new
354
+ doc.attributes.keys.sort.should == ['_id', 'age', 'name']
355
+ end
356
+
357
+ should "return all keys with values" do
358
+ doc = @document.new(:name => 'string', :age => nil)
359
+ doc.attributes.keys.sort.should == ['_id', 'age', 'name']
360
+ doc.attributes.values.should include('string')
361
+ doc.attributes.values.should include(nil)
362
+ end
363
+
364
+ should "have indifferent access" do
365
+ doc = @document.new(:name => 'string')
366
+ doc.attributes[:name].should == 'string'
367
+ doc.attributes['name'].should == 'string'
368
+ end
596
369
  end
597
- end
598
370
 
599
- context "reading an attribute before typcasting" do
600
- should "work for defined keys" do
601
- doc = @document.new(:name => 12)
602
- doc.name_before_typecast.should == 12
371
+ context "to_mongo" do
372
+ should "default to hash with _id key" do
373
+ doc = @document.new
374
+ doc.to_mongo.keys.sort.should == ['_id', 'age', 'name']
375
+ end
376
+
377
+ should "return all keys" do
378
+ doc = @document.new(:name => 'string', :age => nil)
379
+ doc.to_mongo.keys.sort.should == ['_id', 'age', 'name']
380
+ doc.to_mongo.values.should include('string')
381
+ doc.to_mongo.values.should include(nil)
382
+ end
603
383
  end
604
384
 
605
- should "raise no method error for undefined keys" do
606
- doc = @document.new
607
- lambda { doc.foo_before_typecast }.should raise_error(NoMethodError)
385
+ context "clone" do
386
+ should "regenerate the id" do
387
+ doc = @document.new(:name => "foo", :age => 27)
388
+ doc_id = doc.id
389
+ clone = doc.clone
390
+ clone_id = clone.id
391
+ clone_id.should_not == doc_id
392
+ end
393
+
394
+ should "copy the attributes" do
395
+ doc = @document.new(:name => "foo", :age => 27)
396
+ clone = doc.clone
397
+ clone.name.should == "foo"
398
+ clone.age.should == 27
399
+ end
608
400
  end
609
401
 
610
- should "be accessible for use in a document" do
611
- @document.class_eval do
612
- def untypcasted_name
613
- read_attribute_before_typecast(:name)
402
+ context "key shorcut access" do
403
+ context "[]" do
404
+ should "work when key found" do
405
+ doc = @document.new(:name => 'string')
406
+ doc[:name].should == 'string'
407
+ end
408
+
409
+ should "raise exception when key not found" do
410
+ doc = @document.new(:name => 'string')
411
+ assert_raises(MongoMapper::KeyNotFound) { doc[:not_here] }
614
412
  end
615
413
  end
616
414
 
617
- doc = @document.new(:name => 12)
618
- doc.name.should == '12'
619
- doc.untypcasted_name.should == 12
620
- end
621
- end
415
+ context "[]=" do
416
+ should "write key value for existing key" do
417
+ doc = @document.new
418
+ doc[:name] = 'string'
419
+ doc[:name].should == 'string'
420
+ end
622
421
 
623
- context "writing an attribute" do
624
- should "work for defined keys" do
625
- doc = @document.new
626
- doc.name = 'John'
627
- doc.name.should == 'John'
628
- end
422
+ should "create key and write value for missing key" do
423
+ doc = @document.new
424
+ doc[:foo] = 'string'
425
+ doc.class.keys.include?('foo').should be_true
426
+ doc[:foo].should == 'string'
427
+ end
629
428
 
630
- should "raise no method error for undefined keys" do
631
- doc = @document.new
632
- lambda { doc.fart = 'poof!' }.should raise_error(NoMethodError)
429
+ should "share the new key with the class" do
430
+ doc = @document.new
431
+ doc[:foo] = 'string'
432
+ @document.keys.should include('foo')
433
+ end
434
+ end
633
435
  end
634
436
 
635
- should "typecast value" do
636
- doc = @document.new
637
- doc.name = 1234
638
- doc.name.should == '1234'
639
- doc.age = '21'
640
- doc.age.should == 21
641
- end
642
-
643
- should "be accessible for use in the model" do
644
- @document.class_eval do
645
- def name_and_age=(new_value)
646
- new_value.match(/([^\(\s]+) \((.*)\)/)
647
- write_attribute :name, $1
648
- write_attribute :age, $2
437
+ context "reading a key" do
438
+ should "work for defined keys" do
439
+ doc = @document.new(:name => 'string')
440
+ doc.name.should == 'string'
441
+ end
442
+
443
+ should "raise no method error for undefined keys" do
444
+ doc = @document.new
445
+ lambda { doc.fart }.should raise_error(NoMethodError)
446
+ end
447
+
448
+ should "be accessible for use in the model" do
449
+ @document.class_eval do
450
+ def name_and_age
451
+ "#{self[:name]} (#{self[:age]})"
452
+ end
649
453
  end
454
+
455
+ doc = @document.new(:name => 'John', :age => 27)
456
+ doc.name_and_age.should == 'John (27)'
650
457
  end
651
458
 
652
- doc = @document.new
653
- doc.name_and_age = 'Frank (62)'
654
- doc.name.should == 'Frank'
655
- doc.age.should == 62
656
- end
657
-
658
- should "be overrideable by modules" do
659
- @document = Class.new do
660
- include MongoMapper::Document
661
- key :other_child, String
662
- end
663
-
664
- child = @document.new(:other_child => 'foo')
665
- child.other_child.should == 'foo'
666
-
667
- @document.send :include, KeyOverride
668
-
669
- overriden_child = @document.new(:other_child => 'foo')
670
- overriden_child.other_child.should == 'foo modified'
671
- end
672
- end # writing an attribute
673
-
674
- context "checking if an attributes value is present" do
675
- should "work for defined keys" do
676
- doc = @document.new
677
- doc.name?.should be_false
678
- doc.name = 'John'
679
- doc.name?.should be_true
459
+ should "set instance variable" do
460
+ @document.key :foo, Array
461
+ doc = @document.new
462
+ doc.instance_variable_get("@foo").should be_nil
463
+ doc.foo
464
+ doc.instance_variable_get("@foo").should == []
465
+ end
466
+
467
+ should "be overrideable by modules" do
468
+ @document = Doc do
469
+ key :other_child, String
470
+ end
471
+
472
+ child = @document.new
473
+ child.other_child.should be_nil
474
+
475
+ @document.send :include, KeyOverride
476
+
477
+ overriden_child = @document.new
478
+ overriden_child.other_child.should == 'special result'
479
+ end
680
480
  end
681
-
682
- should "raise no method error for undefined keys" do
683
- doc = @document.new
684
- lambda { doc.fart? }.should raise_error(NoMethodError)
481
+
482
+ context "reading a key before typcasting" do
483
+ should "work for defined keys" do
484
+ doc = @document.new(:name => 12)
485
+ doc.name_before_typecast.should == 12
486
+ end
487
+
488
+ should "raise no method error for undefined keys" do
489
+ doc = @document.new
490
+ lambda { doc.foo_before_typecast }.should raise_error(NoMethodError)
491
+ end
492
+
493
+ should "be accessible for use in a document" do
494
+ @document.class_eval do
495
+ def untypcasted_name
496
+ read_key_before_typecast(:name)
497
+ end
498
+ end
499
+
500
+ doc = @document.new(:name => 12)
501
+ doc.name.should == '12'
502
+ doc.untypcasted_name.should == 12
503
+ end
685
504
  end
686
- end
687
-
688
- context "equality" do
689
- setup do
690
- @oid = Mongo::ObjectID.new
505
+
506
+ context "writing a key" do
507
+ should "work for defined keys" do
508
+ doc = @document.new
509
+ doc.name = 'John'
510
+ doc.name.should == 'John'
511
+ end
512
+
513
+ should "raise no method error for undefined keys" do
514
+ doc = @document.new
515
+ lambda { doc.fart = 'poof!' }.should raise_error(NoMethodError)
516
+ end
517
+
518
+ should "typecast value" do
519
+ doc = @document.new
520
+ doc.name = 1234
521
+ doc.name.should == '1234'
522
+ doc.age = '21'
523
+ doc.age.should == 21
524
+ end
525
+
526
+ should "be accessible for use in the model" do
527
+ @document.class_eval do
528
+ def name_and_age=(new_value)
529
+ new_value.match(/([^\(\s]+) \((.*)\)/)
530
+ write_key :name, $1
531
+ write_key :age, $2
532
+ end
533
+ end
534
+
535
+ doc = @document.new
536
+ doc.name_and_age = 'Frank (62)'
537
+ doc.name.should == 'Frank'
538
+ doc.age.should == 62
539
+ end
540
+
541
+ should "be overrideable by modules" do
542
+ @document = Doc do
543
+ key :other_child, String
544
+ end
545
+
546
+ child = @document.new(:other_child => 'foo')
547
+ child.other_child.should == 'foo'
548
+
549
+ @document.send :include, KeyOverride
550
+
551
+ overriden_child = @document.new(:other_child => 'foo')
552
+ overriden_child.other_child.should == 'foo modified'
553
+ end
554
+ end # writing a key
555
+
556
+ context "checking if a keys value is present" do
557
+ should "work for defined keys" do
558
+ doc = @document.new
559
+ doc.name?.should be_false
560
+ doc.name = 'John'
561
+ doc.name?.should be_true
562
+ end
563
+
564
+ should "raise no method error for undefined keys" do
565
+ doc = @document.new
566
+ lambda { doc.fart? }.should raise_error(NoMethodError)
567
+ end
691
568
  end
692
- should "be equal if id and class are the same" do
693
- (@document.new('_id' => @oid) == @document.new('_id' => @oid)).should be(true)
569
+
570
+ should "call inspect on the document's attributes instead of to_s when inspecting the document" do
571
+ doc = @document.new(:animals => %w(dog cat))
572
+ doc.inspect.should include(%(animals: ["dog", "cat"]))
694
573
  end
695
574
 
696
- should "not be equal if class same but id different" do
697
- (@document.new('_id' => @oid) == @document.new('_id' => Mongo::ObjectID.new)).should be(false)
575
+ context "equality" do
576
+ setup do
577
+ @oid = Mongo::ObjectID.new
578
+ end
579
+
580
+ should "delegate hash to _id" do
581
+ doc = @document.new
582
+ doc.hash.should == doc._id.hash
583
+ end
584
+
585
+ should "delegate eql to ==" do
586
+ doc = @document.new
587
+ other = @document.new
588
+ doc.eql?(other).should == (doc == other)
589
+ doc.eql?(doc).should == (doc == doc)
590
+ end
591
+
592
+ should "know if same object as another" do
593
+ doc = @document.new
594
+ doc.should equal(doc)
595
+ doc.should_not equal(@document.new)
596
+ end
597
+
598
+ should "allow set operations on array of documents" do
599
+ doc = @document.new
600
+ ([doc] & [doc]).should == [doc]
601
+ end
602
+
603
+ should "be equal if id and class are the same" do
604
+ (@document.new('_id' => @oid) == @document.new('_id' => @oid)).should be_true
605
+ end
606
+
607
+ should "not be equal if class same but id different" do
608
+ (@document.new('_id' => @oid) == @document.new('_id' => Mongo::ObjectID.new)).should be_false
609
+ end
610
+
611
+ should "not be equal if id same but class different" do
612
+ another_document = Doc()
613
+ (@document.new('_id' => @oid) == another_document.new('_id' => @oid)).should be_false
614
+ end
698
615
  end
699
616
 
700
- should "not be equal if id same but class different" do
701
- @another_document = Class.new do
702
- include MongoMapper::Document
617
+ context "reading keys with default values" do
618
+ setup do
619
+ @document = EDoc do
620
+ key :name, String, :default => 'foo'
621
+ key :age, Integer, :default => 20
622
+ key :net_worth, Float, :default => 100.00
623
+ key :active, Boolean, :default => true
624
+ key :smart, Boolean, :default => false
625
+ key :skills, Array, :default => [1]
626
+ key :options, Hash, :default => {'foo' => 'bar'}
627
+ end
628
+
629
+ @doc = @document.new
703
630
  end
704
631
 
705
- (@document.new('_id' => @oid) == @another_document.new('_id' => @oid)).should be(false)
632
+ should "work for strings" do
633
+ @doc.name.should == 'foo'
634
+ end
635
+
636
+ should "work for integers" do
637
+ @doc.age.should == 20
638
+ end
639
+
640
+ should "work for floats" do
641
+ @doc.net_worth.should == 100.00
642
+ end
643
+
644
+ should "work for booleans" do
645
+ @doc.active.should == true
646
+ @doc.smart.should == false
647
+ end
648
+
649
+ should "work for arrays" do
650
+ @doc.skills.should == [1]
651
+ @doc.skills << 2
652
+ @doc.skills.should == [1, 2]
653
+ end
654
+
655
+ should "work for hashes" do
656
+ @doc.options['foo'].should == 'bar'
657
+ @doc.options['baz'] = 'wick'
658
+ @doc.options['baz'].should == 'wick'
659
+ end
706
660
  end
707
- end
708
- end # instance of a embedded document
661
+ end # instance of a embedded document
662
+ end
709
663
  end