rs_voteable_mongo 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,436 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Mongo::Voteable do
4
+
5
+ context 'when :index is passed as an argument' do
6
+ before do
7
+ Post.remove_indexes
8
+ Category.remove_indexes
9
+
10
+ Post.create_voteable_indexes
11
+ Category.create_voteable_indexes
12
+ end
13
+
14
+ it 'defines indexes' do
15
+ [Post, Category].each do |klass|
16
+ [ {'votes.up' => 1, '_id' => 1},
17
+ {'votes.down' => 1, '_id' => 1},
18
+ ].each { |index_key|
19
+ klass.collection.indexes[index_key].should_not be_nil
20
+ klass.collection.indexes[index_key]['unique'].should be_true
21
+ }
22
+
23
+ [ {'votes.count' => -1},
24
+ {'votes.up_count' => -1},
25
+ {'votes.down_count' => -1},
26
+ {'votes.point' => -1},
27
+ ].each { |index_key|
28
+ klass.collection.indexes[index_key].should_not be_nil
29
+ }
30
+ end
31
+ end
32
+ end
33
+
34
+ before :all do
35
+ Category.destroy_all
36
+ @category1 = Category.create!(:name => 'xyz')
37
+ @category2 = Category.create!(:name => 'abc')
38
+ Post.destroy_all
39
+ @post1 = Post.create!(:title => 'post1')
40
+ @post2 = Post.create!(:title => 'post2')
41
+
42
+ @post1.category_ids = [@category1.id, @category2.id]
43
+ @post1.save!
44
+
45
+ @comment = @post2.comments.create!
46
+
47
+ @user1 = User.create!
48
+ @user2 = User.create!
49
+ end
50
+
51
+ it "vote for unexisting post" do
52
+ object_id = defined?(Moped::BSON) ? Moped::BSON::ObjectId : BSON::ObjectId
53
+ @user1.vote(:votee_class => Post, :votee_id => object_id.new, :value => :up).should == false
54
+ end
55
+
56
+ context "just created" do
57
+ it 'votes_count, up_votes_count, down_votes_count, votes_point should be zero' do
58
+ @category1.up_votes_count.should == 0
59
+ @category1.down_votes_count.should == 0
60
+ @category1.votes_count.should == 0
61
+ @category1.votes_point.should == 0
62
+
63
+ @category2.up_votes_count.should == 0
64
+ @category2.down_votes_count.should == 0
65
+ @category2.votes_count.should == 0
66
+ @category2.votes_point.should == 0
67
+
68
+ @post1.up_votes_count.should == 0
69
+ @post1.down_votes_count.should == 0
70
+ @post1.votes_count.should == 0
71
+ @post1.votes_point.should == 0
72
+
73
+ @post2.up_votes_count.should == 0
74
+ @post2.down_votes_count.should == 0
75
+ @post2.votes_count.should == 0
76
+ @post2.votes_point.should == 0
77
+
78
+ @comment.up_votes_count.should == 0
79
+ @comment.down_votes_count.should == 0
80
+ @comment.votes_count.should == 0
81
+ @comment.votes_point.should == 0
82
+ end
83
+
84
+ it 'up_voter_ids, down_voter_ids should be empty' do
85
+ @category1.up_voter_ids.should be_empty
86
+ @category1.down_voter_ids.should be_empty
87
+
88
+ @category2.up_voter_ids.should be_empty
89
+ @category2.down_voter_ids.should be_empty
90
+
91
+ @post1.up_voter_ids.should be_empty
92
+ @post1.down_voter_ids.should be_empty
93
+
94
+ @post2.up_voter_ids.should be_empty
95
+ @post2.down_voter_ids.should be_empty
96
+
97
+ @comment.up_voter_ids.should be_empty
98
+ @comment.down_voter_ids.should be_empty
99
+ end
100
+
101
+ it 'voted by voter should be empty' do
102
+ Category.voted_by(@user1).should be_empty
103
+ Category.voted_by(@user2).should be_empty
104
+
105
+ Post.voted_by(@user1).should be_empty
106
+ Post.voted_by(@user2).should be_empty
107
+
108
+ Comment.voted_by(@user1).should be_empty
109
+ Comment.voted_by(@user2).should be_empty
110
+ end
111
+
112
+ it 'revote post1 has no effect' do
113
+ @post1.vote(:revote => true, :voter => @user1, :value => 'up')
114
+
115
+ @post1.up_votes_count.should == 0
116
+ @post1.down_votes_count.should == 0
117
+ @post1.votes_count.should == 0
118
+ @post1.votes_point.should == 0
119
+ end
120
+
121
+ it 'revote post2 has no effect' do
122
+ Post.vote(:revote => true, :votee_id => @post2.id, :voter_id => @user2.id, :value => :down)
123
+ @post2.reload
124
+
125
+ @post2.up_votes_count.should == 0
126
+ @post2.down_votes_count.should == 0
127
+ @post2.votes_count.should == 0
128
+ @post2.votes_point.should == 0
129
+ end
130
+ end
131
+
132
+ context 'user1 vote up post1 the first time' do
133
+ before :all do
134
+ @post = @post1.vote(:voter_id => @user1.id, :value => :up)
135
+ end
136
+
137
+ it 'validates return post' do
138
+ @post.should be_is_a Post
139
+ @post.should_not be_new_record
140
+
141
+ @post.votes.should == {
142
+ 'up' => [@user1.id],
143
+ 'down' => [],
144
+ 'up_count' => 1,
145
+ 'down_count' => 0,
146
+ 'count' => 1,
147
+ 'point' => 1
148
+ }
149
+ end
150
+
151
+ it 'validates' do
152
+ @post1.up_votes_count.should == 1
153
+ @post1.down_votes_count.should == 0
154
+ @post1.votes_count.should == 1
155
+ @post1.votes_point.should == 1
156
+
157
+ @post1.vote_value(@user1).should == :up
158
+ @post1.should be_voted_by(@user1)
159
+ @post1.vote_value(@user2.id).should be_nil
160
+ @post1.should_not be_voted_by(@user2.id)
161
+
162
+ @post1.up_voters(User).to_a.should == [ @user1 ]
163
+ @post1.voters(User).to_a.should == [ @user1 ]
164
+ @post1.down_voters(User).should be_empty
165
+
166
+ Post.voted_by(@user1).to_a.should == [ @post1 ]
167
+ Post.voted_by(@user2).to_a.should be_empty
168
+
169
+ @category1.reload
170
+ @category1.up_votes_count.should == 0
171
+ @category1.down_votes_count.should == 0
172
+ @category1.votes_count.should == 0
173
+ @category1.votes_point.should == 3
174
+
175
+ @category2.reload
176
+ @category2.up_votes_count.should == 0
177
+ @category2.down_votes_count.should == 0
178
+ @category2.votes_count.should == 0
179
+ @category2.votes_point.should == 3
180
+ end
181
+
182
+ it 'user1 vote post1 has no effect' do
183
+ Post.vote(:revote => false, :votee_id => @post1.id, :voter_id => @user1.id, :value => :up)
184
+ @post1.reload
185
+
186
+ @post1.up_votes_count.should == 1
187
+ @post1.down_votes_count.should == 0
188
+ @post1.votes_count.should == 1
189
+ @post1.votes_point.should == 1
190
+
191
+ @post1.vote_value(@user1.id).should == :up
192
+ end
193
+ end
194
+
195
+ context 'user2 vote down post1 the first time' do
196
+ before :all do
197
+ Post.vote(:votee_id => @post1.id, :voter_id => @user2.id, :value => :down)
198
+ @post1.reload
199
+ end
200
+
201
+ it 'post1 up_votes_count is the same' do
202
+ @post1.up_votes_count.should == 1
203
+ end
204
+
205
+ it 'post1 vote_value on user1 is the same' do
206
+ @post1.vote_value(@user1.id).should == :up
207
+ end
208
+
209
+ it 'down_votes_count, votes_count, and votes_point changed' do
210
+ @post1.down_votes_count.should == 1
211
+ @post1.votes_count.should == 2
212
+ @post1.votes_point.should == 0
213
+ @post1.vote_value(@user2.id).should == :down
214
+ end
215
+
216
+ it 'post1 get voters' do
217
+ @post1.up_voters(User).to_a.should == [ @user1 ]
218
+ @post1.down_voters(User).to_a.should == [ @user2 ]
219
+ @post1.voters(User).to_a.should == [ @user1, @user2 ]
220
+ end
221
+
222
+ it 'posts voted_by user1, user2 is post1 only' do
223
+ Post.voted_by(@user1).to_a.should == [ @post1 ]
224
+ Post.voted_by(@user2).to_a.should == [ @post1 ]
225
+ end
226
+
227
+ it 'categories votes' do
228
+ @category1.reload
229
+ @category1.up_votes_count.should == 0
230
+ @category1.down_votes_count.should == 0
231
+ @category1.votes_count.should == 0
232
+ @category1.votes_point.should == -2
233
+
234
+ @category2.reload
235
+ @category2.up_votes_count.should == 0
236
+ @category2.down_votes_count.should == 0
237
+ @category2.votes_count.should == 0
238
+ @category2.votes_point.should == -2
239
+ end
240
+ end
241
+
242
+ context 'user1 change vote on post1 from up to down' do
243
+ before :all do
244
+ Post.vote(:revote => true, :votee_id => @post1.id, :voter_id => @user1.id, :value => :down)
245
+ Mongo::Voteable::Tasks.remake_stats
246
+ @post1.reload
247
+ end
248
+
249
+ it 'validates' do
250
+ @post1.up_votes_count.should == 0
251
+ @post1.down_votes_count.should == 2
252
+ @post1.votes_count.should == 2
253
+ @post1.votes_point.should == -2
254
+
255
+ @post1.vote_value(@user1.id).should == :down
256
+ @post1.vote_value(@user2.id).should == :down
257
+
258
+ Post.voted_by(@user1).to_a.should == [ @post1 ]
259
+ Post.voted_by(@user2).to_a.should == [ @post1 ]
260
+ end
261
+ end
262
+
263
+ context 'user1 vote down post2 the first time' do
264
+ before :all do
265
+ @post2.vote(:voter_id => @user1.id, :value => :down)
266
+ end
267
+
268
+ it 'validates' do
269
+ @post2.up_votes_count.should == 0
270
+ @post2.down_votes_count.should == 1
271
+ @post2.votes_count.should == 1
272
+ @post2.votes_point.should == -1
273
+
274
+ @post2.vote_value(@user1.id).should == :down
275
+ @post2.vote_value(@user2.id).should be_nil
276
+
277
+ Post.voted_by(@user1).to_a.should == [ @post1, @post2 ]
278
+ end
279
+ end
280
+
281
+ context 'user1 change vote on post2 from down to up' do
282
+ before :all do
283
+ Post.vote(:revote => true, :votee_id => @post2.id.to_s, :voter_id => @user1.id.to_s, :value => :up)
284
+ Mongo::Voteable::Tasks.remake_stats
285
+ @post2.reload
286
+ end
287
+
288
+ it 'validates' do
289
+ @post2.up_votes_count.should == 1
290
+ @post2.down_votes_count.should == 0
291
+ @post2.votes_count.should == 1
292
+ @post2.votes_point.should == 1
293
+
294
+ @post2.vote_value(@user1.id).should == :up
295
+ @post2.vote_value(@user2.id).should be_nil
296
+
297
+ Post.voted_by(@user1).size.should == 2
298
+ Post.voted_by(@user1).should be_include @post1
299
+ Post.voted_by(@user1).should be_include @post2
300
+ end
301
+ end
302
+
303
+
304
+ context 'user1 vote up post2 comment the first time' do
305
+ before :all do
306
+ @comment.vote(:voter_id => @user1.id, :value => :up)
307
+ @comment.reload
308
+ @post2.reload
309
+ end
310
+
311
+ it 'validates' do
312
+ @post2.up_votes_count.should == 2
313
+ @post2.down_votes_count.should == 0
314
+ @post2.votes_count.should == 2
315
+ @post2.votes_point.should == 3
316
+
317
+ @comment.up_votes_count.should == 1
318
+ @comment.down_votes_count.should == 0
319
+ @comment.votes_count.should == 1
320
+ @comment.votes_point.should == 1
321
+ end
322
+ end
323
+
324
+
325
+ context 'user1 revote post2 comment from up to down' do
326
+ before :all do
327
+ @user1.vote(:votee => @comment, :value => :down)
328
+ @comment.reload
329
+ @post2.reload
330
+ end
331
+
332
+ it 'validates' do
333
+ @post2.up_votes_count.should == 1
334
+ @post2.down_votes_count.should == 1
335
+ @post2.votes_count.should == 2
336
+ @post2.votes_point.should == 0
337
+
338
+ @comment.up_votes_count.should == 0
339
+ @comment.down_votes_count.should == 1
340
+ @comment.votes_count.should == 1
341
+ @comment.votes_point.should == -3
342
+ end
343
+
344
+ it 'revote with wrong value has no effect' do
345
+ @user1.vote(:votee => @comment, :value => :down)
346
+
347
+ @post2.up_votes_count.should == 1
348
+ @post2.down_votes_count.should == 1
349
+ @post2.votes_count.should == 2
350
+ @post2.votes_point.should == 0
351
+
352
+ @comment.up_votes_count.should == 0
353
+ @comment.down_votes_count.should == 1
354
+ @comment.votes_count.should == 1
355
+ @comment.votes_point.should == -3
356
+ end
357
+ end
358
+
359
+ context "user1 unvote on post1" do
360
+ before(:all) do
361
+ @post1.vote(:voter_id => @user1.id, :votee_id => @post1.id, :unvote => true)
362
+ Mongo::Voteable::Tasks.remake_stats
363
+ @post1.reload
364
+ end
365
+
366
+ it 'validates' do
367
+ @post1.up_votes_count.should == 0
368
+ @post1.down_votes_count.should == 1
369
+ @post1.votes_count.should == 1
370
+ @post1.votes_point.should == -1
371
+
372
+ @post1.vote_value(@user1.id).should be_nil
373
+ @post1.vote_value(@user2.id).should == :down
374
+
375
+ Post.voted_by(@user1).to_a.should_not include(@post1)
376
+ end
377
+ end
378
+
379
+ context "@post1 has 1 down vote and -1 point, @post2 has 1 up vote, 1 down vote and 0 point" do
380
+ it "verify @post1 counters" do
381
+ @post1.up_votes_count.should == 0
382
+ @post1.down_votes_count.should == 1
383
+ @post1.votes_count.should == 1
384
+ @post1.votes_point.should == -1
385
+ end
386
+
387
+ it "verify @post2 counters" do
388
+ @post2.up_votes_count.should == 1
389
+ @post2.down_votes_count.should == 1
390
+ @post2.votes_count.should == 2
391
+ @post2.votes_point.should == 0
392
+ end
393
+ end
394
+
395
+ context "user1 unvote on comment" do
396
+ before(:all) do
397
+ @user1.unvote(@comment)
398
+ Mongo::Voteable::Tasks.remake_stats
399
+ @comment.reload
400
+ @post2.reload
401
+ end
402
+
403
+ it "" do
404
+ @comment.up_votes_count.should == 0
405
+ @comment.down_votes_count.should == 0
406
+ @comment.votes_count.should == 0
407
+ @comment.votes_point.should == 0
408
+
409
+ @post2.up_votes_count.should == 1
410
+ @post2.down_votes_count.should == 0
411
+ @post2.votes_count.should == 1
412
+ @post2.votes_point.should == 1
413
+ end
414
+ end
415
+
416
+ context 'final' do
417
+ it "test remake stats" do
418
+ Mongo::Voteable::Tasks.remake_stats
419
+
420
+ @post1.up_votes_count.should == 0
421
+ @post1.down_votes_count.should == 1
422
+ @post1.votes_count.should == 1
423
+ @post1.votes_point.should == -1
424
+
425
+ @post2.up_votes_count.should == 1
426
+ @post2.down_votes_count.should == 0
427
+ @post2.votes_count.should == 1
428
+ @post2.votes_point.should == 1
429
+
430
+ @comment.up_votes_count.should == 0
431
+ @comment.down_votes_count.should == 0
432
+ @comment.votes_count.should == 0
433
+ @comment.votes_point.should == 0
434
+ end
435
+ end
436
+ end
@@ -0,0 +1,150 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Mongo::Voter do
4
+ before :all do
5
+ @post1 = Post.create!(:title => 'post_1')
6
+ @post2 = Post.create!(:title => 'post_2')
7
+
8
+ @user1 = User.create!
9
+ @user2 = User.create!
10
+ end
11
+
12
+ context "just created" do
13
+ it 'validates' do
14
+ Post.voted_by(@user1).should be_empty
15
+ Post.up_voted_by(@user1).should be_empty
16
+ Post.down_voted_by(@user1).should be_empty
17
+ @user1.voted?(@post1).should be_false
18
+ @user1.voted?(@post2).should be_false
19
+
20
+ Post.voted_by(@user2).should be_empty
21
+ Post.up_voted_by(@user2).should be_empty
22
+ Post.down_voted_by(@user2).should be_empty
23
+ @user2.voted?(@post1).should be_false
24
+ @user2.voted?(@post2).should be_false
25
+ end
26
+
27
+ it 'revote has no effect' do
28
+ @user2.vote(:revote => true, :votee => @post2, :value => :down)
29
+ @post2.reload
30
+
31
+ @post2.votes_count.should == 0
32
+ @post2.votes_point.should == 0
33
+ end
34
+ end
35
+
36
+ context 'user1 vote up post1 the first time' do
37
+ before :all do
38
+ @user1.vote(:revote => '', :votee_id => @post1.id, :votee_class => Post, :value => :up)
39
+ @post1.reload
40
+ end
41
+
42
+ it 'validates' do
43
+ @post1.votes_count.should == 1
44
+ @post1.votes_point.should == 1
45
+
46
+ @user1.vote_value(@post1).should == :up
47
+ @user2.vote_value(:votee_class => Post, :votee_id => @post1.id).should be_nil
48
+
49
+ @user1.should be_voted(@post1)
50
+ @user2.should_not be_voted(:votee_class => Post, :votee_id => @post1.id)
51
+
52
+ Post.voted_by(@user1).to_a.should == [ @post1 ]
53
+ Post.up_voted_by(@user1).to_a.should == [ @post1 ]
54
+ Post.down_voted_by(@user1).to_a.should be_empty
55
+ Post.voted_by(@user2).to_a.should be_empty
56
+
57
+ User.up_voted_for(@post1).to_a.should == [ @user1 ]
58
+ User.down_voted_for(@post1).to_a.should be_empty
59
+ User.voted_for(@post1).to_a.should == [ @user1 ]
60
+ end
61
+
62
+ it 'user1 vote post1 has no effect' do
63
+ @user1.vote(:votee => @post1, :value => :up)
64
+ @post1.reload
65
+
66
+ @post1.votes_count.should == 1
67
+ @post1.votes_point.should == 1
68
+
69
+ @post1.vote_value(@user1.id).should == :up
70
+ end
71
+ end
72
+
73
+ context 'user2 vote down post1 the first time' do
74
+ before :all do
75
+ @user2.vote(:votee => @post1, :value => :down)
76
+ @post1.reload
77
+ end
78
+
79
+ it 'validates' do
80
+ @post1.votes_count.should == 2
81
+ @post1.votes_point.should == 0
82
+
83
+ @user1.vote_value(@post1).should == :up
84
+ @user2.vote_value(@post1).should == :down
85
+
86
+ Post.voted_by(@user1).to_a.should == [ @post1 ]
87
+ Post.voted_by(@user2).to_a.should == [ @post1 ]
88
+ Post.up_voted_by(@user2).to_a.should be_empty
89
+ Post.down_voted_by(@user2).to_a.should == [ @post1 ]
90
+
91
+ User.up_voted_for(@post1).to_a.should == [ @user1 ]
92
+ User.down_voted_for(@post1).to_a.should == [ @user2 ]
93
+ User.voted_for(@post1).to_a.should == [ @user1, @user2 ]
94
+ end
95
+ end
96
+
97
+ context 'user1 change vote on post1 from up to down' do
98
+ before :all do
99
+ @user1.vote(:votee => @post1, :value => :down)
100
+ @post1.reload
101
+ end
102
+
103
+ it 'validates' do
104
+ @post1.votes_count.should == 2
105
+ @post1.votes_point.should == -2
106
+
107
+ @user1.vote_value(@post1).should == :down
108
+ @user2.vote_value(@post1).should == :down
109
+
110
+ Post.voted_by(@user1).to_a.should == [ @post1 ]
111
+ Post.voted_by(@user2).to_a.should == [ @post1 ]
112
+ end
113
+ end
114
+
115
+ context 'user1 vote down post2 the first time' do
116
+ before :all do
117
+ @user1.vote(:new => 'abc', :votee => @post2, :value => :down)
118
+ @post2.reload
119
+ end
120
+
121
+ it 'validates' do
122
+ @post2.votes_count.should == 1
123
+ @post2.votes_point.should == -1
124
+
125
+ @user1.vote_value(@post2).should == :down
126
+ @user2.vote_value(@post2).should be_nil
127
+
128
+ Post.voted_by(@user1).to_a.should == [ @post1, @post2 ]
129
+ end
130
+ end
131
+
132
+ context 'user1 change vote on post2 from down to up' do
133
+ before :all do
134
+ @user1.vote(:revote => 'abc', :votee => @post2, :value => :up)
135
+ @post2.reload
136
+ end
137
+
138
+ it 'validates' do
139
+ @post2.votes_count.should == 1
140
+ @post2.votes_point.should == 1
141
+
142
+ @user1.vote_value(@post2).should == :up
143
+ @user2.vote_value(@post2).should be_nil
144
+
145
+ Post.voted_by(@user1).size.should == 2
146
+ Post.voted_by(@user1).should be_include @post1
147
+ Post.voted_by(@user1).should be_include @post2
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'voteable_mongo/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'rs_voteable_mongo'
7
+ s.version = VoteableMongo::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ['RocketScience','Alex Nguyen']
10
+ s.email = ['i@gleb.tv','alex@vinova.sg']
11
+ s.homepage = 'https://github.com/rs-pro/voteable_mongo'
12
+ s.summary = %q{Add up / down voting ability to Mongoid documents}
13
+ s.description = %q{Add up / down voting ability to Mongoid documents. Optimized for speed by using only ONE request to MongoDB to validate, update, and retrieve updated data.}
14
+
15
+ s.add_dependency "mongoid", [">= 3.0", "< 5.0"]
16
+ s.add_development_dependency 'rspec', '~> 2.14.1'
17
+
18
+ s.rubyforge_project = 'voteable_mongo'
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
23
+ s.require_paths = ['lib']
24
+ end