jnunemaker-mongomapper 0.2.0 → 0.3.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 (55) hide show
  1. data/.gitignore +1 -0
  2. data/History +17 -0
  3. data/README.rdoc +6 -3
  4. data/Rakefile +3 -2
  5. data/VERSION +1 -1
  6. data/bin/mmconsole +56 -0
  7. data/lib/mongomapper.rb +48 -17
  8. data/lib/mongomapper/associations.rb +31 -39
  9. data/lib/mongomapper/associations/base.rb +40 -22
  10. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +33 -0
  11. data/lib/mongomapper/associations/belongs_to_proxy.rb +10 -14
  12. data/lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb +34 -0
  13. data/lib/mongomapper/associations/{has_many_embedded_proxy.rb → many_embedded_proxy.rb} +5 -5
  14. data/lib/mongomapper/associations/many_proxy.rb +55 -0
  15. data/lib/mongomapper/associations/proxy.rb +21 -14
  16. data/lib/mongomapper/callbacks.rb +1 -1
  17. data/lib/mongomapper/document.rb +82 -59
  18. data/lib/mongomapper/embedded_document.rb +121 -130
  19. data/lib/mongomapper/finder_options.rb +21 -6
  20. data/lib/mongomapper/key.rb +5 -7
  21. data/lib/mongomapper/observing.rb +1 -41
  22. data/lib/mongomapper/pagination.rb +52 -0
  23. data/lib/mongomapper/rails_compatibility/document.rb +15 -0
  24. data/lib/mongomapper/rails_compatibility/embedded_document.rb +25 -0
  25. data/lib/mongomapper/serialization.rb +1 -1
  26. data/mongomapper.gemspec +62 -36
  27. data/test/NOTE_ON_TESTING +1 -0
  28. data/test/functional/test_associations.rb +485 -0
  29. data/test/{test_callbacks.rb → functional/test_callbacks.rb} +2 -1
  30. data/test/functional/test_document.rb +636 -0
  31. data/test/functional/test_pagination.rb +82 -0
  32. data/test/functional/test_rails_compatibility.rb +31 -0
  33. data/test/functional/test_validations.rb +172 -0
  34. data/test/models.rb +92 -0
  35. data/test/test_helper.rb +5 -0
  36. data/test/{serializers → unit/serializers}/test_json_serializer.rb +0 -0
  37. data/test/unit/test_association_base.rb +131 -0
  38. data/test/unit/test_document.rb +115 -0
  39. data/test/{test_embedded_document.rb → unit/test_embedded_document.rb} +158 -66
  40. data/test/{test_finder_options.rb → unit/test_finder_options.rb} +66 -0
  41. data/test/{test_key.rb → unit/test_key.rb} +13 -1
  42. data/test/unit/test_mongo_id.rb +35 -0
  43. data/test/{test_mongomapper.rb → unit/test_mongomapper.rb} +0 -0
  44. data/test/{test_observing.rb → unit/test_observing.rb} +0 -0
  45. data/test/unit/test_pagination.rb +113 -0
  46. data/test/unit/test_rails_compatibility.rb +34 -0
  47. data/test/{test_serializations.rb → unit/test_serializations.rb} +0 -2
  48. data/test/{test_validations.rb → unit/test_validations.rb} +0 -134
  49. metadata +68 -36
  50. data/lib/mongomapper/associations/has_many_proxy.rb +0 -28
  51. data/lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb +0 -31
  52. data/lib/mongomapper/rails_compatibility.rb +0 -23
  53. data/test/test_associations.rb +0 -149
  54. data/test/test_document.rb +0 -944
  55. data/test/test_rails_compatibility.rb +0 -29
