mongomatic 0.3.2 → 0.4.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.
@@ -6,11 +6,25 @@ module Mongomatic
6
6
  end
7
7
 
8
8
  def to_be
9
- add_error_msg unless value
9
+ case value
10
+ when Proc
11
+ add_error_msg unless value.call
12
+ when Symbol
13
+ add_error_msg unless instance.send(value)
14
+ else
15
+ add_error_msg unless value
16
+ end
10
17
  end
11
18
 
12
19
  def to_not_be
13
- add_error_msg if value
20
+ case value
21
+ when Proc
22
+ add_error_msg if value.call
23
+ when Symbol
24
+ add_error_msg if instance.send(value)
25
+ else
26
+ add_error_msg if value
27
+ end
14
28
  end
15
29
  end
16
30
  end
@@ -80,7 +80,7 @@ module Mongomatic
80
80
  end
81
81
 
82
82
  def add_error_msg
83
- instance.errors << [message]
83
+ instance.errors << Array(message)
84
84
  end
85
85
  end
86
86
  end
@@ -2,15 +2,46 @@ module Mongomatic
2
2
  # Provides convenience methods for atomic MongoDB operations.
3
3
  module Modifiers
4
4
 
5
+ class UnexpectedFieldType < RuntimeError; end
6
+
7
+ def hash_for_field(field)
8
+ parts = field.split(".")
9
+ return [parts[0], self.doc] if parts.size == 1
10
+ field = parts.pop # last one is the field
11
+ curr_hash = self.doc
12
+ parts.each_with_index do |part, i|
13
+ curr_hash[part] ||= {}
14
+ return [field, curr_hash[part]] if parts.size == i+1
15
+ curr_hash = curr_hash[part]
16
+ end
17
+ end
18
+ private :hash_for_field
19
+
5
20
  # MongoDB equivalent: { $push : { field : value } }<br/>
6
21
  # Appends value to field, if field is an existing array, otherwise sets field to the array [value]
7
- # if field is not present. If field is present but is not an array, an error condition is raised.
8
- # user.push("interests", "skydiving")
9
- def push(field, val, do_reload=true)
10
- field = field.to_s
11
- if update({}, { "$push" => { field => val } })
12
- reload if do_reload; true
22
+ # if field is not present. If field is present but is not an array, error is returned.
23
+ def push(field, val, safe=false)
24
+ mongo_field = field.to_s
25
+ field, hash = hash_for_field(mongo_field)
26
+
27
+ unless hash[field].nil? || hash[field].is_a?(Array)
28
+ raise(UnexpectedFieldType)
13
29
  end
30
+
31
+ op = { "$push" => { mongo_field => val } }
32
+ res = true
33
+
34
+ safe == true ? res = update!({}, op) : update({}, op)
35
+
36
+ if res
37
+ hash[field] ||= []
38
+ hash[field] << val
39
+ true
40
+ end
41
+ end
42
+
43
+ def push!(field, val)
44
+ push(field, val, true)
14
45
  end
15
46
 
16
47
  # MongoDB equivalent: { $pushAll : { field : value_array } }<br/>
@@ -18,97 +49,249 @@ module Mongomatic
18
49
  # the array value_array if field is not present. If field is present but is not an array, an error
19
50
  # condition is raised.
20
51
  # user.push("interests", ["skydiving", "coding"])
21
- def push_all(field, val, do_reload=true)
22
- field = field.to_s
52
+ def push_all(field, val, safe=false)
53
+ mongo_field = field.to_s
54
+ field, hash = hash_for_field(mongo_field)
55
+
56
+ unless hash[field].nil? || hash[field].is_a?(Array)
57
+ raise(UnexpectedFieldType)
58
+ end
59
+
23
60
  val = Array(val)
24
- if update({}, { "$pushAll" => { field => val } })
25
- reload if do_reload; true
61
+ op = { "$pushAll" => { mongo_field => val } }
62
+ res = true
63
+
64
+ safe == true ? res = update!({}, op) : update({}, op)
65
+
66
+ if res
67
+ hash[field] ||= []
68
+ val.each { |v| hash[field] << v }
69
+ true
26
70
  end
27
71
  end
28
72
 
