jnunemaker-mongomapper 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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)