@@ -0,0 +1,115 @@
1
+ require 'test_helper'
2
+
3
+ class DocumentTest < Test::Unit::TestCase
4
+ context "The Document Class" do
5
+ setup do
6
+ @document = Class.new do
7
+ include MongoMapper::Document
8
+ end
9
+ end
10
+
11
+ should "track its descendants" do
12
+ MongoMapper::Document.descendants.should include(@document)
13
+ end
14
+
15
+ should "use default database by default" do
16
+ @document.database.should == MongoMapper.database
17
+ end
18
+
19
+ should "have a connection" do
20
+ @document.connection.should be_instance_of(XGen::Mongo::Driver::Mongo)
21
+ end
22
+
23
+ should "allow setting different connection without affecting the default" do
24
+ conn = XGen::Mongo::Driver::Mongo.new
25
+ @document.connection conn
26
+ @document.connection.should == conn
27
+ @document.connection.should_not == MongoMapper.connection
28
+ end
29
+
30
+ should "allow setting a different database without affecting the default" do
31
+ @document.database AlternateDatabase
32
+ @document.database.name.should == AlternateDatabase
33
+
34
+ another_document = Class.new do
35
+ include MongoMapper::Document
36
+ end
37
+ another_document.database.should == MongoMapper.database
38
+ end
39
+
40
+ should "default collection name to class name tableized" do
41
+ class Item
42
+ include MongoMapper::Document
43
+ end
44
+
45
+ Item.collection.should be_instance_of(XGen::Mongo::Driver::Collection)
46
+ Item.collection.name.should == 'items'
47
+ end
48
+
49
+ should "allow setting the collection name" do
50
+ @document.collection('foobar')
51
+ @document.collection.should be_instance_of(XGen::Mongo::Driver::Collection)
52
+ @document.collection.name.should == 'foobar'
53
+ end
54
+ end # Document class
55
+
56
+ context "An instance of a document" do
57
+ setup do
58
+ @document = Class.new do
59
+ include MongoMapper::Document
60
+
61
+ key :name, String
62
+ key :age, Integer
63
+ end
64
+ @document.collection.clear
65
+ end
66
+
67
+ should "have access to the class's collection" do
68
+ doc = @document.new
69
+ doc.collection.should == @document.collection
70
+ end
71
+
72
+ should "automatically have an _id key" do
73
+ @document.keys.keys.should include('_id')
74
+ end
75
+
76
+ should "automatically have a created_at key" do
77
+ @document.keys.keys.should include('created_at')
78
+ end
79
+
80
+ should "automatically have an updated_at key" do
81
+ @document.keys.keys.should include('updated_at')
82
+ end
83
+
84
+ should "use default values if defined for keys" do
85
+ @document.key :active, Boolean, :default => true
86
+
87
+ @document.new.active.should be_true
88
+ @document.new(:active => false).active.should be_false
89
+ end
90
+
91
+ context "new?" do
92
+ should "be true if no id" do
93
+ @document.new.new?.should be(true)
94
+ end
95
+ end
96
+
97
+ context "equality" do
98
+ should "be equal if id and class are the same" do
99
+ (@document.new('_id' => 1) == @document.new('_id' => 1)).should be(true)
100
+ end
101
+
102
+ should "not be equal if class same but id different" do
103
+ (@document.new('_id' => 1) == @document.new('_id' => 2)).should be(false)
104
+ end
105
+
106
+ should "not be equal if id same but class different" do
107
+ @another_document = Class.new do
108
+ include MongoMapper::Document
109
+ end
110
+
111
+ (@document.new('_id' => 1) == @another_document.new('_id' => 1)).should be(false)
112
+ end
113
+ end
114
+ end # instance of a document
115
+ end # DocumentTest
@@ -1,5 +1,25 @@
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
+ class OtherChild < Parent
19
+ include MongoMapper::EmbeddedDocument
20
+ key :other_child, String
21
+ end
22
+
3
23
  class EmbeddedDocumentTest < Test::Unit::TestCase
4
24
  context "Including MongoMapper::EmbeddedDocument" do
5
25
  setup do
@@ -7,33 +27,135 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
7
27
  include MongoMapper::EmbeddedDocument
8
28
  end
9
29
  end
10
-
30
+
11
31
  should "clear out document default keys" do
12
32
  @klass.keys.size.should == 0
13
33
  end
14
34
  end
15
35
 
