mongo_mapper 0.7.0 → 0.7.1

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 (43) hide show
  1. data/README.rdoc +3 -1
  2. data/Rakefile +9 -12
  3. data/lib/mongo_mapper.rb +30 -10
  4. data/lib/mongo_mapper/document.rb +16 -74
  5. data/lib/mongo_mapper/embedded_document.rb +7 -1
  6. data/lib/mongo_mapper/plugins.rb +3 -0
  7. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +1 -12
  8. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +6 -1
  9. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +4 -1
  10. data/lib/mongo_mapper/plugins/callbacks.rb +183 -12
  11. data/lib/mongo_mapper/plugins/keys.rb +17 -5
  12. data/lib/mongo_mapper/plugins/modifiers.rb +87 -0
  13. data/lib/mongo_mapper/plugins/pagination/proxy.rb +7 -3
  14. data/lib/mongo_mapper/plugins/protected.rb +1 -1
  15. data/lib/mongo_mapper/plugins/rails.rb +16 -8
  16. data/lib/mongo_mapper/plugins/serialization.rb +51 -81
  17. data/lib/mongo_mapper/plugins/timestamps.rb +21 -0
  18. data/lib/mongo_mapper/plugins/userstamps.rb +14 -0
  19. data/lib/mongo_mapper/query.rb +1 -1
  20. data/lib/mongo_mapper/version.rb +3 -0
  21. data/mongo_mapper.gemspec +22 -11
  22. data/test/active_model_lint_test.rb +11 -0
  23. data/test/functional/associations/test_in_array_proxy.rb +16 -0
  24. data/test/functional/associations/test_many_documents_proxy.rb +22 -0
  25. data/test/functional/test_callbacks.rb +104 -34
  26. data/test/functional/test_document.rb +70 -149
  27. data/test/functional/test_embedded_document.rb +39 -34
  28. data/test/functional/test_indexing.rb +44 -0
  29. data/test/functional/test_modifiers.rb +297 -227
  30. data/test/functional/test_protected.rb +11 -5
  31. data/test/functional/test_timestamps.rb +64 -0
  32. data/test/functional/test_userstamps.rb +28 -0
  33. data/test/support/timing.rb +1 -1
  34. data/test/unit/serializers/test_json_serializer.rb +30 -17
  35. data/test/unit/test_embedded_document.rb +15 -15
  36. data/test/unit/test_keys.rb +15 -11
  37. data/test/unit/test_mongo_mapper.rb +31 -1
  38. data/test/unit/test_pagination.rb +33 -0
  39. data/test/unit/test_query.rb +6 -0
  40. data/test/unit/test_serialization.rb +3 -3
  41. data/test/unit/test_support.rb +9 -5
  42. metadata +17 -6
  43. data/VERSION +0 -1
@@ -16,7 +16,7 @@ class ProtectedTest < Test::Unit::TestCase
16
16
  should 'have protected attributes class method' do
17
17
  @doc_class.protected_attributes.should == [:admin].to_set
18
18
  end
19
-
19
+
20
20
  should "default protected attributes to nil" do
21
21
  Doc().protected_attributes.should be_nil
22
22
  end
@@ -46,7 +46,7 @@ class ProtectedTest < Test::Unit::TestCase
46
46
  doc = @doc_class.new(:name => 'John')
47
47
  doc.admin = true
48
48
  doc.save!
49
-
49
+
50
50
  doc = @doc_class.first(:name => 'John')
51
51
  doc.admin.should be_true
52
52
  doc.name.should == 'John'
@@ -63,8 +63,14 @@ class ProtectedTest < Test::Unit::TestCase
63
63
  @doc.name.should == 'Stimpson J. Cat'
64
64
  @doc.admin.should be_false
65
65
  end
66
+
67
+ should 'be indifferent to whether the protected keys are strings or symbols' do
68
+ @doc.update_attributes!("name" => 'Stimpson J. Cat', "admin" => true)
69
+ @doc.name.should == 'Stimpson J. Cat'
70
+ @doc.admin.should be_false
71
+ end
66
72
  end
67
-
73
+
68
74
  context "Single collection inherited protected attributes" do
69
75
  setup do
70
76
  class ::GrandParent
@@ -126,7 +132,7 @@ class ProtectedTest < Test::Unit::TestCase
126
132
  should 'have protected attributes class method' do
127
133
  @edoc_class.protected_attributes.should == [:admin].to_set