73
+ def push_all!(field, val)
74
+ push_all(field, val, true)
75
+ end
76
+
29
77
  # MongoDB equivalent: { $pull : { field : _value } }<br/>
30
78
  # Removes all occurrences of value from field, if field is an array. If field is present but is not
31
79
  # an array, an error condition is raised.
32
80
  # user.pull("interests", "watching paint dry")
33
- def pull(field, val, do_reload=true)
34
- field = field.to_s
35
- if update({}, { "$pull" => { field => val } })
36
- reload if do_reload; true
81
+ def pull(field, val, safe=false)
82
+ mongo_field = field.to_s
83
+ field, hash = hash_for_field(mongo_field)
84
+
85
+ unless hash[field].nil? || hash[field].is_a?(Array)
86
+ raise(UnexpectedFieldType)
87
+ end
88
+
89
+ op = { "$pull" => { mongo_field => val } }
90
+ res = true
91
+
92
+ safe == true ? res = update!({}, op) : update({}, op)
93
+
94
+ if res
95
+ hash[field] ||= []
96
+ hash[field].delete(val)
97
+ true
37
98
  end
38
99
  end
39
100
 
101
+ def pull!(field, val)
102
+ pull(field, val, true)
103
+ end
104
+
40
105
  # MongoDB equivalent: { $pullAll : { field : value_array } }<br/>
41
106
  # Removes all occurrences of each value in value_array from field, if field is an array. If field is
42
107
  # present but is not an array, an error condition is raised.
43
108
  # user.pull_all("interests", ["watching paint dry", "sitting on my ass"])
44
- def pull_all(field, val, do_reload=true)
45
- field = field.to_s
46
- if update({}, { "$pullAll" => { field => val } })
47
- reload if do_reload; true
109
+ def pull_all(field, val, safe=false)
110
+ mongo_field = field.to_s
111
+ field, hash = hash_for_field(mongo_field)
112
+
113
+ unless hash[field].nil? || hash[field].is_a?(Array)
114
+ raise(UnexpectedFieldType)
48
115
  end
116
+
117
+ op = { "$pullAll" => { mongo_field => Array(val) } }
118
+ res = true
119
+
120
+ safe == true ? res = update!({}, op) : update({}, op)
121
+
122
+ if res
123
+ hash[field] ||= []
124
+ Array(val).each do |v|
125
+ hash[field].delete(v)
126
+ end; true
127
+ end
128
+ end
129
+
130
+ def pull_all!(field, val)
131
+ pull_all(field, val, true)
49
132
  end
50
133
 
51
134
  # MongoDB equivalent: { $inc : { field : value } }<br/>
52
135
  # Increments field by the number value if field is present in the object, otherwise sets field to the number value.
53
136
  # user.inc("cents_in_wallet", 1000)
54
- def inc(field, val, do_reload=true)
55
- field = field.to_s
56
- if update({}, { "$inc" => { field => val } })
57
- reload if do_reload; true
137
+ def inc(field, val, safe=false)
138
+ mongo_field = field.to_s
139
+ field, hash = hash_for_field(mongo_field)
140
+
141
+ unless hash[field].nil? || ["Fixnum","Float"].include?(hash[field].class.to_s)
142
+ raise(UnexpectedFieldType)
143
+ end
144
+
145
+ op = { "$inc" => { mongo_field => val } }
146
+ res = true
147
+
148
+ safe == true ? res = update!({}, op) : update({}, op)
149
+
150
+ if res
151
+ hash[field] ||= 0
152
+ hash[field] += val
153
+ true
58
154
  end
59
155
  end
60
156
 
157
+ def inc!(field, val)
158
+ inc(field, val, true)
159
+ end
160
+
61
161
  # MongoDB equivalent: { $set : { field : value } }<br/>
62
162
  # Sets field to value. All datatypes are supported with $set.
63
163
  # user.set("name", "Ben")
64
- def set(field, val, do_reload=true)
65
- field = field.to_s
66
- if update({}, { "$set" => { field => val } })
67
- reload if do_reload; true
164
+ def set(field, val, safe=false)
165
+ mongo_field = field.to_s
166
+ field, hash = hash_for_field(field.to_s)
167
+
168
+ op = { "$set" => { mongo_field => val } }
169
+ res = true
170
+
171
+ safe == true ? res = update!({}, op) : update({}, op)
172
+
173
+ if res
174
+ hash[field] = val
175
+ true
68
176
  end