36
+ context "parent_model" do
37
+ should "be nil if none of parents ancestors include EmbeddedDocument" do
38
+ parent = Class.new
39
+ document = Class.new(parent) do
40
+ include MongoMapper::EmbeddedDocument
41
+ end
42
+ document.parent_model.should be_nil
43
+ end
44
+
45
+ should "find parent" do
46
+ Parent.parent_model.should == Grandparent
47
+ Child.parent_model.should == Parent
48
+ end
49
+ end
50
+
51
+ context "defining a key" do
52
+ setup do
53
+ @document = Class.new do
54
+ include MongoMapper::EmbeddedDocument
55
+ end
56
+ end
57
+
58
+ should "work" do
59
+ key = @document.key(:name, String)
60
+ key.name.should == 'name'
61
+ key.type.should == String
62
+ key.should be_instance_of(MongoMapper::Key)
63
+ end
64
+
65
+ should "work with options" do
66
+ key = @document.key(:name, String, :required => true)
67
+ key.options[:required].should be(true)
68
+ end
69
+
70
+ should "be tracked per document" do
71
+ @document.key(:name, String)
72
+ @document.key(:age, Integer)
73
+ @document.keys['name'].name.should == 'name'
74
+ @document.keys['name'].type.should == String
75
+ @document.keys['age'].name.should == 'age'
76
+ @document.keys['age'].type.should == Integer
77
+ end
78
+
79
+ should "be redefinable" do
80
+ @document.key(:foo, String)
81
+ @document.keys['foo'].type.should == String
82
+ @document.key(:foo, Integer)
83
+ @document.keys['foo'].type.should == Integer
84
+ end
85
+
86
+ should "create reader method" do
87
+ @document.new.should_not respond_to(:foo)
88
+ @document.key(:foo, String)
89
+ @document.new.should respond_to(:foo)
90
+ end
91
+
92
+ should "create reader before typecast method" do
93
+ @document.new.should_not respond_to(:foo_before_typecast)
94
+ @document.key(:foo, String)
95
+ @document.new.should respond_to(:foo_before_typecast)
96
+ end
97
+
98
+ should "create writer method" do
99
+ @document.new.should_not respond_to(:foo=)
100
+ @document.key(:foo, String)
101
+ @document.new.should respond_to(:foo=)
102
+ end
103
+
104
+ should "create boolean method" do
105
+ @document.new.should_not respond_to(:foo?)
106
+ @document.key(:foo, String)
107
+ @document.new.should respond_to(:foo?)
108
+ end
109
+ end
110
+
111
+ context "keys" do
112
+ should "be inherited" do
113
+ Grandparent.keys.keys.should == ['grandparent']
114
+ Parent.keys.keys.sort.should == ['grandparent', 'parent']
115
+ Child.keys.keys.sort.should == ['child', 'grandparent', 'parent']
116
+ end
117
+
118
+ should "propogate to subclasses if key added after class definition" do
119
+ Grandparent.key :_type, String
120
+
121
+ Grandparent.keys.keys.sort.should == ['_type', 'grandparent']
122
+ Parent.keys.keys.sort.should == ['_type', 'grandparent', 'parent']
123
+ Child.keys.keys.sort.should == ['_type', 'child', 'grandparent', 'parent']
124
+ end
125
+ end
126
+
127
+ context "subclasses" do
128
+ should "default to nil" do
129
+ Child.subclasses.should be_nil
130
+ end
131
+
132
+ should "be recorded" do
133
+ Grandparent.subclasses.should == [Parent]
134
+ Parent.subclasses.should == [Child, OtherChild]
135
+ end
136
+ end
137
+
16
138
  context "An instance of an embedded document" do
17
139
  setup do
18
140
  @document = Class.new do
19
141
  include MongoMapper::EmbeddedDocument
20
-
142
+
21
143
  key :name, String
22
144
  key :age, Integer
23
145
  end
24
146
  end
25
-
26
- context "when initialized" do
147
+
148
+ context "being initialized" do
27
149
  should "accept a hash that sets keys and values" do
28
150
  doc = @document.new(:name => 'John', :age => 23)
29
151
  doc.attributes.should == {'name' => 'John', 'age' => 23}
30
152
  end
31
-
153
+
32
154
  should "not throw error if initialized with nil" do
33
155
  doc = @document.new(nil)
34
156
  end
35
157
  end
36
-
158
+
37
159
  context "mass assigning keys" do
38
160
  should "update values for keys provided" do
39
161
  doc = @document.new(:name => 'foobar', :age => 10)
@@ -49,22 +171,22 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
49
171
  doc.attributes[:age].should == 10
50
172
  end
51
173
 
52
- should "ignore keys that do not exist" do
174
+ should "raise undefined method if no key exists" do
53
175
  doc = @document.new(:name => 'foobar', :age => 10)
54
- doc.attributes = {:name => 'new value', :foobar => 'baz'}
55
- doc.attributes[:name].should == 'new value'
56
- doc.attributes[:foobar].should be(nil)
176
+ lambda {
177
+ doc.attributes = {:name => 'new value', :foobar => 'baz'}
178
+ }.should raise_error(NoMethodError)
57
179
  end
58
-
180
+
59
181
  should "not ignore keys that have methods defined" do
60
182
  @document.class_eval do
61
183
  attr_writer :password
62
-
184
+
63
185
  def passwd
64
186
  @password
65
187
  end
66
188
  end
67
-
189
+
68
190
  doc = @document.new(:name => 'foobar', :password => 'secret')
69
191
  doc.passwd.should == 'secret'
70
192
  end
@@ -76,7 +198,7 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
76
198
  end
77
199
  end
78
200
 
79
- context "requesting keys" do
201
+ context "attributes" do
80
202
  should "default to empty hash" do
81
203
  doc = @document.new
82
204
  doc.attributes.should == {}
@@ -87,20 +209,20 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
87
209
  doc.attributes.should == {'name' => 'string'}
88
210
  end
89
211
  end
90
-
91
- context "key shorcuts" do
212
+
213
+ context "key shorcut access" do
92
214
  should "be able to read key with []" do
93
215
  doc = @document.new(:name => 'string')
94
216
  doc[:name].should == 'string'
95
217
  end
96
-
218
+
97
219
  should "be able to write key value with []=" do
