voteable_mongo 0.8.1 → 0.9.0
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.
- data/CHANGELOG.rdoc +6 -0
- data/README.rdoc +40 -4
- data/Rakefile +4 -4
- data/TODO +5 -0
- data/lib/voteable_mongo.rb +2 -3
- data/lib/voteable_mongo/integrations/mongo_mapper.rb +28 -0
- data/lib/voteable_mongo/integrations/mongoid.rb +31 -0
- data/lib/voteable_mongo/{voteable/tasks.rb → tasks.rb} +16 -17
- data/lib/voteable_mongo/version.rb +1 -1
- data/lib/voteable_mongo/voteable.rb +40 -34
- data/lib/voteable_mongo/voter.rb +1 -3
- data/lib/voteable_mongo/{voteable/voting.rb → voting.rb} +24 -41
- data/spec/mongo_mapper/models/category.rb +11 -0
- data/spec/mongo_mapper/models/comment.rb +13 -0
- data/spec/mongo_mapper/models/post.rb +17 -0
- data/spec/mongo_mapper/models/user.rb +4 -0
- data/spec/{models → mongoid/models}/category.rb +0 -0
- data/spec/{models → mongoid/models}/comment.rb +1 -1
- data/spec/{models → mongoid/models}/post.rb +2 -0
- data/spec/{models → mongoid/models}/user.rb +0 -0
- data/spec/spec_helper.rb +24 -18
- data/spec/voteable_mongo/tasks_spec.rb +7 -6
- data/spec/voteable_mongo/voteable_spec.rb +16 -15
- data/spec/voteable_mongo/voter_spec.rb +9 -7
- data/voteable_mongo.gemspec +4 -4
- metadata +29 -20
- data/lib/voteable_mongo/voteable/votes.rb +0 -19
data/CHANGELOG.rdoc
CHANGED
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Voteable Mongo
|
2
2
|
|
3
|
-
voteable_mongo allows you to make your Mongoid::Document
|
3
|
+
voteable_mongo allows you to make your Mongoid::Document or MongoMapper::Document objects voteable (up or down) and tabulate votes count and votes point for you. For instance, in a forum, a user can vote up (or down) on a post or a comment.
|
4
4
|
|
5
5
|
voteable_mongo is built for speed. It uses only one database request per collection to validate data, update data, and get updated data. Initial idea is based on http://cookbook.mongodb.org/patterns/votes
|
6
6
|
|
@@ -27,6 +27,7 @@ After that, remember to run "bundle install"
|
|
27
27
|
|
28
28
|
=== Make Post and Comment voteable, User become the voter
|
29
29
|
|
30
|
+
== Mongoid
|
30
31
|
post.rb
|
31
32
|
|
32
33
|
class Post
|
@@ -62,6 +63,42 @@ user.rb
|
|
62
63
|
include Mongo::Voter
|
63
64
|
end
|
64
65
|
|
66
|
+
|
67
|
+
== MongoMapper
|
68
|
+
post.rb
|
69
|
+
|
70
|
+
class Post
|
71
|
+
include MongoMapper::Document
|
72
|
+
include Mongo::Voteable
|
73
|
+
|
74
|
+
# set points for each vote
|
75
|
+
voteable self, :up => +1, :down => -1
|
76
|
+
|
77
|
+
many :comments
|
78
|
+
end
|
79
|
+
|
80
|
+
comment.rb
|
81
|
+
|
82
|
+
require 'post'
|
83
|
+
|
84
|
+
class Comment
|
85
|
+
include MongoMapper::Document
|
86
|
+
include Mongo::Voteable
|
87
|
+
|
88
|
+
belongs_to :post
|
89
|
+
|
90
|
+
voteable self, :up => +1, :down => -3
|
91
|
+
voteable Post, :up => +2, :down => -1
|
92
|
+
end
|
93
|
+
|
94
|
+
user.rb
|
95
|
+
|
96
|
+
class User
|
97
|
+
include MongoMapper::Document
|
98
|
+
include Mongo::Voter
|
99
|
+
end
|
100
|
+
|
101
|
+
|
65
102
|
=== Make a vote
|
66
103
|
|
67
104
|
@user.vote(@post, :up)
|
@@ -89,9 +126,8 @@ Re-vote
|
|
89
126
|
|
90
127
|
Un-vote
|
91
128
|
Post.vote(:voter_id => user_id, :votee_id => post_id, :value => :up, :unvote => true)
|
92
|
-
|
93
|
-
|
94
|
-
votee = Post.vote(:voter_id => user_id, :votee_id => post_id, :value => :up, :return_votee => true)
|
129
|
+
|
130
|
+
Note: vote function always return updated votee object
|
95
131
|
|
96
132
|
=== Get vote_value
|
97
133
|
|
data/Rakefile
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'bundler'
|
2
2
|
Bundler::GemHelper.install_tasks
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
4
|
+
require 'rspec'
|
5
|
+
require 'rspec/core/rake_task'
|
6
6
|
Rspec::Core::RakeTask.new(:spec) do |spec|
|
7
|
-
spec.pattern =
|
7
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
8
8
|
end
|
9
9
|
|
10
|
-
task :default => [
|
10
|
+
task :default => ['spec']
|
data/TODO
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
* Use mongo_ruby_driver as much as possible
|
2
|
+
* Move mongoid dependency to a separate module
|
3
|
+
* Learn from other gems how they manage and support multiple adaptors
|
4
|
+
- https://github.com/pluginaweek/state_machine/tree/master/lib/state_machine/integrations
|
5
|
+
- https://github.com/ianwhite/orm_adapter
|
1
6
|
* Add support for mongo_mapper
|
2
7
|
* Add options hash validations
|
3
8
|
* Refactor specs
|
data/lib/voteable_mongo.rb
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Mongo
|
2
|
+
module Voteable
|
3
|
+
module Integrations
|
4
|
+
module MongoMapper
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
key :votes, Hash, :default => DEFAULT_VOTES
|
9
|
+
|
10
|
+
class << self
|
11
|
+
alias_method :voteable_index, :ensure_index
|
12
|
+
alias_method :voteable_collection, :collection
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ClassMethods
|
17
|
+
def voteable_relation(class_name)
|
18
|
+
associations.find{ |x, r| r.class_name == class_name }.try(:last)
|
19
|
+
end
|
20
|
+
|
21
|
+
def voteable_foreign_key(metadata)
|
22
|
+
(metadata.options[:in] || "#{metadata.name}_id").to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Mongo
|
2
|
+
module Voteable
|
3
|
+
module Integrations
|
4
|
+
module Mongoid
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
field :votes, :type => Hash, :default => DEFAULT_VOTES
|
9
|
+
|
10
|
+
class << self
|
11
|
+
alias_method :voteable_index, :index
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def voteable_relation(class_name)
|
17
|
+
relations.find{ |x, r| r.class_name == class_name }.try(:last)
|
18
|
+
end
|
19
|
+
|
20
|
+
def voteable_collection
|
21
|
+
collection.master.collection
|
22
|
+
end
|
23
|
+
|
24
|
+
def voteable_foreign_key(metadata)
|
25
|
+
metadata.foreign_key.to_s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -10,7 +10,7 @@ module Mongo
|
|
10
10
|
klass_voteable = voteable[class_name]
|
11
11
|
puts "Init stats for #{class_name}" if log
|
12
12
|
klass.collection.update({:votes => nil}, {
|
13
|
-
'$set' => { :votes =>
|
13
|
+
'$set' => { :votes => DEFAULT_VOTES }
|
14
14
|
}, {
|
15
15
|
:safe => true,
|
16
16
|
:multi => true
|
@@ -68,12 +68,6 @@ module Mongo
|
|
68
68
|
'votes_count' => true,
|
69
69
|
'votes_point' => true,
|
70
70
|
'voteable' => true
|
71
|
-
# 'votes.u' => true,
|
72
|
-
# 'votes.d' => true,
|
73
|
-
# 'votes.uc' => true,
|
74
|
-
# 'votes.dc' => true,
|
75
|
-
# 'votes.c' => true,
|
76
|
-
# 'votes.p' => true
|
77
71
|
}
|
78
72
|
}, { :safe => true })
|
79
73
|
end
|
@@ -95,12 +89,15 @@ module Mongo
|
|
95
89
|
def self.remake_stats_for(doc, voteable)
|
96
90
|
up_count = doc.up_voter_ids.length
|
97
91
|
down_count = doc.down_voter_ids.length
|
98
|
-
|
99
92
|
doc.update_attributes(
|
100
|
-
'votes
|
101
|
-
|
102
|
-
|
103
|
-
|
93
|
+
'votes' => {
|
94
|
+
'up' => doc.up_voter_ids,
|
95
|
+
'down' => doc.down_voter_ids,
|
96
|
+
'up_count' => up_count,
|
97
|
+
'down_count' => down_count,
|
98
|
+
'count' => up_count + down_count,
|
99
|
+
'point' => voteable[:up].to_i*up_count + voteable[:down].to_i*down_count
|
100
|
+
}
|
104
101
|
)
|
105
102
|
end
|
106
103
|
|
@@ -109,10 +106,10 @@ module Mongo
|
|
109
106
|
VOTEABLE.each do |class_name, voteable|
|
110
107
|
klass = class_name.constantize
|
111
108
|
voteable.each do |parent_class_name, parent_voteable|
|
112
|
-
|
113
|
-
if
|
109
|
+
metadata = klass.voteable_relation(parent_class_name)
|
110
|
+
if metadata
|
114
111
|
parent_class = parent_class_name.constantize
|
115
|
-
foreign_key =
|
112
|
+
foreign_key = klass.voteable_foreign_key(metadata)
|
116
113
|
puts "Updating stats for #{class_name} > #{parent_class_name}" if log
|
117
114
|
klass.all.each{ |doc|
|
118
115
|
update_parent_stats_for(doc, parent_class, foreign_key, parent_voteable)
|
@@ -142,9 +139,11 @@ module Mongo
|
|
142
139
|
'votes.down_count' => down_count
|
143
140
|
)
|
144
141
|
end
|
145
|
-
|
142
|
+
|
143
|
+
parent_ids = parent_id.is_a?(Array) ? parent_id : [ parent_id ]
|
144
|
+
|
146
145
|
parent_class.collection.update(
|
147
|
-
{ '_id' =>
|
146
|
+
{ '_id' => { '$in' => parent_ids } },
|
148
147
|
{ '$inc' => inc_options },
|
149
148
|
{ :safe => true }
|
150
149
|
)
|
@@ -1,36 +1,45 @@
|
|
1
|
-
require 'voteable_mongo/
|
2
|
-
require 'voteable_mongo/
|
1
|
+
require 'voteable_mongo/voting'
|
2
|
+
require 'voteable_mongo/integrations/mongoid'
|
3
|
+
require 'voteable_mongo/integrations/mongo_mapper'
|
3
4
|
|
4
5
|
module Mongo
|
5
6
|
module Voteable
|
6
7
|
extend ActiveSupport::Concern
|
7
8
|
|
9
|
+
DEFAULT_VOTES = {
|
10
|
+
'up' => [],
|
11
|
+
'down' => [],
|
12
|
+
'up_count' => 0,
|
13
|
+
'down_count' => 0,
|
14
|
+
'count' => 0,
|
15
|
+
'point' => 0
|
16
|
+
}
|
17
|
+
|
8
18
|
included do
|
9
19
|
include ::Mongo::Voteable::Voting
|
10
|
-
|
11
|
-
field :votes, :type => Votes
|
12
20
|
|
13
|
-
|
14
|
-
|
15
|
-
|
21
|
+
if defined?(Mongoid) && defined?(field)
|
22
|
+
include ::Mongo::Voteable::Integrations::Mongoid
|
23
|
+
elsif defined?(MongoMapper)
|
24
|
+
include ::Mongo::Voteable::Integrations::MongoMapper
|
16
25
|
end
|
17
26
|
|
18
27
|
scope :voted_by, lambda { |voter|
|
19
|
-
voter_id = voter.is_a?(BSON::ObjectId) ? voter : voter.id
|
20
|
-
|
28
|
+
voter_id = voter.is_a?(::BSON::ObjectId) ? voter : voter.id
|
29
|
+
where('$or' => [{ 'votes.up' => voter_id }, { 'votes.down' => voter_id }])
|
21
30
|
}
|
22
|
-
|
31
|
+
|
23
32
|
scope :up_voted_by, lambda { |voter|
|
24
|
-
voter_id = voter.is_a?(BSON::ObjectId) ? voter : voter.id
|
25
|
-
where(
|
33
|
+
voter_id = voter.is_a?(::BSON::ObjectId) ? voter : voter.id
|
34
|
+
where('votes.up' => voter_id)
|
26
35
|
}
|
27
|
-
|
36
|
+
|
28
37
|
scope :down_voted_by, lambda { |voter|
|
29
|
-
voter_id = voter.is_a?(BSON::ObjectId) ? voter : voter.id
|
30
|
-
where(
|
38
|
+
voter_id = voter.is_a?(::BSON::ObjectId) ? voter : voter.id
|
39
|
+
where('votes.down' => voter_id)
|
31
40
|
}
|
32
|
-
end
|
33
|
-
|
41
|
+
end
|
42
|
+
|
34
43
|
# How many points should be assigned for each up or down vote and other options
|
35
44
|
# This hash should manipulated using voteable method
|
36
45
|
VOTEABLE = {}
|
@@ -89,24 +98,21 @@ module Mongo
|
|
89
98
|
validate_and_normalize_vote_options(options)
|
90
99
|
down_voted_by(options[:voter_id]).where(:_id => options[:votee_id]).count == 1
|
91
100
|
end
|
92
|
-
|
93
|
-
private
|
101
|
+
|
94
102
|
def create_voteable_indexes
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
index [['votes.point', -1]]
|
109
|
-
end
|
103
|
+
# Compound index _id and voters.up, _id and voters.down
|
104
|
+
# to make up_voted_by, down_voted_by, voted_by scopes and voting faster
|
105
|
+
# Should run in background since it introduce new index value and
|
106
|
+
# while waiting to build, the system can use _id for voting
|
107
|
+
# http://www.mongodb.org/display/DOCS/Indexing+as+a+Background+Operation
|
108
|
+
voteable_index [['votes.up', 1], ['_id', 1]], :unique => true
|
109
|
+
voteable_index [['votes.down', 1], ['_id', 1]], :unique => true
|
110
|
+
|
111
|
+
# Index counters and point for desc ordering
|
112
|
+
voteable_index [['votes.up_count', -1]]
|
113
|
+
voteable_index [['votes.down_count', -1]]
|
114
|
+
voteable_index [['votes.count', -1]]
|
115
|
+
voteable_index [['votes.point', -1]]
|
110
116
|
end
|
111
117
|
end
|
112
118
|
|
data/lib/voteable_mongo/voter.rb
CHANGED
@@ -3,8 +3,6 @@ module Mongo
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
-
include ::Mongoid::Document
|
7
|
-
|
8
6
|
scope :up_voted_for, lambda { |votee| where(:_id => { '$in' => votee.up_voter_ids }) }
|
9
7
|
scope :down_voted_for, lambda { |votee| where(:_id => { '$in' => votee.down_voter_ids }) }
|
10
8
|
scope :voted_for, lambda { |votee| where(:_id => { '$in' => votee.voter_ids }) }
|
@@ -41,7 +39,7 @@ module Mongo
|
|
41
39
|
votee = unless options.is_a?(Hash)
|
42
40
|
options
|
43
41
|
else
|
44
|
-
options[:votee] || options[:votee_type].classify.constantize.
|
42
|
+
options[:votee] || options[:votee_type].classify.constantize.where(
|
45
43
|
:_id => options[:votee_id]
|
46
44
|
).first
|
47
45
|
end
|
@@ -12,9 +12,8 @@ module Mongo
|
|
12
12
|
# - :value: :up or :down
|
13
13
|
# - :revote: if true change vote vote from :up to :down and vise versa
|
14
14
|
# - :unvote: if true undo the voting
|
15
|
-
# - :return_votee: if true always return updated voteable object
|
16
15
|
#
|
17
|
-
# @return [
|
16
|
+
# @return [votee, false]
|
18
17
|
def vote(options)
|
19
18
|
validate_and_normalize_vote_options(options)
|
20
19
|
options[:voteable] = VOTEABLE[name][name]
|
@@ -28,27 +27,21 @@ module Mongo
|
|
28
27
|
new_vote_query_and_update(options)
|
29
28
|
end
|
30
29
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
rescue Exception => e
|
45
|
-
# $stderr.puts "Mongo error: #{e.inspect}" # DEBUG
|
46
|
-
# Don't update parents if operation fail or no matched object found
|
47
|
-
return false
|
48
|
-
end
|
30
|
+
# If votee exits or need to update parent
|
31
|
+
# use Collection#find_and_modify to retrieve updated votes data and parent_ids
|
32
|
+
doc = voteable_collection.find_and_modify(
|
33
|
+
:query => query,
|
34
|
+
:update => update,
|
35
|
+
:new => true
|
36
|
+
)
|
37
|
+
|
38
|
+
if doc
|
39
|
+
update_parent_votes(doc, options) if options[:voteable][:update_parents]
|
40
|
+
# Update new votes data
|
41
|
+
options[:votee].write_attribute('votes', doc['votes']) if options[:votee]
|
42
|
+
options[:votee] || new(doc)
|
49
43
|
else
|
50
|
-
|
51
|
-
collection.update(query, update)
|
44
|
+
false
|
52
45
|
end
|
53
46
|
end
|
54
47
|
end
|
@@ -155,25 +148,15 @@ module Mongo
|
|
155
148
|
|
156
149
|
def update_parent_votes(doc, options)
|
157
150
|
VOTEABLE[name].each do |class_name, voteable|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
class_name.constantize.collection.update(
|
168
|
-
{ '_id' => foreign_key_value },
|
169
|
-
{ '$inc' => parent_inc_options(voteable, options) }
|
170
|
-
)
|
171
|
-
elsif relation_metadata.relation == ::Mongoid::Relations::Referenced::ManyToMany
|
172
|
-
class_name.constantize.collection.update(
|
173
|
-
{ '_id' => { '$in' => foreign_key_value } },
|
174
|
-
{ '$inc' => parent_inc_options(voteable, options) },
|
175
|
-
{ :multi => true }
|
176
|
-
)
|
151
|
+
if metadata = voteable_relation(class_name)
|
152
|
+
if parent_id = doc[voteable_foreign_key(metadata)]
|
153
|
+
parent_ids = parent_id.is_a?(Array) ? parent_id : [ parent_id ]
|
154
|
+
class_name.constantize.collection.update(
|
155
|
+
{ '_id' => { '$in' => parent_ids } },
|
156
|
+
{ '$inc' => parent_inc_options(voteable, options) },
|
157
|
+
{ :multi => true }
|
158
|
+
)
|
159
|
+
end
|
177
160
|
end
|
178
161
|
end
|
179
162
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'post')
|
2
|
+
|
3
|
+
class Comment
|
4
|
+
include MongoMapper::Document
|
5
|
+
include Mongo::Voteable
|
6
|
+
|
7
|
+
key :content, String
|
8
|
+
|
9
|
+
belongs_to :post
|
10
|
+
|
11
|
+
voteable self, :up => +1, :down => -3
|
12
|
+
voteable Post, :up => +2, :down => -1
|
13
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'category')
|
2
|
+
|
3
|
+
class Post
|
4
|
+
include MongoMapper::Document
|
5
|
+
include Mongo::Voteable
|
6
|
+
|
7
|
+
key :title, String
|
8
|
+
key :content, String
|
9
|
+
|
10
|
+
key :category_ids, Array
|
11
|
+
many :categories, :in => :category_ids
|
12
|
+
|
13
|
+
many :comments
|
14
|
+
|
15
|
+
voteable self, :up => +1, :down => -1, :index => true
|
16
|
+
voteable Category, :up => +3, :down => -5, :update_counters => false
|
17
|
+
end
|
File without changes
|
File without changes
|
data/spec/spec_helper.rb
CHANGED
@@ -3,29 +3,35 @@ require 'bundler'
|
|
3
3
|
Bundler.setup
|
4
4
|
|
5
5
|
|
6
|
+
if rand > 0.6
|
7
|
+
puts 'Mongoid'
|
8
|
+
require 'mongoid'
|
9
|
+
models_folder = File.join(File.dirname(__FILE__), 'mongoid/models')
|
10
|
+
Mongoid.configure do |config|
|
11
|
+
name = 'voteable_mongo_test'
|
12
|
+
host = 'localhost'
|
13
|
+
config.master = Mongo::Connection.new.db(name)
|
14
|
+
config.autocreate_indexes = true
|
15
|
+
end
|
16
|
+
else
|
17
|
+
puts 'MongoMapper'
|
18
|
+
require 'mongo_mapper'
|
19
|
+
models_folder = File.join(File.dirname(__FILE__), 'mongo_mapper/models')
|
20
|
+
MongoMapper.database = 'voteable_mongo_test'
|
21
|
+
end
|
22
|
+
|
23
|
+
|
6
24
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
7
25
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
8
26
|
|
9
|
-
MODELS = File.join(File.dirname(__FILE__), "models")
|
10
|
-
$LOAD_PATH.unshift(MODELS)
|
11
27
|
|
12
|
-
|
13
|
-
require 'mongoid'
|
14
28
|
require 'voteable_mongo'
|
15
29
|
require 'rspec'
|
16
30
|
require 'rspec/autorun'
|
17
31
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
Dir[ File.join(MODELS, "*.rb") ].sort.each { |file| require File.basename(file) }
|
27
|
-
|
28
|
-
User.collection.drop
|
29
|
-
Post.collection.drop
|
30
|
-
Comment.collection.drop
|
31
|
-
Category.collection.drop
|
32
|
+
Dir[ File.join(models_folder, '*.rb') ].each { |file|
|
33
|
+
require file
|
34
|
+
file_name = File.basename(file).sub('.rb', '')
|
35
|
+
klass = file_name.classify.constantize
|
36
|
+
# klass.collection.drop
|
37
|
+
}
|
@@ -8,8 +8,8 @@ describe Mongo::Voteable::Tasks do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
it 'after create votes has default value' do
|
11
|
-
@post1.votes.should == Mongo::Voteable::
|
12
|
-
@post2.votes.should == Mongo::Voteable::
|
11
|
+
@post1.votes.should == ::Mongo::Voteable::DEFAULT_VOTES
|
12
|
+
@post2.votes.should == ::Mongo::Voteable::DEFAULT_VOTES
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'reset votes data' do
|
@@ -21,13 +21,14 @@ describe Mongo::Voteable::Tasks do
|
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'init_stats recover votes default value' do
|
24
|
-
Mongo::Voteable::Tasks.init_stats
|
24
|
+
::Mongo::Voteable::Tasks.init_stats
|
25
|
+
::Mongo::Voteable::Tasks.migrate_old_votes
|
25
26
|
|
26
27
|
@post1.reload
|
27
28
|
@post2.reload
|
28
|
-
|
29
|
-
@post1.votes.should == Mongo::Voteable::
|
30
|
-
@post2.votes.should == Mongo::Voteable::
|
29
|
+
|
30
|
+
@post1.votes.should == ::Mongo::Voteable::DEFAULT_VOTES
|
31
|
+
@post2.votes.should == ::Mongo::Voteable::DEFAULT_VOTES
|
31
32
|
end
|
32
33
|
end
|
33
34
|
end
|
@@ -6,18 +6,20 @@ describe Mongo::Voteable do
|
|
6
6
|
before do
|
7
7
|
Post.collection.drop_indexes
|
8
8
|
Category.collection.drop_indexes
|
9
|
+
|
10
|
+
Post.create_voteable_indexes
|
11
|
+
Category.create_voteable_indexes
|
9
12
|
end
|
10
|
-
|
13
|
+
|
11
14
|
it 'defines indexes' do
|
12
15
|
[Post, Category].each do |klass|
|
13
|
-
klass.create_indexes
|
14
16
|
[ 'votes.up_1__id_1',
|
15
17
|
'votes.down_1__id_1'
|
16
18
|
].each { |index_key|
|
17
19
|
klass.collection.index_information.should have_key index_key
|
18
20
|
klass.collection.index_information[index_key]['unique'].should be_true
|
19
21
|
}
|
20
|
-
|
22
|
+
|
21
23
|
[ 'votes.count_-1',
|
22
24
|
'votes.up_count_-1',
|
23
25
|
'votes.down_count_-1',
|
@@ -33,12 +35,9 @@ describe Mongo::Voteable do
|
|
33
35
|
@category1 = Category.create!(:name => 'xyz')
|
34
36
|
@category2 = Category.create!(:name => 'abc')
|
35
37
|
|
36
|
-
@post1 = Post.create!
|
38
|
+
@post1 = Post.create!(:category_ids => [@category1.id, @category2.id])
|
37
39
|
@post2 = Post.create!
|
38
|
-
|
39
|
-
@post1.categories << @category1
|
40
|
-
@category2.posts << @post1
|
41
|
-
|
40
|
+
|
42
41
|
@comment = @post2.comments.create!
|
43
42
|
|
44
43
|
@user1 = User.create!
|
@@ -123,7 +122,7 @@ describe Mongo::Voteable do
|
|
123
122
|
|
124
123
|
context 'user1 vote up post1 the first time' do
|
125
124
|
before :all do
|
126
|
-
@post = @post1.vote(:voter_id => @user1.id, :value => :up
|
125
|
+
@post = @post1.vote(:voter_id => @user1.id, :value => :up)
|
127
126
|
end
|
128
127
|
|
129
128
|
it 'validates return post' do
|
@@ -151,8 +150,8 @@ describe Mongo::Voteable do
|
|
151
150
|
@post1.vote_value(@user2.id).should be_nil
|
152
151
|
@post1.should_not be_voted_by(@user2.id)
|
153
152
|
|
154
|
-
@post1.up_voters(User).should == [ @user1 ]
|
155
|
-
@post1.voters(User).should == [ @user1 ]
|
153
|
+
@post1.up_voters(User).to_a.should == [ @user1 ]
|
154
|
+
@post1.voters(User).to_a.should == [ @user1 ]
|
156
155
|
@post1.down_voters(User).should be_empty
|
157
156
|
|
158
157
|
Post.voted_by(@user1).to_a.should == [ @post1 ]
|
@@ -206,9 +205,9 @@ describe Mongo::Voteable do
|
|
206
205
|
end
|
207
206
|
|
208
207
|
it 'post1 get voters' do
|
209
|
-
@post1.up_voters(User).should == [ @user1 ]
|
210
|
-
@post1.down_voters(User).should == [ @user2 ]
|
211
|
-
@post1.voters(User).should == [ @user1, @user2 ]
|
208
|
+
@post1.up_voters(User).to_a.should == [ @user1 ]
|
209
|
+
@post1.down_voters(User).to_a.should == [ @user2 ]
|
210
|
+
@post1.voters(User).to_a.should == [ @user1, @user2 ]
|
212
211
|
end
|
213
212
|
|
214
213
|
it 'posts voted_by user1, user2 is post1 only' do
|
@@ -286,7 +285,9 @@ describe Mongo::Voteable do
|
|
286
285
|
@post2.vote_value(@user1.id).should == :up
|
287
286
|
@post2.vote_value(@user2.id).should be_nil
|
288
287
|
|
289
|
-
Post.voted_by(@user1).
|
288
|
+
Post.voted_by(@user1).size.should == 2
|
289
|
+
Post.voted_by(@user1).should be_include @post1
|
290
|
+
Post.voted_by(@user1).should be_include @post2
|
290
291
|
end
|
291
292
|
end
|
292
293
|
|
@@ -54,9 +54,9 @@ describe Mongo::Voter do
|
|
54
54
|
Post.down_voted_by(@user1).to_a.should be_empty
|
55
55
|
Post.voted_by(@user2).to_a.should be_empty
|
56
56
|
|
57
|
-
User.up_voted_for(@post1).should == [ @user1 ]
|
58
|
-
User.down_voted_for(@post1).should be_empty
|
59
|
-
User.voted_for(@post1).should == [ @user1 ]
|
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
60
|
end
|
61
61
|
|
62
62
|
it 'user1 vote post1 has no effect' do
|
@@ -88,9 +88,9 @@ describe Mongo::Voter do
|
|
88
88
|
Post.up_voted_by(@user2).to_a.should be_empty
|
89
89
|
Post.down_voted_by(@user2).to_a.should == [ @post1 ]
|
90
90
|
|
91
|
-
User.up_voted_for(@post1).should == [ @user1 ]
|
92
|
-
User.down_voted_for(@post1).should == [ @user2 ]
|
93
|
-
User.voted_for(@post1).should == [ @user1, @user2 ]
|
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
94
|
end
|
95
95
|
end
|
96
96
|
|
@@ -142,7 +142,9 @@ describe Mongo::Voter do
|
|
142
142
|
@user1.vote_value(@post2).should == :up
|
143
143
|
@user2.vote_value(@post2).should be_nil
|
144
144
|
|
145
|
-
Post.voted_by(@user1).
|
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
|
146
148
|
end
|
147
149
|
end
|
148
150
|
end
|
data/voteable_mongo.gemspec
CHANGED
@@ -10,12 +10,12 @@ Gem::Specification.new do |s|
|
|
10
10
|
s.email = ['alex@vinova.sg']
|
11
11
|
s.homepage = 'https://github.com/vinova/voteable_mongo'
|
12
12
|
s.summary = %q{Add Up / Down Voting for Mongoid and MongoMapper}
|
13
|
-
s.description = %q{
|
13
|
+
s.description = %q{Built for speed by using only one database request per collection to validate, update, and retrieve updated data}
|
14
14
|
|
15
|
-
s.add_development_dependency 'rspec'
|
15
|
+
s.add_development_dependency 'rspec', '~> 2.5.0'
|
16
16
|
s.add_development_dependency 'mongoid', '~> 2.0.0'
|
17
|
-
s.add_development_dependency 'mongo_mapper'
|
18
|
-
s.add_development_dependency 'bson_ext'
|
17
|
+
s.add_development_dependency 'mongo_mapper', '~> 0.9.0'
|
18
|
+
s.add_development_dependency 'bson_ext', '~> 1.3.0'
|
19
19
|
|
20
20
|
s.rubyforge_project = 'voteable_mongo'
|
21
21
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: voteable_mongo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.9.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Alex Nguyen
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-05-
|
13
|
+
date: 2011-05-04 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -18,9 +18,9 @@ dependencies:
|
|
18
18
|
requirement: &id001 !ruby/object:Gem::Requirement
|
19
19
|
none: false
|
20
20
|
requirements:
|
21
|
-
- -
|
21
|
+
- - ~>
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version:
|
23
|
+
version: 2.5.0
|
24
24
|
type: :development
|
25
25
|
version_requirements: *id001
|
26
26
|
- !ruby/object:Gem::Dependency
|
@@ -40,9 +40,9 @@ dependencies:
|
|
40
40
|
requirement: &id003 !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
|
-
- -
|
43
|
+
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
45
|
+
version: 0.9.0
|
46
46
|
type: :development
|
47
47
|
version_requirements: *id003
|
48
48
|
- !ruby/object:Gem::Dependency
|
@@ -51,12 +51,12 @@ dependencies:
|
|
51
51
|
requirement: &id004 !ruby/object:Gem::Requirement
|
52
52
|
none: false
|
53
53
|
requirements:
|
54
|
-
- -
|
54
|
+
- - ~>
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version:
|
56
|
+
version: 1.3.0
|
57
57
|
type: :development
|
58
58
|
version_requirements: *id004
|
59
|
-
description:
|
59
|
+
description: Built for speed by using only one database request per collection to validate, update, and retrieve updated data
|
60
60
|
email:
|
61
61
|
- alex@vinova.sg
|
62
62
|
executables: []
|
@@ -75,19 +75,24 @@ files:
|
|
75
75
|
- Rakefile
|
76
76
|
- TODO
|
77
77
|
- lib/voteable_mongo.rb
|
78
|
+
- lib/voteable_mongo/integrations/mongo_mapper.rb
|
79
|
+
- lib/voteable_mongo/integrations/mongoid.rb
|
78
80
|
- lib/voteable_mongo/railtie.rb
|
79
81
|
- lib/voteable_mongo/railties/database.rake
|
82
|
+
- lib/voteable_mongo/tasks.rb
|
80
83
|
- lib/voteable_mongo/version.rb
|
81
84
|
- lib/voteable_mongo/voteable.rb
|
82
|
-
- lib/voteable_mongo/voteable/tasks.rb
|
83
|
-
- lib/voteable_mongo/voteable/votes.rb
|
84
|
-
- lib/voteable_mongo/voteable/voting.rb
|
85
85
|
- lib/voteable_mongo/voter.rb
|
86
|
+
- lib/voteable_mongo/voting.rb
|
86
87
|
- spec/.rspec
|
87
|
-
- spec/models/category.rb
|
88
|
-
- spec/models/comment.rb
|
89
|
-
- spec/models/post.rb
|
90
|
-
- spec/models/user.rb
|
88
|
+
- spec/mongo_mapper/models/category.rb
|
89
|
+
- spec/mongo_mapper/models/comment.rb
|
90
|
+
- spec/mongo_mapper/models/post.rb
|
91
|
+
- spec/mongo_mapper/models/user.rb
|
92
|
+
- spec/mongoid/models/category.rb
|
93
|
+
- spec/mongoid/models/comment.rb
|
94
|
+
- spec/mongoid/models/post.rb
|
95
|
+
- spec/mongoid/models/user.rb
|
91
96
|
- spec/spec_helper.rb
|
92
97
|
- spec/voteable_mongo/tasks_spec.rb
|
93
98
|
- spec/voteable_mongo/voteable_spec.rb
|
@@ -121,10 +126,14 @@ signing_key:
|
|
121
126
|
specification_version: 3
|
122
127
|
summary: Add Up / Down Voting for Mongoid and MongoMapper
|
123
128
|
test_files:
|
124
|
-
- spec/models/category.rb
|
125
|
-
- spec/models/comment.rb
|
126
|
-
- spec/models/post.rb
|
127
|
-
- spec/models/user.rb
|
129
|
+
- spec/mongo_mapper/models/category.rb
|
130
|
+
- spec/mongo_mapper/models/comment.rb
|
131
|
+
- spec/mongo_mapper/models/post.rb
|
132
|
+
- spec/mongo_mapper/models/user.rb
|
133
|
+
- spec/mongoid/models/category.rb
|
134
|
+
- spec/mongoid/models/comment.rb
|
135
|
+
- spec/mongoid/models/post.rb
|
136
|
+
- spec/mongoid/models/user.rb
|
128
137
|
- spec/spec_helper.rb
|
129
138
|
- spec/voteable_mongo/tasks_spec.rb
|
130
139
|
- spec/voteable_mongo/voteable_spec.rb
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module Mongo
|
2
|
-
module Voteable
|
3
|
-
|
4
|
-
class Votes
|
5
|
-
include Mongoid::Document
|
6
|
-
|
7
|
-
field :up, :type => Array, :default => []
|
8
|
-
field :down, :type => Array, :default => []
|
9
|
-
field :up_count, :type => Integer, :default => 0
|
10
|
-
field :down_count, :type => Integer, :default => 0
|
11
|
-
field :count, :type => Integer, :default => 0
|
12
|
-
field :point, :type => Integer, :default => 0
|
13
|
-
|
14
|
-
DEFAULT_ATTRIBUTES = new.attributes
|
15
|
-
DEFAULT_ATTRIBUTES.delete('_id')
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
19
|
-
end
|