69
177
  end
178
+
179
+ def set!(field, val)
180
+ set(field, val, true)
181
+ end
70
182
 
71
183
  # MongoDB equivalent: { $unset : { field : 1} }<br/>
72
184
  # Deletes a given field. v1.3+
73
185
  # user.unset("name")
74
- def unset(field, do_reload=true)
75
- field = field.to_s
76
- if update({}, { "$unset" => { field => 1 } })
77
- reload if do_reload; true
186
+ def unset(field, safe=false)
187
+ mongo_field = field.to_s
188
+ field, hash = hash_for_field(mongo_field)
189
+
190
+ op = { "$unset" => { mongo_field => 1 } }
191
+ res = true
192
+
193
+ safe == true ? res = update!({}, op) : update({}, op)
194
+
195
+ if res
196
+ hash.delete(field)
197
+ true
78
198
  end
79
199
  end
80
200
 
201
+ def unset!(field)
202
+ unset(field, true)
203
+ end
204
+
81
205
  # MongoDB equivalent: { $addToSet : { field : value } }<br/>
82
206
  # Adds value to the array only if its not in the array already.<br/>
83
207
  # Or to add many values:<br/>
84
208
  # { $addToSet : { a : { $each : [ 3 , 5 , 6 ] } } }
85
209
  # user.add_to_set("friend_ids", BSON::ObjectID('...'))
86
- def add_to_set(field, val, do_reload=true)
87
- field = field.to_s
88
- if update({}, { "$addToSet" => { field => val } })
89
- reload if do_reload; true
210
+ def add_to_set(field, val, safe=false)
211
+ mongo_field = field.to_s
212
+ field, hash = hash_for_field(mongo_field)
213
+
214
+ unless hash[field].nil? || hash[field].is_a?(Array)
215
+ raise(UnexpectedFieldType)
216
+ end
217
+
218
+ return false if val.nil?
219
+
220
+ if val.is_a?(Array)
221
+ op = { "$addToSet" => { mongo_field => { "$each" => val } } }
222
+ else
223
+ op = { "$addToSet" => { mongo_field => val } }
224
+ end
225
+
226
+ res = true
227
+ safe == true ? res = update!({}, op) : update({}, op)
228
+
229
+ if res
230
+ hash[field] ||= []
231
+ Array(val).each do |v|
232
+ hash[field] << v unless hash[field].include?(v)
233
+ end
234
+ true
90
235
  end
91
236
  end
92
237
 
238
+ def add_to_set!(field, val)
239
+ add_to_set(field, val, true)
240
+ end
241
+
93
242
  # MongoDB equivalent: { $pop : { field : 1 } }<br/>
94
243
  # Removes the last element in an array (ADDED in 1.1)
95
244
  # user.pop_last("friend_ids")
96
- def pop_last(field, do_reload=true)
97
- field = field.to_s
98
- if update({}, { "$pop" => { field => 1 } })
99
- reload if do_reload; true
245
+ def pop_last(field, safe=false)
246
+ mongo_field = field.to_s
247
+ field, hash = hash_for_field(mongo_field)
248
+
249
+ unless hash[field].nil? || hash[field].is_a?(Array)
250
+ raise(UnexpectedFieldType)
100
251
  end
252
+
253
+ op = { "$pop" => { mongo_field => 1 } }
254
+
255
+ res = true
256
+ safe == true ? res = update!({}, op) : update({}, op)
257
+
258
+ if res
259
+ hash[field] ||= []
260
+ hash[field].pop
261
+ true
262
+ end
263
+ end
264
+
265
+ def pop_last!(field)
266
+ pop_last(field, true)
101
267
  end
102
268
 
103
269
  # MongoDB equivalent: { $pop : { field : -1 } }<br/>
104
270
  # Removes the first element in an array (ADDED in 1.1)
105
271
  # user.pop_first("friend_ids")
