mongo_mapper 0.7.0 → 0.7.1

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