98
220
  doc = @document.new
99
221
  doc[:name] = 'string'
100
222
  doc[:name].should == 'string'
101
223
  end
102
224
  end
103
-
225
+
104
226
  context "indifferent access" do
105
227
  should "be enabled for keys" do
106
228
  doc = @document.new(:name => 'string')
@@ -119,47 +241,37 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
119
241
  doc = @document.new
120
242
  lambda { doc.fart }.should raise_error(NoMethodError)
121
243
  end
122
-
123
- should "know if reader defined" do
124
- doc = @document.new
125
- doc.reader?('name').should be(true)
126
- doc.reader?(:name).should be(true)
127
- doc.reader?('age').should be(true)
128
- doc.reader?(:age).should be(true)
129
- doc.reader?('foobar').should be(false)
130
- doc.reader?(:foobar).should be(false)
131
- end
132
-
244
+
133
245
  should "be accessible for use in the model" do
134
246
  @document.class_eval do
135
247
  def name_and_age
136
248
  "#{read_attribute(:name)} (#{read_attribute(:age)})"
137
249
  end
138
250
  end
139
-
251
+
140
252
  doc = @document.new(:name => 'John', :age => 27)
141
253
  doc.name_and_age.should == 'John (27)'
142
254
  end
143
255
  end
144
-
256
+
145
257
  context "reading an attribute before typcasting" do
146
258
  should "work for defined keys" do
147
259
  doc = @document.new(:name => 12)
148
260
  doc.name_before_typecast.should == 12
149
261
  end
150
-
262
+
151
263
  should "raise no method error for undefined keys" do
152
264
  doc = @document.new
153
265
  lambda { doc.foo_before_typecast }.should raise_error(NoMethodError)
154
266
  end
155
-
267
+
156
268
  should "be accessible for use in a document" do
157
269
  @document.class_eval do
158
270
  def untypcasted_name
159
271
  read_attribute_before_typecast(:name)
160
272
  end
161
273
  end
162
-
274
+
163
275
  doc = @document.new(:name => 12)
164
276
  doc.name.should == '12'
165
277
  doc.untypcasted_name.should == 12
@@ -186,28 +298,15 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
186
298
  doc.age.should == 21
187
299
  end
188
300
 
189
- should "know if writer defined" do
190
- doc = @document.new
191
- doc.writer?('name').should be(true)
192
- doc.writer?('name=').should be(true)
193
- doc.writer?(:name).should be(true)
194
- doc.writer?('age').should be(true)
195
- doc.writer?('age=').should be(true)
196
- doc.writer?(:age).should be(true)
197
- doc.writer?('foobar').should be(false)
198
- doc.writer?('foobar=').should be(false)
199
- doc.writer?(:foobar).should be(false)
200
- end
201
-
202
301
  should "be accessible for use in the model" do
203
- @document.class_eval do
302
+ @document.class_eval do
204
303
  def name_and_age=(new_value)
205
304
  new_value.match(/([^\(\s]+) \((.*)\)/)
206
305
  write_attribute :name, $1
207
306
  write_attribute :age, $2
208
307
  end
209
308
  end
210
-
309
+
211
310
  doc = @document.new
212
311
  doc.name_and_age = 'Frank (62)'
213
312
  doc.name.should == 'Frank'
@@ -215,24 +314,17 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
215
314
  end
216
315
  end # writing an attribute
217
316
 
218
- context "respond_to?" do
219
- setup do
220
- @doc = @document.new
221
- end
222
-
223
- should "work for readers" do
224
- @doc.respond_to?(:name).should be_true
225
- @doc.respond_to?('name').should be_true
226
- end
227
-
228
- should "work for writers" do
229
- @doc.respond_to?(:name=).should be_true
230
- @doc.respond_to?('name=').should be_true
317
+ context "checking if an attributes value is present" do
318
+ should "work for defined keys" do
319
+ doc = @document.new
320
+ doc.name?.should be_false
321
+ doc.name = 'John'
322
+ doc.name?.should be_true
231
323
  end
232
324
 
233
- should "work for readers before typecast" do
234
- @doc.respond_to?(:name_before_typecast).should be_true
235
- @doc.respond_to?('name_before_typecast').should be_true
325
+ should "raise no method error for undefined keys" do
326
+ doc = @document.new
327
+ lambda { doc.fart? }.should raise_error(NoMethodError)
236
328
  end
237
329
  end
238
330
 
@@ -242,7 +334,7 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
242
334
  doc2 = @document.new(:name => 'John', :age => 27)
243
335
  doc1.should == doc2
244
336
  end
245
-
337
+
246
338
  should "be false if not all the keys and values are equal" do
247
339
  doc1 = @document.new(:name => 'Steve', :age => 27)
248
340
  doc2 = @document.new(:name => 'John', :age => 27)