mongo_mapper-unstable 2010.1.27 → 2010.1.28
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.
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/mongo_mapper/document.rb +17 -12
- data/lib/mongo_mapper/embedded_document.rb +12 -5
- data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +1 -0
- data/lib/mongo_mapper/plugins/keys.rb +9 -1
- data/lib/mongo_mapper/plugins/protected.rb +41 -0
- data/lib/mongo_mapper/support.rb +2 -1
- data/lib/mongo_mapper.rb +2 -1
- data/test/functional/associations/test_many_embedded_proxy.rb +38 -0
- data/test/functional/test_document.rb +91 -73
- data/test/functional/test_protected.rb +139 -0
- data/test/test_helper.rb +11 -17
- data/test/unit/test_embedded_document.rb +544 -533
- data/test/unit/test_support.rb +5 -1
- data/test/unit/test_validations.rb +55 -3
- metadata +6 -3
@@ -1,652 +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
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
13
|
class EmbeddedDocumentTest < Test::Unit::TestCase
|
36
|
-
context "
|
14
|
+
context "" do
|
37
15
|
setup do
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
should "add _id key" do
|
42
|
-
@klass.keys['_id'].should_not be_nil
|
43
|
-
end
|
44
|
-
|
45
|
-
should "know it is using object id" do
|
46
|
-
@klass.using_object_id?.should be_true
|
47
|
-
end
|
48
|
-
|
49
|
-
should "know it is not using object id if _id type is changed" do
|
50
|
-
@klass.key :_id, String
|
51
|
-
@klass.using_object_id?.should be_false
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
context "Class Methods" do
|
56
|
-
should "include logger" do
|
57
|
-
@klass = EDoc()
|
58
|
-
@klass.logger.should == MongoMapper.logger
|
59
|
-
@klass.logger.should be_instance_of(Logger)
|
60
|
-
end
|
61
|
-
|
62
|
-
should "return false for embeddable" do
|
63
|
-
EDoc().embeddable?.should be_true
|
64
|
-
end
|
65
|
-
|
66
|
-
context "#to_mongo" do
|
67
|
-
setup { @klass = EDoc() }
|
68
|
-
|
69
|
-
should "be nil if nil" do
|
70
|
-
@klass.to_mongo(nil).should be_nil
|
71
|
-
end
|
72
|
-
|
73
|
-
should "convert to_mongo for other values" do
|
74
|
-
doc = @klass.new(:foo => 'bar')
|
75
|
-
to_mongo = @klass.to_mongo(doc)
|
76
|
-
to_mongo.is_a?(Hash).should be_true
|
77
|
-
to_mongo['foo'].should == 'bar'
|
16
|
+
class ::Grandparent
|
17
|
+
include MongoMapper::EmbeddedDocument
|
18
|
+
key :grandparent, String
|
78
19
|
end
|
79
|
-
end
|
80
|
-
|
81
|
-
context "#from_mongo" do
|
82
|
-
setup { @klass = EDoc() }
|
83
|
-
|
84
|
-
should "be nil if nil" do
|
85
|
-
@klass.from_mongo(nil).should be_nil
|
86
|
-
end
|
87
|
-
|
88
|
-
should "be instance if instance of class" do
|
89
|
-
doc = @klass.new
|
90
|
-
@klass.from_mongo(doc).should == doc
|
91
|
-
end
|
92
|
-
|
93
|
-
should "be instance if hash of attributes" do
|
94
|
-
doc = @klass.from_mongo({:foo => 'bar'})
|
95
|
-
doc.instance_of?(@klass).should be_true
|
96
|
-
doc.foo.should == 'bar'
|
97
|
-
end
|
98
|
-
end
|
99
20
|
|
100
|
-
|
101
|
-
|
102
|
-
|
21
|
+
class ::Parent < ::Grandparent
|
22
|
+
include MongoMapper::EmbeddedDocument
|
23
|
+
key :parent, String
|
103
24
|
end
|
104
25
|
|
105
|
-
|
106
|
-
|
107
|
-
key
|
26
|
+
class ::Child < ::Parent
|
27
|
+
include MongoMapper::EmbeddedDocument
|
28
|
+
key :child, String
|
108
29
|
end
|
109
30
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
key.type.should == String
|
114
|
-
end
|
31
|
+
class ::OtherChild < ::Parent
|
32
|
+
include MongoMapper::EmbeddedDocument
|
33
|
+
include KeyOverride
|
115
34
|
|
116
|
-
|
117
|
-
key = @document.key(:name, String, :required => true)
|
118
|
-
key.name.should == 'name'
|
119
|
-
key.type.should == String
|
120
|
-
key.options[:required].should be_true
|
35
|
+
key :other_child, String
|
121
36
|
end
|
37
|
+
end
|
122
38
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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)
|
44
|
+
end
|
45
|
+
|
46
|
+
context "Including MongoMapper::EmbeddedDocument in a class" do
|
47
|
+
setup do
|
48
|
+
@klass = EDoc()
|
127
49
|
end
|
128
50
|
|
129
|
-
should "
|
130
|
-
@
|
131
|
-
@document.key(:age, Integer)
|
132
|
-
@document.keys['name'].name.should == 'name'
|
133
|
-
@document.keys['name'].type.should == String
|
134
|
-
@document.keys['age'].name.should == 'age'
|
135
|
-
@document.keys['age'].type.should == Integer
|
51
|
+
should "add _id key" do
|
52
|
+
@klass.keys['_id'].should_not be_nil
|
136
53
|
end
|
137
54
|
|
138
|
-
should "
|
139
|
-
@
|
140
|
-
@document.keys['foo'].type.should == String
|
141
|
-
@document.key(:foo, Integer)
|
142
|
-
@document.keys['foo'].type.should == Integer
|
55
|
+
should "know it is using object id" do
|
56
|
+
@klass.using_object_id?.should be_true
|
143
57
|
end
|
144
58
|
|
145
|
-
should "
|
146
|
-
@
|
147
|
-
@
|
148
|
-
@document.new.should respond_to(:foo)
|
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
|
149
62
|
end
|
63
|
+
end
|
150
64
|
|
151
|
-
|
152
|
-
|
153
|
-
@
|
154
|
-
@
|
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)
|
155
70
|
end
|
156
71
|
|
157
|
-
should "
|
158
|
-
|
159
|
-
@document.key(:foo, String)
|
160
|
-
@document.new.should respond_to(:foo=)
|
72
|
+
should "return false for embeddable" do
|
73
|
+
EDoc().embeddable?.should be_true
|
161
74
|
end
|
162
75
|
|
163
|
-
|
164
|
-
@
|
165
|
-
@document.key(:foo, String)
|
166
|
-
@document.new.should respond_to(:foo?)
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
context "keys" do
|
171
|
-
should "be inherited" do
|
172
|
-
Grandparent.keys.keys.sort.should == ['_id', 'grandparent']
|
173
|
-
Parent.keys.keys.sort.should == ['_id', 'grandparent', 'parent']
|
174
|
-
Child.keys.keys.sort.should == ['_id', 'child', 'grandparent', 'parent']
|
175
|
-
end
|
76
|
+
context "#to_mongo" do
|
77
|
+
setup { @klass = EDoc() }
|
176
78
|
|
177
|
-
|
178
|
-
|
79
|
+
should "be nil if nil" do
|
80
|
+
@klass.to_mongo(nil).should be_nil
|
81
|
+
end
|
179
82
|
|
180
|
-
|
181
|
-
|
182
|
-
|
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
|
183
89
|
end
|
184
90
|
|
185
|
-
|
186
|
-
|
187
|
-
end
|
91
|
+
context "#from_mongo" do
|
92
|
+
setup { @klass = EDoc() }
|
188
93
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
end
|
193
|
-
|
194
|
-
context "descendants" do
|
195
|
-
should "default to nil" do
|
196
|
-
Child.descendants.should be_nil
|
197
|
-
end
|
94
|
+
should "be nil if nil" do
|
95
|
+
@klass.from_mongo(nil).should be_nil
|
96
|
+
end
|
198
97
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
end
|
204
|
-
end
|
98
|
+
should "be instance if instance of class" do
|
99
|
+
doc = @klass.new
|
100
|
+
@klass.from_mongo(doc).should == doc
|
101
|
+
end
|
205
102
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
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'
|
107
|
+
end
|
211
108
|
end
|
212
|
-
end
|
213
|
-
|
214
|
-
should "have to_param that is string representation of id" do
|
215
|
-
doc = @document.new
|
216
|
-
doc.to_param.should == doc.id.to_s
|
217
|
-
doc.to_param.should be_instance_of(String)
|
218
|
-
end
|
219
|
-
|
220
|
-
should "have access to class logger" do
|
221
|
-
doc = @document.new
|
222
|
-
doc.logger.should == @document.logger
|
223
|
-
doc.logger.should be_instance_of(Logger)
|
224
|
-
end
|
225
|
-
|
226
|
-
should "automatically have an _id key" do
|
227
|
-
@document.keys.keys.should include('_id')
|
228
|
-
end
|
229
|
-
|
230
|
-
should "create id during initialization" do
|
231
|
-
@document.new._id.should be_instance_of(Mongo::ObjectID)
|
232
|
-
end
|
233
|
-
|
234
|
-
should "have id method returns _id" do
|
235
|
-
id = Mongo::ObjectID.new
|
236
|
-
doc = @document.new(:_id => id)
|
237
|
-
doc.id.should == id
|
238
|
-
end
|
239
|
-
|
240
|
-
should "convert string object id to mongo object id when assigning id with _id object id type" do
|
241
|
-
id = Mongo::ObjectID.new
|
242
|
-
|
243
|
-
doc = @document.new(:id => id.to_s)
|
244
|
-
doc._id.should == id
|
245
|
-
doc.id.should == id
|
246
|
-
|
247
|
-
doc = @document.new(:_id => id.to_s)
|
248
|
-
doc._id.should == id
|
249
|
-
doc.id.should == id
|
250
|
-
end
|
251
109
|
|
252
|
-
|
253
|
-
|
254
|
-
|
110
|
+
context "defining a key" do
|
111
|
+
setup do
|
112
|
+
@document = EDoc()
|
113
|
+
end
|
114
|
+
|
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
|
166
|
+
|
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
|
255
178
|
end
|
256
179
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
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
|
186
|
+
|
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
|
197
|
+
end
|
198
|
+
|
199
|
+
should "not include descendant keys" do
|
200
|
+
lambda { Parent.new.other_child }.should raise_error
|
201
|
+
end
|
262
202
|
end
|
263
203
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
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
|
270
213
|
end
|
271
214
|
end
|
272
215
|
|
273
|
-
context "
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
end
|
280
|
-
|
281
|
-
should "be able to assign keys dynamically" do
|
282
|
-
doc = @document.new(:name => 'John', :skills => ['ruby', 'rails'])
|
283
|
-
doc.name.should == 'John'
|
284
|
-
doc.skills.should == ['ruby', 'rails']
|
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
|
285
222
|
end
|
286
223
|
|
287
|
-
should "
|
288
|
-
|
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)
|
289
228
|
end
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
229
|
+
|
230
|
+
should "have access to class logger" do
|
231
|
+
doc = @document.new
|
232
|
+
doc.logger.should == @document.logger
|
233
|
+
doc.logger.should be_instance_of(Logger)
|
295
234
|
end
|
296
235
|
|
297
|
-
should "
|
298
|
-
@
|
236
|
+
should "automatically have an _id key" do
|
237
|
+
@document.keys.keys.should include('_id')
|
299
238
|
end
|
300
|
-
|
301
|
-
should "
|
302
|
-
@
|
239
|
+
|
240
|
+
should "create id during initialization" do
|
241
|
+
@document.new._id.should be_instance_of(Mongo::ObjectID)
|
303
242
|
end
|
304
|
-
end
|
305
243
|
|
306
|
-
|
307
|
-
|
308
|
-
doc = @document.new(:
|
309
|
-
doc.
|
310
|
-
doc.attributes[:name].should == 'new value'
|
311
|
-
doc.attributes[:age].should == 5
|
244
|
+
should "have id method returns _id" do
|
245
|
+
id = Mongo::ObjectID.new
|
246
|
+
doc = @document.new(:_id => id)
|
247
|
+
doc.id.should == id
|
312
248
|
end
|
313
249
|
|
314
|
-
should "
|
315
|
-
|
316
|
-
|
317
|
-
doc.
|
318
|
-
doc.
|
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
|
319
260
|
end
|
320
261
|
|
321
|
-
|
322
|
-
|
323
|
-
|
262
|
+
context "_root_document" do
|
263
|
+
should "default to nil" do
|
264
|
+
@document.new._root_document.should be_nil
|
265
|
+
end
|
324
266
|
|
325
|
-
|
326
|
-
|
327
|
-
|
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)
|
328
272
|
end
|
329
273
|
|
330
|
-
|
331
|
-
|
332
|
-
|
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 => [{}])
|
333
278
|
|
334
|
-
|
335
|
-
|
336
|
-
doc.name.should == '1234'
|
337
|
-
doc.age.should == 21
|
279
|
+
doc.children.first._root_document.should == root
|
280
|
+
end
|
338
281
|
end
|
339
|
-
end
|
340
282
|
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
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
|
289
|
+
end
|
346
290
|
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
end
|
353
|
-
|
354
|
-
should "have indifferent access" do
|
355
|
-
doc = @document.new(:name => 'string')
|
356
|
-
doc.attributes[:name].should == 'string'
|
357
|
-
doc.attributes['name'].should == 'string'
|
358
|
-
end
|
359
|
-
end
|
360
|
-
|
361
|
-
context "to_mongo" do
|
362
|
-
should "default to hash with _id key" do
|
363
|
-
doc = @document.new
|
364
|
-
doc.to_mongo.keys.sort.should == ['_id', 'age', 'name']
|
365
|
-
end
|
366
|
-
|
367
|
-
should "return all keys" do
|
368
|
-
doc = @document.new(:name => 'string', :age => nil)
|
369
|
-
doc.to_mongo.keys.sort.should == ['_id', 'age', 'name']
|
370
|
-
doc.to_mongo.values.should include('string')
|
371
|
-
doc.to_mongo.values.should include(nil)
|
372
|
-
end
|
373
|
-
end
|
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']
|
295
|
+
end
|
374
296
|
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
doc_id = doc.id
|
379
|
-
clone = doc.clone
|
380
|
-
clone_id = clone.id
|
381
|
-
clone_id.should_not == doc_id
|
297
|
+
should "not throw error if initialized with nil" do
|
298
|
+
assert_nothing_raised { @document.new(nil) }
|
299
|
+
end
|
382
300
|
end
|
383
301
|
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
302
|
+
context "initialized when _type key present" do
|
303
|
+
setup do
|
304
|
+
@klass = EDoc('FooBar') { key :_type, String }
|
305
|
+
end
|
306
|
+
|
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
|
389
314
|
end
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
doc
|
396
|
-
doc[:
|
315
|
+
|
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
|
397
322
|
end
|
398
|
-
|
399
|
-
should "
|
400
|
-
doc = @document.new(:name => '
|
401
|
-
|
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
|
338
|
+
end
|
339
|
+
|
340
|
+
doc = @document.new(:name => 'foobar', :password => 'secret')
|
341
|
+
doc.passwd.should == 'secret'
|
342
|
+
end
|
343
|
+
|
344
|
+
should "typecast key values" do
|
345
|
+
doc = @document.new(:name => 1234, :age => '21')
|
346
|
+
doc.name.should == '1234'
|
347
|
+
doc.age.should == 21
|
402
348
|
end
|
403
349
|
end
|
404
|
-
|
405
|
-
context "
|
406
|
-
should "
|
350
|
+
|
351
|
+
context "attributes" do
|
352
|
+
should "default to hash with all keys" do
|
407
353
|
doc = @document.new
|
408
|
-
doc[
|
409
|
-
doc[:name].should == 'string'
|
354
|
+
doc.attributes.keys.sort.should == ['_id', 'age', 'name']
|
410
355
|
end
|
411
|
-
|
412
|
-
should "
|
413
|
-
doc = @document.new
|
414
|
-
doc[
|
415
|
-
doc.
|
416
|
-
doc
|
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)
|
417
362
|
end
|
418
363
|
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
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
|
424
369
|
end
|
425
|
-
end
|
426
370
|
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
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
|
431
383
|
end
|
432
384
|
|
433
|
-
|
434
|
-
|
435
|
-
|
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
|
436
400
|
end
|
437
401
|
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
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] }
|
442
412
|
end
|
443
413
|
end
|
444
414
|
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
doc = @document.new
|
452
|
-
doc.instance_variable_get("@foo").should be_nil
|
453
|
-
doc.foo
|
454
|
-
doc.instance_variable_get("@foo").should == []
|
455
|
-
end
|
456
|
-
|
457
|
-
should "be overrideable by modules" do
|
458
|
-
@document = Doc do
|
459
|
-
key :other_child, String
|
460
|
-
end
|
461
|
-
|
462
|
-
child = @document.new
|
463
|
-
child.other_child.should be_nil
|
464
|
-
|
465
|
-
@document.send :include, KeyOverride
|
466
|
-
|
467
|
-
overriden_child = @document.new
|
468
|
-
overriden_child.other_child.should == 'special result'
|
469
|
-
end
|
470
|
-
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
|
471
421
|
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
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
|
477
428
|
|
478
|
-
|
479
|
-
|
480
|
-
|
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
|
481
435
|
end
|
482
436
|
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
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
|
487
453
|
end
|
454
|
+
|
455
|
+
doc = @document.new(:name => 'John', :age => 27)
|
456
|
+
doc.name_and_age.should == 'John (27)'
|
488
457
|
end
|
489
458
|
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
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
|
495
466
|
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
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
|
501
480
|
end
|
502
481
|
|
503
|
-
|
504
|
-
|
505
|
-
|
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
|
506
504
|
end
|
507
505
|
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
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
|
522
533
|
end
|
534
|
+
|
535
|
+
doc = @document.new
|
536
|
+
doc.name_and_age = 'Frank (62)'
|
537
|
+
doc.name.should == 'Frank'
|
538
|
+
doc.age.should == 62
|
523
539
|
end
|
524
540
|
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
end
|
530
|
-
|
531
|
-
should "be overrideable by modules" do
|
532
|
-
@document = Doc do
|
533
|
-
key :other_child, String
|
534
|
-
end
|
535
|
-
|
536
|
-
child = @document.new(:other_child => 'foo')
|
537
|
-
child.other_child.should == 'foo'
|
538
|
-
|
539
|
-
@document.send :include, KeyOverride
|
540
|
-
|
541
|
-
overriden_child = @document.new(:other_child => 'foo')
|
542
|
-
overriden_child.other_child.should == 'foo modified'
|
543
|
-
end
|
544
|
-
end # writing a key
|
545
|
-
|
546
|
-
context "checking if a keys value is present" do
|
547
|
-
should "work for defined keys" do
|
548
|
-
doc = @document.new
|
549
|
-
doc.name?.should be_false
|
550
|
-
doc.name = 'John'
|
551
|
-
doc.name?.should be_true
|
552
|
-
end
|
553
|
-
|
554
|
-
should "raise no method error for undefined keys" do
|
555
|
-
doc = @document.new
|
556
|
-
lambda { doc.fart? }.should raise_error(NoMethodError)
|
557
|
-
end
|
558
|
-
end
|
559
|
-
|
560
|
-
should "call inspect on the document's attributes instead of to_s when inspecting the document" do
|
561
|
-
doc = @document.new(:animals => %w(dog cat))
|
562
|
-
doc.inspect.should include(%(animals: ["dog", "cat"]))
|
563
|
-
end
|
564
|
-
|
565
|
-
context "equality" do
|
566
|
-
setup do
|
567
|
-
@oid = Mongo::ObjectID.new
|
568
|
-
end
|
569
|
-
|
570
|
-
should "delegate hash to _id" do
|
571
|
-
doc = @document.new
|
572
|
-
doc.hash.should == doc._id.hash
|
573
|
-
end
|
574
|
-
|
575
|
-
should "delegate eql to ==" do
|
576
|
-
doc = @document.new
|
577
|
-
other = @document.new
|
578
|
-
doc.eql?(other).should == (doc == other)
|
579
|
-
doc.eql?(doc).should == (doc == doc)
|
580
|
-
end
|
581
|
-
|
582
|
-
should "know if same object as another" do
|
583
|
-
doc = @document.new
|
584
|
-
doc.should equal(doc)
|
585
|
-
doc.should_not equal(@document.new)
|
586
|
-
end
|
587
|
-
|
588
|
-
should "allow set operations on array of documents" do
|
589
|
-
doc = @document.new
|
590
|
-
([doc] & [doc]).should == [doc]
|
591
|
-
end
|
592
|
-
|
593
|
-
should "be equal if id and class are the same" do
|
594
|
-
(@document.new('_id' => @oid) == @document.new('_id' => @oid)).should be_true
|
595
|
-
end
|
541
|
+
should "be overrideable by modules" do
|
542
|
+
@document = Doc do
|
543
|
+
key :other_child, String
|
544
|
+
end
|
596
545
|
|
597
|
-
|
598
|
-
|
599
|
-
end
|
546
|
+
child = @document.new(:other_child => 'foo')
|
547
|
+
child.other_child.should == 'foo'
|
600
548
|
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
end
|
606
|
-
|
607
|
-
context "reading keys with default values" do
|
608
|
-
setup do
|
609
|
-
@document = EDoc do
|
610
|
-
key :name, String, :default => 'foo'
|
611
|
-
key :age, Integer, :default => 20
|
612
|
-
key :net_worth, Float, :default => 100.00
|
613
|
-
key :active, Boolean, :default => true
|
614
|
-
key :smart, Boolean, :default => false
|
615
|
-
key :skills, Array, :default => [1]
|
616
|
-
key :options, Hash, :default => {'foo' => 'bar'}
|
549
|
+
@document.send :include, KeyOverride
|
550
|
+
|
551
|
+
overriden_child = @document.new(:other_child => 'foo')
|
552
|
+
overriden_child.other_child.should == 'foo modified'
|
617
553
|
end
|
554
|
+
end # writing a key
|
618
555
|
|
619
|
-
|
620
|
-
|
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
|
621
563
|
|
622
|
-
|
623
|
-
|
564
|
+
should "raise no method error for undefined keys" do
|
565
|
+
doc = @document.new
|
566
|
+
lambda { doc.fart? }.should raise_error(NoMethodError)
|
567
|
+
end
|
624
568
|
end
|
625
569
|
|
626
|
-
should "
|
627
|
-
@
|
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"]))
|
628
573
|
end
|
629
574
|
|
630
|
-
|
631
|
-
|
632
|
-
|
575
|
+
context "equality" do
|
576
|
+
setup do
|
577
|
+
@oid = Mongo::ObjectID.new
|
578
|
+
end
|
633
579
|
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
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
|
638
597
|
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
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
|
643
615
|
end
|
644
616
|
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
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
|
630
|
+
end
|
631
|
+
|
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
|
649
660
|
end
|
650
|
-
end
|
651
|
-
end
|
661
|
+
end # instance of a embedded document
|
662
|
+
end
|
652
663
|
end
|