106
- def pop_first(field, do_reload=true)
107
- field = field.to_s
108
- if update({}, { "$pop" => { field => -1 } })
109
- reload if do_reload; true
272
+ def pop_first(field, safe=false)
273
+ mongo_field = field.to_s
274
+ field, hash = hash_for_field(mongo_field)
275
+
276
+ unless hash[field].nil? || hash[field].is_a?(Array)
277
+ raise(UnexpectedFieldType)
278
+ end
279
+
280
+ op = { "$pop" => { mongo_field => -1 } }
281
+
282
+ res = true
283
+ safe == true ? res = update!({}, op) : update({}, op)
284
+
285
+ if res
286
+ hash[field] ||= []
287
+ hash[field].shift
288
+ true
110
289
  end
111
290
  end
112
291
 
292
+ def pop_first!(field)
293
+ pop_first(field, true)
294
+ end
295
+
113
296
  end
114
297
  end
@@ -0,0 +1,253 @@
1
+ require 'helper'
2
+
3
+ class TestModifiers < Test::Unit::TestCase
4
+ def setup
5
+ Person.collection.drop
6
+ end
7
+
8
+ should "be able to push" do
9
+ p1 = Person.new(:name => "Jordan")
10
+ p1.insert
11
+ assert p1.push("interests", "skydiving")
12
+ assert p1["interests"].include?("skydiving")
13
+ p1 = Person.find_one(p1["_id"])
14
+ assert p1["interests"].include?("skydiving")
15
+ assert p1.push!("interests", "coding")
16
+ assert p1["interests"].include?("coding")
17
+ p1 = Person.find_one(p1["_id"])
18
+ assert_equal ["skydiving","coding"], p1["interests"]
19
+
20
+ p1["interests"] = "foo"
21
+ assert_raise(Mongomatic::Modifiers::UnexpectedFieldType) { p1.push("interests", "snowboarding") }
22
+ end
23
+
24
+ should "be able to push on a field in an embedded hash" do
25
+ p1 = Person.new(:name => "Jordan")
26
+ p1.insert
27
+ assert p1.push!("personal.interests", "skydiving")
28
+ assert_equal ["skydiving"], p1["personal"]["interests"]
29
+ p1 = Person.find_one(p1["_id"])
30
+ assert_equal ["skydiving"], p1["personal"]["interests"]
31
+ end
32
+
33
+ should "be able to push_all" do
34
+ p1 = Person.new(:name => "Jordan")
35
+ p1.insert
36
+ assert p1.push("interests", "skydiving")
37
+ assert p1["interests"].include?("skydiving")
38
+ p1 = Person.find_one(p1["_id"])
39
+ assert p1["interests"].include?("skydiving")
40
+
41
+ assert p1.push_all!("interests", ["coding","running","snowboarding","reading"])
42
+ assert_equal ["skydiving","coding","running","snowboarding","reading"], p1["interests"]
43
+ p1 = Person.find_one(p1["_id"])
44
+ assert_equal ["skydiving","coding","running","snowboarding","reading"], p1["interests"]
45
+
46
+ p1["interests"] = "foo"
47
+ assert_raise(Mongomatic::Modifiers::UnexpectedFieldType) { p1.push_all("interests", ["snowboarding"]) }
48
+ end
49
+
50
+ should "be able to push_all on a field in an embedded hash" do
51
+ p1 = Person.new(:name => "Jordan")
52
+ p1.insert
53
+ p1.push_all!("contacts.coworkers", ["Chris","Keith","Jordan","Mike"])
54
+ assert_equal ["Chris","Keith","Jordan","Mike"], p1["contacts"]["coworkers"]
55
+ p1 = Person.find_one(p1["_id"])
56
+ assert_equal ["Chris","Keith","Jordan","Mike"], p1["contacts"]["coworkers"]
57
+ end
58
+
59
+ should "be able to pull" do
60
+ p1 = Person.new(:name => "Jordan")
61
+ p1.insert
62
+ assert p1.push("interests", "skydiving")
63
+ assert p1.push_all!("interests", ["coding","running","snowboarding","reading"])
64
+ p1 = Person.find_one(p1["_id"])
65
+ assert_equal ["skydiving","coding","running","snowboarding","reading"], p1["interests"]
66
+ assert p1.pull!("interests", "running")
67
+ assert_equal ["skydiving","coding","snowboarding","reading"], p1["interests"]
68
+ p1 = Person.find_one(p1["_id"])
69
+ assert_equal ["skydiving","coding","snowboarding","reading"], p1["interests"]
70
+
71
+ p1["interests"] = "foo"
72
+ assert_raise(Mongomatic::Modifiers::UnexpectedFieldType) { p1.pull("interests", ["snowboarding"]) }
73
+ end
74
+
75
+ should "be able to pull on a field in an embedded hash" do
76
+ p1 = Person.new(:name => "Jordan")
77
+ p1.insert!
78
+ p1.push_all!("contacts.coworkers", ["Chris","Keith","Jordan","Mike","Joe"])
79
+ assert_equal ["Chris","Keith","Jordan","Mike","Joe"], p1["contacts"]["coworkers"]
80
+ p1.pull!("contacts.coworkers", "Joe")
81
+ assert_equal ["Chris","Keith","Jordan","Mike"], p1["contacts"]["coworkers"]
82
+ p1 = Person.find_one(p1["_id"])
83
+ assert_equal ["Chris","Keith","Jordan","Mike"], p1["contacts"]["coworkers"]
84
+ end
85
+
86
+ should "be able to pull_all" do
87
+ p1 = Person.new(:name => "Jordan")
88
+ p1.insert
89
+ assert p1.push_all!("interests", ["skydiving", "coding","running","snowboarding","reading"])
90
+ p1 = Person.find_one(p1["_id"])
91
+ assert_equal ["skydiving","coding","running","snowboarding","reading"], p1["interests"]
92
+ p1.pull_all!("interests", ["running", "snowboarding"])
93
+ assert_equal ["skydiving", "coding","reading"], p1["interests"]
94
+ p1 = Person.find_one(p1["_id"])
95
+ assert_equal ["skydiving", "coding","reading"], p1["interests"]
96
+
97
+ p1["interests"] = "foo"
98
+ assert_raise(Mongomatic::Modifiers::UnexpectedFieldType) { p1.pull_all("interests", ["snowboarding"]) }
99
+ end
100
+
101
+ should "be able to pull_all on a field in an embedded hash" do
102
+ p1 = Person.new(:name => "Jordan")
103
+ p1.insert!
104
+ p1.push_all!("contacts.coworkers", ["Chris","Jim","Keith","Jordan","Mike","Joe"])
105
+ assert_equal ["Chris","Jim","Keith","Jordan","Mike","Joe"], p1["contacts"]["coworkers"]
106
+ p1.pull_all!("contacts.coworkers", ["Joe","Jim"])
107
+ assert_equal ["Chris","Keith","Jordan","Mike"], p1["contacts"]["coworkers"]
108
+ p1 = Person.find_one(p1["_id"])
109
+ assert_equal ["Chris","Keith","Jordan","Mike"], p1["contacts"]["coworkers"]
110
+ end
111
+
112
+ should "be able to inc" do
113
+ p1 = Person.new(:name => "Jordan")
114
+ assert p1.insert!
115
+ p1["count1"] = 5
116
+ assert p1.update!
117
+ assert p1.inc!("count1", 3)
118
+ assert p1.inc!("count2", -4)
119
+ assert_equal 8, p1["count1"]
120
+ assert_equal -4, p1["count2"]
121
+ p1 = Person.find_one(p1["_id"])
122
+ assert_equal 8, p1["count1"]
123
+ assert_equal -4, p1["count2"]
124
+ end
125
+
126
+ should "be able to inc a field in an embedded hash" do
127
+ p1 = Person.new(:name => "Jordan")
128
+ assert p1.insert!
129
+ p1.inc!("counters.visitors", 10)
130
+ p1.inc!("level1.level2.level3.counter", 20)
131
+ assert_equal 10, p1["counters"]["visitors"]
132
+ assert_equal 20, p1["level1"]["level2"]["level3"]["counter"]
133
+ p1 = Person.find_one(p1["_id"])
134
+ assert_equal 10, p1["counters"]["visitors"]
135
+ assert_equal 20, p1["level1"]["level2"]["level3"]["counter"]
136
+ end
137
+
138
+ should "be able to set" do
139
+ p1 = Person.new(:name => "Jordan")
140
+ assert p1.insert!
141
+ assert p1.set!("foo", "bar")
142
+ assert_equal "bar", p1["foo"]
143
+ p1 = Person.find_one(p1["_id"])
144
+ assert_equal "bar", p1["foo"]
145
+ end
146
+
147
+ should "be able to set a field in an embedded hash" do
148
+ p1 = Person.new(:name => "Jordan")
149
+ assert p1.insert!
150
+ p1.set!("l1.l2.l3.l4.name", "Ben")
151
+ assert_equal "Ben", p1["l1"]["l2"]["l3"]["l4"]["name"]
152
+ p1 = Person.find_one(p1["_id"])
153
+ assert_equal "Ben", p1["l1"]["l2"]["l3"]["l4"]["name"]
154
+ end
155
+
156
+ should "be able to unset" do
157
+ p1 = Person.new(:name => "Jordan")
158
+ assert p1.insert!
159
+ assert p1.set!("foo", "bar")
160
+ assert_equal "bar", p1["foo"]
161
+ p1 = Person.find_one(p1["_id"])
162
+ assert_equal "bar", p1["foo"]
163
+
164
+ assert p1.unset!("foo")
165
+ assert p1["foo"].nil?
166
+ p1 = Person.find_one(p1["_id"])
167
+ assert p1["foo"].nil?
168
+ end
169
+
170
+ should "be able to unset a field in an embedded hash" do
171
+ p1 = Person.new(:name => "Jordan")
172
+ assert p1.insert!
173
+ p1.set!("l1.l2.l3.l4.name", "Ben")
174
+ assert_equal "Ben", p1["l1"]["l2"]["l3"]["l4"]["name"]
175
+ p1 = Person.find_one(p1["_id"])
176
+ assert_equal "Ben", p1["l1"]["l2"]["l3"]["l4"]["name"]
177
+ assert p1["l1"]["l2"]["l3"]["l4"].has_key?("name")
178
+
179
+ p1.unset!("l1.l2.l3.l4.name")
180
+ assert_equal nil, p1["l1"]["l2"]["l3"]["l4"]["name"]
181
+ assert !p1["l1"]["l2"]["l3"]["l4"].has_key?("name")
182
+
183
+ p1 = Person.find_one(p1["_id"])
184
+ assert_equal nil, p1["l1"]["l2"]["l3"]["l4"]["name"]
185
+ assert !p1["l1"]["l2"]["l3"]["l4"].has_key?("name")
186
+ end
187
+
188
+ should "be able to add_to_set" do
189
+ p1 = Person.new(:name => "Jordan")
190
+ assert p1.insert!
191
+
192
+ assert p1.add_to_set!("hot_colors", "red")
193
+ assert p1.add_to_set!("cold_colors", ["grey","blue"])
194
+
195
+ assert_equal ["red"], p1["hot_colors"]
196
+ assert_equal ["grey","blue"], p1["cold_colors"]
197
+
198
+ p1 = Person.find_one(p1["_id"])
199
+
200
+ assert_equal ["red"], p1["hot_colors"]
201
+ assert_equal ["grey","blue"], p1["cold_colors"]
202
+ end
203
+
204
+ should "be able to add_to_set in an embedded hash" do
205
+ p1 = Person.new(:name => "Jordan")
206
+ assert p1.insert!
207
+ p1.add_to_set!("colors.hot", ["red", "pink", "orange"])
208
+ assert_equal ["red", "pink", "orange"], p1["colors"]["hot"]
209
+ p1 = Person.find_one(p1["_id"])
210
+ assert_equal ["red", "pink", "orange"], p1["colors"]["hot"]
211
+ end
212
+
213
+ should "be able to pop_last" do
214
+ p1 = Person.new(:name => "Jordan")
215
+ p1["numbers"] = [1,2,3,4,5]
216
+ assert p1.insert!
217
+ p1.pop_last!("numbers")
218
+ assert_equal [1,2,3,4], p1["numbers"]
219
+ p1 = Person.find_one(p1["_id"])
220
+ assert_equal [1,2,3,4], p1["numbers"]
221
+ end
222
+
223
+ should "be able to pop_last in an embedded doc" do
224
+ p1 = Person.new(:name => "Jordan")
225
+ p1["stats"] = { "numbers" => [1,2,3,4,5] }
226
+ assert p1.insert!
227
+ p1.pop_last!("stats.numbers")
228
+ assert_equal [1,2,3,4], p1["stats"]["numbers"]
229
+ p1 = Person.find_one(p1["_id"])
230
+ assert_equal [1,2,3,4], p1["stats"]["numbers"]
231
+ end
232
+
233
+ should "be able to pop_first" do
234
+ p1 = Person.new(:name => "Jordan")
235
+ p1["numbers"] = [1,2,3,4,5]
236
+ assert p1.insert!
237
+ p1.pop_first!("numbers")
238
+ assert_equal [2,3,4,5], p1["numbers"]
239
+ p1 = Person.find_one(p1["_id"])
240
+ assert_equal [2,3,4,5], p1["numbers"]
241
+ end
242
+
243
+ should "be able to pop_first in an embedded doc" do
244
+ p1 = Person.new(:name => "Jordan")
245
+ p1["stats"] = { "numbers" => [1,2,3,4,5] }
246
+ assert p1.insert!
247
+ p1.pop_first!("stats.numbers")
248
+ assert_equal [2,3,4,5], p1["stats"]["numbers"]
249
+ p1 = Person.find_one(p1["_id"])
250
+ assert_equal [2,3,4,5], p1["stats"]["numbers"]
251
+ end
252
+
253
+ end
@@ -251,6 +251,60 @@ class TestMongomatic < Test::Unit::TestCase
251
251
  assert_equal ['Dead must be false'], p.errors.full_messages