128
134
  end
129
-
135
+
130
136
  should "default protected attributes to nil" do
131
137
  EDoc().protected_attributes.should be_nil
132
138
  end
@@ -152,4 +158,4 @@ class ProtectedTest < Test::Unit::TestCase
152
158
  @edoc.admin.should be_false
153
159
  end
154
160
  end
155
- end
161
+ end
@@ -0,0 +1,64 @@
1
+ require 'test_helper'
2
+
3
+ class TimestampsTest < Test::Unit::TestCase
4
+ context "timestamping" do
5
+ setup do
6
+ @klass = Doc do
7
+ set_collection_name 'users'
8
+
9
+ key :first_name, String
10
+ key :last_name, String
11
+ key :age, Integer
12
+ key :date, Date
13
+ end
14
+ @klass.timestamps!
15
+ end
16
+
17
+ should "set created_at and updated_at on create" do
18
+ doc = @klass.new(:first_name => 'John', :age => 27)
19
+ doc.created_at.should be(nil)
20
+ doc.updated_at.should be(nil)
21
+ doc.save
22
+ doc.created_at.should_not be(nil)
23
+ doc.updated_at.should_not be(nil)
24
+ end
25
+
26
+ should "not overwrite created_at if it already exists" do
27
+ original_created_at = 1.month.ago
28
+ doc = @klass.new(:first_name => 'John', :age => 27, :created_at => original_created_at)
29
+ doc.created_at.to_i.should == original_created_at.to_i
30
+ doc.updated_at.should be_nil
31
+ doc.save
32
+ doc.created_at.to_i.should == original_created_at.to_i
33
+ doc.updated_at.should_not be_nil
34
+ end
35
+
36
+ should "set updated_at on field update but leave created_at alone" do
37
+ doc = @klass.create(:first_name => 'John', :age => 27)
38
+ old_created_at = doc.created_at
39
+ old_updated_at = doc.updated_at
40
+ doc.first_name = 'Johnny'
41
+
42
+ Timecop.freeze(Time.now + 5.seconds) do
43
+ doc.save
44
+ end
45
+
46
+ doc.created_at.should == old_created_at
47
+ doc.updated_at.should_not == old_updated_at
48
+ end
49
+
50
+ should "set updated_at on document update but leave created_at alone" do
51
+ doc = @klass.create(:first_name => 'John', :age => 27)
52
+ old_created_at = doc.created_at
53
+ old_updated_at = doc.updated_at
54
+
55
+ Timecop.freeze(Time.now + 5.seconds) do
56
+ @klass.update(doc._id, { :first_name => 'Johnny' })
57
+ end
58
+
59
+ doc = doc.reload
60
+ doc.created_at.should == old_created_at
61
+ doc.updated_at.should_not == old_updated_at
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,28 @@
1
+ require 'test_helper'
2
+
3
+ class UserstampsTest < Test::Unit::TestCase
4
+ context "userstamping" do
5
+ setup do
6
+ @document = Doc do
7
+ set_collection_name 'users'
8
+ userstamps!
9
+ end
10
+ end
11
+
12
+ should "add creator_id key" do
13
+ @document.keys.keys.should include('creator_id')
14
+ end
15
+
16
+ should "add updater_id key" do
17
+ @document.keys.keys.should include('updater_id')
18
+ end
19
+
20
+ should "add belongs_to creator" do
21
+ @document.associations.keys.should include('creator')
22
+ end
23
+
24
+ should "add belongs_to updater" do
25
+ @document.associations.keys.should include('updater')
26
+ end
27
+ end
28
+ end
@@ -5,7 +5,7 @@ class Test::Unit::TestCase
5
5
  end_time = Time.now
6
6
 
7
7
  duration = end_time - begin_time
8
- threshold = 1.0
8
+ threshold = 5.0
9
9
 
10
10
  if duration > threshold
11
11
  puts "\nSLOW TEST: #{duration} - #{self.name}"
@@ -1,6 +1,14 @@
1
1
  require 'test_helper'
2
+ require 'active_support/version'
2
3
 
3
4
  class JsonSerializationTest < Test::Unit::TestCase
5
+
6
+ # Helper function in case things change in the future
7
+ # - replacing all those to_json calls was a nightmare
8
+ def convert_to_json object, options = {}
9
+ ActiveSupport::JSON.encode(object, options)
10
+ end
11
+
4
12
  class Tag