252
252
  end
253
253
 
254
+ should "be able to use be_expected with a block" do
255
+ p = Person.new
256
+ class << p
257
+ def validate
258
+ expectations do
259
+ be_expected lambda { self['name'].is_a? String }, "Name must be a string"
260
+ not_be_expected lambda { self['alive'] && self['dead'] }, "Cannot be alive and dead"
261
+ end
262
+ end
263
+ end
264
+
265
+ p['name'] = 1
266
+ assert !p.valid?
267
+ assert_equal p.errors.full_messages, ["Name must be a string"]
268
+
269
+ p['alive'] = true
270
+ p['dead'] = true
271
+ p['name'] = "Jordan"
272
+
273
+ assert !p.valid?
274
+ assert_equal p.errors.full_messages, ["Cannot be alive and dead"]
275
+
276
+ p['dead'] = false
277
+ assert p.valid?
278
+ end
279
+
280
+ should "be able to use be_expected with a method call" do
281
+ p = Person.new
282
+ class << p
283
+ def validate
284
+ expectations do
285
+ be_expected :method_1, "Method 1 must return true"
286
+ not_be_expected :method_2, "Method 2 must return false"
287
+ end
288
+ end
289
+
290
+ def method_1
291
+ (self['name'] == 'Jordan') ? true : false
292
+ end
293
+
294
+ def method_2
295
+ (self['age'] == 21) ? false : true
296
+ end
297
+ end
298
+
299
+ assert !p.valid?
300
+ assert_equal ["Method 1 must return true", "Method 2 must return false"], p.errors.full_messages
301
+
302
+ p['name'] = 'Jordan'
303
+ p['age'] = 21
304
+
305
+ assert p.valid?
306
+ end
307
+
254
308
  should "be able to use the be_present expectation" do
255
309
  p = Person.new
256
310
  class << p
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 3
8
- - 2
9
- version: 0.3.2
7
+ - 4
8
+ - 1
9
+ version: 0.4.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Ben Myles
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-08-19 00:00:00 -07:00
17
+ date: 2010-08-24 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -116,6 +116,7 @@ files:
116
116
  - LICENSE
117
117
  - README.rdoc
118
118
  - test/helper.rb
119
+ - test/test_modifiers.rb
119
120
  - test/test_mongomatic.rb
120
121
  has_rdoc: true
121
122
  homepage: http://mongomatic.com/
@@ -151,4 +152,5 @@ specification_version: 3
151
152
  summary: Mongomatic is a simple Ruby object mapper for Mongo
152
153
  test_files:
153
154
  - test/helper.rb
155
+ - test/test_modifiers.rb
154
156
  - test/test_mongomatic.rb