5
13
  include MongoMapper::EmbeddedDocument
6
14
  key :name, String
@@ -30,11 +38,11 @@ class JsonSerializationTest < Test::Unit::TestCase
30
38
 
31
39
  should "include demodulized root" do
32
40
  Contact.include_root_in_json = true
33
- assert_match %r{^\{"contact": \{}, @contact.to_json
41
+ assert_match %r{^\{"contact":\s?\{}, convert_to_json(@contact)
34
42
  end
35
43
 
36
44
  should "encode all encodable attributes" do
37
- json = @contact.to_json
45
+ json = convert_to_json(@contact)
38
46
 
39
47
  assert_no_match %r{"_id"}, json
40
48
  assert_match %r{"name":"Konata Izumi"}, json
@@ -45,7 +53,7 @@ class JsonSerializationTest < Test::Unit::TestCase
45
53
  end
46
54
 
47
55
  should "allow attribute filtering with only" do
48
- json = @contact.to_json(:only => [:name, :age])
56
+ json = convert_to_json(@contact, :only => [:name, :age])
49
57
 
50
58
  assert_no_match %r{"_id"}, json
51
59
  assert_match %r{"name":"Konata Izumi"}, json
@@ -56,7 +64,7 @@ class JsonSerializationTest < Test::Unit::TestCase
56
64
  end
57
65
 
58
66
  should "allow attribute filtering with except" do
59
- json = @contact.to_json(:except => [:name, :age])
67
+ json = convert_to_json(@contact, :except => [:name, :age])
60
68
 
61
69
  assert_no_match %r{"_id"}, json
62
70
  assert_no_match %r{"name"}, json
@@ -68,12 +76,12 @@ class JsonSerializationTest < Test::Unit::TestCase
68
76
 
69
77
  context "_id key" do
70
78
  should "not be included by default" do
71
- json = @contact.to_json
79
+ json = convert_to_json(@contact)
72
80
  assert_no_match %r{"_id":}, json
73
81
  end
74
82
 
75
83
  should "not be included even if :except is used" do
76
- json = @contact.to_json(:except => :name)
84
+ json = convert_to_json(@contact, :except => :name)
77
85
  assert_no_match %r{"_id":}, json
78
86
  end
79
87
  end
@@ -85,12 +93,12 @@ class JsonSerializationTest < Test::Unit::TestCase
85
93
  end
86
94
 
87
95
  should "be included by default" do
88
- json = @contact.to_json
96
+ json = convert_to_json(@contact)
89
97
  assert_match %r{"id"}, json
90
98
  end
91
99
 
92
100
  should "be included when single method included" do
93
- json = @contact.to_json(:methods => :label)
101
+ json = convert_to_json(@contact, :methods => :label)
94
102
  assert_match %r{"id"}, json
95
103
  assert_match %r{"label":"Has cheezburger"}, json
96
104
  assert_match %r{"name":"Konata Izumi"}, json
@@ -98,7 +106,7 @@ class JsonSerializationTest < Test::Unit::TestCase
98
106
  end
99
107
 
100
108
  should "be included when multiple methods included" do
101
- json = @contact.to_json(:methods => [:label, :favorite_quote])
109
+ json = convert_to_json(@contact, :methods => [:label, :favorite_quote])
102
110
  assert_match %r{"id"}, json
103
111
  assert_match %r{"label":"Has cheezburger"}, json
104
112
  assert_match %r{"favorite_quote":"Constraints are liberating"}, json
@@ -106,9 +114,14 @@ class JsonSerializationTest < Test::Unit::TestCase
106
114
  end
107
115
 
108
116
  should "not be included if :only is present" do
109
- json = @contact.to_json(:only => :name)
117
+ json = convert_to_json(@contact, :only => :name)
110
118
  assert_no_match %r{"id":}, json
111
119
  end
120
+
121
+ should "be represented by a string" do
122
+ json = convert_to_json(@contact)
123
+ assert_match %r{"id":"}, json
124
+ end
112
125
  end
113
126
 
114
127
  context "including methods" do
@@ -118,12 +131,12 @@ class JsonSerializationTest < Test::Unit::TestCase
118
131
  end
119
132
 
120
133
  should "include single method" do
121
- json = @contact.to_json(:methods => :label)
134
+ json = convert_to_json(@contact, :methods => :label)
122
135
  assert_match %r{"label":"Has cheezburger"}, json
123
136
  end
124
137
 
125
138
  should "include multiple methods" do
126
- json = @contact.to_json(:only => :name, :methods => [:label, :favorite_quote])
139
+ json = convert_to_json(@contact, :only => :name, :methods => [:label, :favorite_quote])
127
140
  assert_match %r{"label":"Has cheezburger"}, json
128
141
  assert_match %r{"favorite_quote":"Constraints are liberating"}, json
129
142
  assert_match %r{"name":"Konata Izumi"}, json
@@ -143,13 +156,13 @@ class JsonSerializationTest < Test::Unit::TestCase
143
156
  end
144
157
 
145
158
  should "allow attribute filtering with only" do
146
- json = @contacts.to_json(:only => :name)
159
+ json =convert_to_json(@contacts, :only => :name)
147
160
  assert_match %r{\{"name":"David"\}}, json
148
161
  assert_match %r{\{"name":"Mary"\}}, json
149
162
  end
150
163
 
151
164
  should "allow attribute filtering with except" do
152
- json = @contacts.to_json(:except => [:name, :preferences, :awesome, :created_at, :updated_at])
165
+ json = convert_to_json(@contacts, :except => [:name, :preferences, :awesome, :created_at, :updated_at])
153
166
  assert_match %r{"age":39}, json
154
167
  assert_match %r{"age":14}, json
155
168
  assert_no_match %r{"name":}, json
@@ -165,7 +178,7 @@ class JsonSerializationTest < Test::Unit::TestCase
165
178
  1 => Contact.new(:name => 'David', :age => 39),
166
179
  2 => Contact.new(:name => 'Mary', :age => 14)
167
180
  }
168
- json = contacts.to_json(:only => [1, :name])
181
+ json = convert_to_json(contacts, :only => [1, :name])
169
182
  assert_match %r{"1":}, json
170
183
  assert_match %r{\{"name":"David"\}}, json
171
184
  assert_no_match %r{"2":}, json
@@ -174,7 +187,7 @@ class JsonSerializationTest < Test::Unit::TestCase
174
187
  should "include embedded attributes" do
175
188
  contact = Contact.new(:name => 'John', :age => 27)
176
189
  contact.tags = [Tag.new(:name => 'awesome'), Tag.new(:name => 'ruby')]
177
- json = contact.to_json
190
+ json = convert_to_json(contact)
178
191
  assert_match %r{"tags":}, json
179
192
  assert_match %r{"name":"awesome"}, json
180
193
  assert_match %r{"name":"ruby"}, json
@@ -183,7 +196,7 @@ class JsonSerializationTest < Test::Unit::TestCase
183
196
  should "include dynamic attributes" do
184
197
  contact = Contact.new(:name => 'John', :age => 27, :foo => 'bar')
185
198
  contact['smell'] = 'stinky'
186
- json = contact.to_json
199
+ json = convert_to_json(contact)
187
200
  assert_match %r{"smell":"stinky"}, json
188
201
  end
189
202
  end
@@ -42,7 +42,7 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
42
42
  Object.send :remove_const, 'Child' if defined?(::Child)
43
43
  Object.send :remove_const, 'OtherChild' if defined?(::OtherChild)
44
44
  end
45
-
45
+
46
46
  context "Including MongoMapper::EmbeddedDocument in a class" do
47
47
  setup do
48
48
  @klass = EDoc()
@@ -249,34 +249,34 @@ class EmbeddedDocumentTest < Test::Unit::TestCase
249
249
 
250
250
  should "convert string object id to mongo object id when assigning id with _id object id type" do
251
251
  id = Mongo::ObjectID.new
252
-
253
252
  doc = @document.new(:id => id.to_s)
254
253
  doc._id.should == id
255
- doc.id.should == id
256
-
254
+ doc.id.should == id
257
255
  doc = @document.new(:_id => id.to_s)
258
256
  doc._id.should == id
259
- doc.id.should == id
257
+ doc.id.should == id
260
258
  end
261
259
 
262
- context "_root_document" do
260
+ context "_parent_document" do
263
261
  should "default to nil" do
262
+ @document.new._parent_document.should be_nil
264
263
  @document.new._root_document.should be_nil
265
264
  end
266
265
 
267
- should "allow setting when initialized" do
266
+ should "set _root_document when setting _parent_document" do
268
267
  root = Doc().new
269
- doc = @document.new :_root_document => root
270
-
268
+ doc = @document.new(:_parent_document => root)
269
+ doc._parent_document.should be(root)
271
270
  doc._root_document.should be(root)
272
271
  end
273
272
 
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
273
+ should "set _root_document when setting _parent_document on embedded many" do
274
+ root = Doc().new
275
+ klass = EDoc { many :children }
276
+ parent = klass.new(:_parent_document => root, :children => [{}])
277
+ child = parent.children.first
278
+ child._parent_document.should be(parent)
279
+ child._root_document.should be(root)
280
280
  end
281
281
  end
282
282
 
@@ -42,25 +42,25 @@ class KeyTest < Test::Unit::TestCase
42
42
  should "symbolize option keys" do
43
43
  Key.new(:foo, Integer, 'required' => true).options[:required].should be(true)
44
44
  end
45
-
45
+
46
46
  should "work with just name" do
47
47
  key = Key.new(:foo)
48
48
  key.name.should == 'foo'
49
49
  end
50
-
50
+
51
51
  should "work with name and type" do
52
52
  key = Key.new(:foo, String)
53
53
  key.name.should == 'foo'
54
54
  key.type.should == String
55
55
  end
56
-
56
+
57
57
  should "work with name, type, and options" do
58
58
  key = Key.new(:foo, String, :required => true)
59
59
  key.name.should == 'foo'
60
60
  key.type.should == String
61
61
  key.options[:required].should be_true
62
62
  end
63
-
63
+
64
64
  should "work with name and options" do
65
65
  key = Key.new(:foo, :required => true)
66
66
  key.name.should == 'foo'
@@ -80,7 +80,7 @@ class KeyTest < Test::Unit::TestCase
80
80
  should "not be equal to another key with different type" do
81
81
  Key.new(:name, String).should_not == Key.new(:name, Integer)
82
82
  end
83
-
83
+
84
84
  should "know if it is a embedded_document" do
85
85
  Key.new(:name, EDoc()).embeddable?.should be_true
86
86
  end
@@ -88,12 +88,12 @@ class KeyTest < Test::Unit::TestCase
88
88
  should "know if it is not a embedded_document" do
89
89
  Key.new(:name, String).embeddable?.should be_false
90
90
  end
91
-
91
+
92
92
  should "know if it is a number" do
93
93
  Key.new(:age, Integer).number?.should be_true
94
94
  Key.new(:age, Float).number?.should be_true
95
95
  end
96
-
96
+
97
97
  should "know if it is not a number" do
98
98
  Key.new(:age, String).number?.should be_false
99
99
  end
@@ -110,7 +110,7 @@ class KeyTest < Test::Unit::TestCase
110
110
  key.set(FooType.new('something')).should == 'to_mongo'
111
111
  end
112
112
  end
113
-
113
+
114
114
  context "getting a value with a custom type" do
115
115
  should "use #from_mongo to convert back to custom type" do
116
116
  key = Key.new(:foo, FooType)
@@ -123,7 +123,7 @@ class KeyTest < Test::Unit::TestCase
123
123
  key = Key.new(:foo, String)
124
124
  key.get('bar').should == 'bar'
125
125
  end
126
-
126
+
127
127
  should "work without type" do
128
128
  key = Key.new(:foo)
129
129
  key.get([1, '2']).should == [1, '2']
@@ -144,7 +144,7 @@ class KeyTest < Test::Unit::TestCase
144
144
  end
145
145
  end
146
146
  end
147
-
147
+
148
148
  context "getting a value with a default set" do
149
149
  setup do
150
150
  @key = Key.new(:foo, String, :default => 'baz')
@@ -157,7 +157,7 @@ class KeyTest < Test::Unit::TestCase
157
157
  should "return value if not blank" do
158
158
  @key.get('foobar').should == 'foobar'
159
159
  end
160
-
160
+
161
161
  should "work with Boolean type and false value" do
162
162
  Key.new(:active, Boolean, :default => false).get(nil).should be_false
163
163
  end
@@ -165,5 +165,9 @@ class KeyTest < Test::Unit::TestCase
165
165
  should "work with Boolean type and true value" do
166
166
  Key.new(:active, Boolean, :default => true).get(nil).should be_true
167
167
  end
168
+
169
+ should "work with procs" do
170
+ Key.new(:foo, String, :default => lambda { return 'hello world' }).get(nil).should == "hello world"
171
+ end
168
172
  end
169
173
  end # KeyTest