voterable 0.0.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.
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/.rvmrc +55 -0
- data/Gemfile +4 -0
- data/Guardfile +22 -0
- data/Rakefile +1 -0
- data/lib/voterable/functions.rb +13 -0
- data/lib/voterable/tally.rb +14 -0
- data/lib/voterable/version.rb +3 -0
- data/lib/voterable/vote.rb +11 -0
- data/lib/voterable/voteable.rb +273 -0
- data/lib/voterable/voter.rb +55 -0
- data/lib/voterable.rb +10 -0
- data/spec/factories.rb +33 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/voter_spec.rb +24 -0
- data/spec/voting_spec.rb +41 -0
- data/voterable.gemspec +43 -0
- metadata +199 -0
data/.gitignore
ADDED
data/.rspec
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
--colour
|
data/.rvmrc
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# This is an RVM Project .rvmrc file, used to automatically load the ruby
|
|
4
|
+
# development environment upon cd'ing into the directory
|
|
5
|
+
|
|
6
|
+
# First we specify our desired <ruby>[@<gemset>], the @gemset name is optional.
|
|
7
|
+
environment_id="ruby-1.9.2-p290@voterable"
|
|
8
|
+
|
|
9
|
+
#
|
|
10
|
+
# Uncomment following line if you want options to be set only for given project.
|
|
11
|
+
#
|
|
12
|
+
# PROJECT_JRUBY_OPTS=( --1.9 )
|
|
13
|
+
|
|
14
|
+
#
|
|
15
|
+
# First we attempt to load the desired environment directly from the environment
|
|
16
|
+
# file. This is very fast and efficient compared to running through the entire
|
|
17
|
+
# CLI and selector. If you want feedback on which environment was used then
|
|
18
|
+
# insert the word 'use' after --create as this triggers verbose mode.
|
|
19
|
+
#
|
|
20
|
+
if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \
|
|
21
|
+
&& -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]]
|
|
22
|
+
then
|
|
23
|
+
\. "${rvm_path:-$HOME/.rvm}/environments/$environment_id"
|
|
24
|
+
|
|
25
|
+
if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]]
|
|
26
|
+
then
|
|
27
|
+
. "${rvm_path:-$HOME/.rvm}/hooks/after_use"
|
|
28
|
+
fi
|
|
29
|
+
else
|
|
30
|
+
# If the environment file has not yet been created, use the RVM CLI to select.
|
|
31
|
+
if ! rvm --create "$environment_id"
|
|
32
|
+
then
|
|
33
|
+
echo "Failed to create RVM environment '${environment_id}'."
|
|
34
|
+
exit 1
|
|
35
|
+
fi
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
#
|
|
39
|
+
# If you use an RVM gemset file to install a list of gems (*.gems), you can have
|
|
40
|
+
# it be automatically loaded. Uncomment the following and adjust the filename if
|
|
41
|
+
# necessary.
|
|
42
|
+
#
|
|
43
|
+
# filename=".gems"
|
|
44
|
+
# if [[ -s "$filename" ]]
|
|
45
|
+
# then
|
|
46
|
+
# rvm gemset import "$filename" | grep -v already | grep -v listed | grep -v complete | sed '/^$/d'
|
|
47
|
+
# fi
|
|
48
|
+
|
|
49
|
+
# If you use bundler, this might be useful to you:
|
|
50
|
+
# if command -v bundle && [[ -s Gemfile ]]
|
|
51
|
+
# then
|
|
52
|
+
# bundle install
|
|
53
|
+
# fi
|
|
54
|
+
|
|
55
|
+
|
data/Gemfile
ADDED
data/Guardfile
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# A sample Guardfile
|
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
|
3
|
+
|
|
4
|
+
guard 'rspec', :version => 2, :cli => "--drb", :all_on_start => false, :all_after_pass => false do
|
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
|
8
|
+
|
|
9
|
+
# Rails example
|
|
10
|
+
watch(%r{^spec/.+_spec\.rb$})
|
|
11
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
|
12
|
+
watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
|
13
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
|
14
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
|
15
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
|
16
|
+
watch('spec/spec_helper.rb') { "spec" }
|
|
17
|
+
watch('config/routes.rb') { "spec/routing" }
|
|
18
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
|
19
|
+
# Capybara request specs
|
|
20
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
|
21
|
+
end
|
|
22
|
+
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Voterable
|
|
2
|
+
class Tally
|
|
3
|
+
include Mongoid::Document
|
|
4
|
+
|
|
5
|
+
field :name, :type => Symbol
|
|
6
|
+
|
|
7
|
+
field :count, :type => Integer, :default => 0
|
|
8
|
+
field :up, :type => Integer, :default => 0
|
|
9
|
+
field :down, :type => Integer, :default => 0
|
|
10
|
+
field :point, :type => Integer, :default => 0
|
|
11
|
+
|
|
12
|
+
embedded_in :voteable, polymorphic: true
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
|
|
2
|
+
require "voterable/functions"
|
|
3
|
+
|
|
4
|
+
# DUDE! Remember you need to restart the sever to get this file to reload!
|
|
5
|
+
module Voterable
|
|
6
|
+
class Voteable
|
|
7
|
+
|
|
8
|
+
include Mongoid::Document
|
|
9
|
+
include Mongoid::Timestamps
|
|
10
|
+
|
|
11
|
+
belongs_to :voter, polymorphic: true
|
|
12
|
+
has_many :votes, as: :voteable, dependent: :delete, class_name: "Voterable::Vote"
|
|
13
|
+
embeds_many :tallys, as: :tallyable, class_name: "Voterable::Tally"
|
|
14
|
+
|
|
15
|
+
#Create Indexes
|
|
16
|
+
for i in 0..4
|
|
17
|
+
index "tallys.#{i}.point"
|
|
18
|
+
index "tallys.#{i}.count"
|
|
19
|
+
index "tallys.#{i}.up"
|
|
20
|
+
index "tallys.#{i}.down"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
after_initialize :update_tally
|
|
24
|
+
|
|
25
|
+
VOTEABLE = {}
|
|
26
|
+
VOTEBACK = {}
|
|
27
|
+
|
|
28
|
+
TALLY_TYPES = { :all_time => [0, Time.now - Time.at(0)],
|
|
29
|
+
:year => [0, 365.days_in_seconds],
|
|
30
|
+
:month => [0, 30.days_in_seconds],
|
|
31
|
+
:week => [0, 7.days_in_seconds],
|
|
32
|
+
:day => [0, 1.days_in_seconds]
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
TALLYS = [:point, :count, :up, :down]
|
|
36
|
+
|
|
37
|
+
#Class Methods
|
|
38
|
+
|
|
39
|
+
#Set Options
|
|
40
|
+
def self.voteable(klass = self, options = nil)
|
|
41
|
+
VOTEABLE[klass.name] ||= options
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.voteback(klass = self, options = nil)
|
|
45
|
+
VOTEBACK[klass.name] ||= options
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.options(value)
|
|
49
|
+
VOTEABLE[name][value] ||= 0
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.vtback(value)
|
|
53
|
+
VOTEBACK[name][value] ||= 0
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
#Need to make sure these only return kind of voteable
|
|
58
|
+
def self.up_voted_by(voter)
|
|
59
|
+
votes = Vote.where(voter_id:voter.id, vote: :up)
|
|
60
|
+
votes.collect{|x| x.voteable}.compact
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.down_voted_by(voter)
|
|
64
|
+
votes = Vote.where(voter_id:voter.id, vote: :down)
|
|
65
|
+
votes.collect{|x| x.voteable}.compact
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def self.sort_by(hsh)
|
|
69
|
+
|
|
70
|
+
hsh[:page] ||= 1
|
|
71
|
+
hsh[:limit] ||= 30
|
|
72
|
+
hsh[:period] ||= :all_time
|
|
73
|
+
hsh[:tally_type] ||= :point
|
|
74
|
+
|
|
75
|
+
case hsh[:period]
|
|
76
|
+
when :latest
|
|
77
|
+
return self.order_by(:created_at, :desc).page(hsh[:page]).per(hsh[:limit])
|
|
78
|
+
when :all_time
|
|
79
|
+
index = '0.'
|
|
80
|
+
when :year
|
|
81
|
+
index = '1.'
|
|
82
|
+
when :month
|
|
83
|
+
index = '2.'
|
|
84
|
+
when :week
|
|
85
|
+
index = '3.'
|
|
86
|
+
when :day
|
|
87
|
+
index = '4.'
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
string = "tallys." + index + hsh[:tally_type].to_s
|
|
91
|
+
|
|
92
|
+
self.order_by(string,:desc).page(hsh[:page]).per(hsh[:limit]) #.where(:tallys.exists => true)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
#Instance Methods
|
|
97
|
+
|
|
98
|
+
def votes_point
|
|
99
|
+
point || 0
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Vote the voteable thing up or down
|
|
103
|
+
#
|
|
104
|
+
# @parma [ vtr ] voter object that will be doing the voting
|
|
105
|
+
# @return [ vote ] vote that was cast
|
|
106
|
+
def vote(vtr, value)
|
|
107
|
+
|
|
108
|
+
original_points = self.point #Record original points to update user
|
|
109
|
+
|
|
110
|
+
#Check that voter is not self's voter
|
|
111
|
+
return nil if vtr == self.voter
|
|
112
|
+
|
|
113
|
+
vt = Vote.where(voter_id:vtr.id, voteable_id:self.id).first
|
|
114
|
+
if vt && vt.vote == value
|
|
115
|
+
unvote(vtr,vt)
|
|
116
|
+
return nil
|
|
117
|
+
elsif vt
|
|
118
|
+
self.point -= self.class.options(vt.vote) #Remove old vote points
|
|
119
|
+
vtr.reputation -= self.class.vtback(vt.vote)
|
|
120
|
+
else
|
|
121
|
+
self.count += 1
|
|
122
|
+
vt = Vote.new(voter_id:vtr.id, voteable_id:self.id)
|
|
123
|
+
votes << vt
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
case value
|
|
127
|
+
when :up ; self.up += 1
|
|
128
|
+
when :down ; self.down += 1
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
self.point += self.class.options(value) #Add new vote points
|
|
132
|
+
vtr.reputation += self.class.vtback(value)
|
|
133
|
+
self.save
|
|
134
|
+
vtr.save
|
|
135
|
+
|
|
136
|
+
#Update votee reputation
|
|
137
|
+
self.voter.reputation += self.point - original_points
|
|
138
|
+
self.voter.save
|
|
139
|
+
|
|
140
|
+
# Set vote to up or down
|
|
141
|
+
vt.vote= value
|
|
142
|
+
vt.save
|
|
143
|
+
return vt
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def unvote(vtr, vote = nil)
|
|
147
|
+
original_points = self.point #Record original points to update user
|
|
148
|
+
|
|
149
|
+
vote ||= Vote.find(voter_id:vtr.id, voteable_id:self.id)
|
|
150
|
+
return if not vote # Return if vote doens't exist
|
|
151
|
+
|
|
152
|
+
self.point -= self.class.options(vote.vote)
|
|
153
|
+
vtr.reputation -= self.class.vtback(vote.vote)
|
|
154
|
+
|
|
155
|
+
self.count -= 1
|
|
156
|
+
|
|
157
|
+
value = vote.vote
|
|
158
|
+
case value
|
|
159
|
+
when :up ; self.up += 1
|
|
160
|
+
when :down ; self.down += 1
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
#Update votee reputation
|
|
164
|
+
self.voter.reputation += self.point - original_points
|
|
165
|
+
self.voter.save
|
|
166
|
+
vtr.save
|
|
167
|
+
|
|
168
|
+
votes.destroy_all(vote_id:vote.id)
|
|
169
|
+
self.save
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
#Updates tally assuming that classes will
|
|
173
|
+
def update_tallys
|
|
174
|
+
bracket_votes = nil
|
|
175
|
+
TALLY_TYPES.each_key do |period|
|
|
176
|
+
bracket_votes = self.update_tally(period,bracket_votes)
|
|
177
|
+
end
|
|
178
|
+
self.save
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def update_tally(period = :all_time, bracket_votes = nil)
|
|
182
|
+
|
|
183
|
+
bracket_time = TALLY_TYPES[period]
|
|
184
|
+
time_1 = Time.now - bracket_time[1]
|
|
185
|
+
time_2 = Time.now - bracket_time[0]
|
|
186
|
+
|
|
187
|
+
if bracket_votes
|
|
188
|
+
bracket_votes = bracket_votes.where(:updated_at.lte => time_2).and(:updated_at.gte => time_1)
|
|
189
|
+
else
|
|
190
|
+
bracket_votes = self.votes.where(:updated_at.lte => time_2).and(:updated_at.gte => time_1)
|
|
191
|
+
end
|
|
192
|
+
up_count = bracket_votes.where(vote: :up).count
|
|
193
|
+
down_count = bracket_votes.where(vote: :down).count
|
|
194
|
+
|
|
195
|
+
set_tally(:up, up_count, period)
|
|
196
|
+
set_tally(:down, down_count, period)
|
|
197
|
+
set_tally(:count, up_count+down_count, period)
|
|
198
|
+
set_tally(:point, up_count*self.class.options(:up) + down_count*self.class.options(:down), period)
|
|
199
|
+
|
|
200
|
+
bracket_votes
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def setup
|
|
204
|
+
#Add Empty Tally Documents
|
|
205
|
+
TALLY_TYPES.each_key do |t|
|
|
206
|
+
self.tallys << Tally.new(name: t) unless tallys.where(name: t).first
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def get_tally(tally_type, period = :all_time)
|
|
211
|
+
tally = self.tallys.find_or_initialize_by(name: period)
|
|
212
|
+
tally.public_send(tally_type)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def set_tally(tally_type, value, period = :all_time)
|
|
216
|
+
tally = self.tallys.find_or_initialize_by(name: period)
|
|
217
|
+
tally.public_send(tally_type.to_s+'=',value)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
# #Create Getter / Setter Methods for Tally Values
|
|
222
|
+
# TALLYS.each do |tally_name|
|
|
223
|
+
# define_method tally_name do
|
|
224
|
+
# get_tally(tally_name,:all_time)
|
|
225
|
+
# end
|
|
226
|
+
|
|
227
|
+
# define_method "#{tally_name}=" do |value|
|
|
228
|
+
# set_tally(tally_name,value,:all_time)
|
|
229
|
+
# end
|
|
230
|
+
# end
|
|
231
|
+
|
|
232
|
+
#CONVIENCE METHODS, WISH ABOVE WORKED
|
|
233
|
+
def point
|
|
234
|
+
get_tally(:point, :all_time)
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def point=(value)
|
|
238
|
+
set_tally(:point, value, :all_time)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def count
|
|
242
|
+
get_tally(:count, :all_time)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
def count=(value)
|
|
246
|
+
set_tally(:count, value, :all_time)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def up
|
|
250
|
+
get_tally(:up, :all_time)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def up=(value)
|
|
254
|
+
set_tally(:up, value, :all_time)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def down
|
|
258
|
+
get_tally(:down, :all_time)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def down=(value)
|
|
262
|
+
set_tally(:down, value, :all_time)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
#OLD CODE
|
|
269
|
+
# if array.count < hsh[:limit]
|
|
270
|
+
# diff = hsh[:limit] - array.count
|
|
271
|
+
# array += self.where(:tallys.exists => false).limit(diff)
|
|
272
|
+
# end
|
|
273
|
+
# array
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require "voterable/functions"
|
|
2
|
+
|
|
3
|
+
module Voterable
|
|
4
|
+
class Voter
|
|
5
|
+
include Mongoid::Document
|
|
6
|
+
|
|
7
|
+
has_many :voteables, as: :voter,
|
|
8
|
+
dependent: :delete,
|
|
9
|
+
class_name: "Voterable::Voteable"
|
|
10
|
+
|
|
11
|
+
has_many :votes, as: :voter,
|
|
12
|
+
dependent: :delete,
|
|
13
|
+
class_name: "Voterable::Vote"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
field :reputation, :type => Integer, default: 0
|
|
17
|
+
|
|
18
|
+
def vote(voteable, value)
|
|
19
|
+
voteable.vote(self, value)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
##
|
|
23
|
+
# Retuns the number of votes cast by user
|
|
24
|
+
# Example:
|
|
25
|
+
# >> a_voter.vote_count([1.days_in_seconds, 5.days_in_seconds])
|
|
26
|
+
# => 10
|
|
27
|
+
# Arguments:
|
|
28
|
+
# period: (array) time between which votes are counted, going backwards from now
|
|
29
|
+
#
|
|
30
|
+
def vote_count(period = [0, 1.days_in_seconds])
|
|
31
|
+
time_1 = Time.now - period[1]
|
|
32
|
+
time_2 = Time.now - period[0]
|
|
33
|
+
|
|
34
|
+
self.votes.where(:updated_at.lte => time_2).and(:updated_at.gte => time_1).count
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def calculate_reputation
|
|
38
|
+
#Contributed things
|
|
39
|
+
# sum = self.things.count + self.things.count
|
|
40
|
+
sum = 0
|
|
41
|
+
|
|
42
|
+
#Things that got votes
|
|
43
|
+
self.voteables.each{|t| sum+=t.votes_point}
|
|
44
|
+
|
|
45
|
+
#Vote Back
|
|
46
|
+
self.voteables.each do |v|
|
|
47
|
+
sum += v.voteable.class.vtback(v.vote)
|
|
48
|
+
end
|
|
49
|
+
self.reputation = sum
|
|
50
|
+
self.save
|
|
51
|
+
# sum = sum > 0 ? sum : 0
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
end
|
data/lib/voterable.rb
ADDED
data/spec/factories.rb
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#-- Voterable
|
|
2
|
+
require 'voterable'
|
|
3
|
+
|
|
4
|
+
class Voteable < Voterable::Voteable
|
|
5
|
+
|
|
6
|
+
voteable self, :up => +5, :down => -2 #, :index => true
|
|
7
|
+
voteback self, :up => +1, :down => -2
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class Voter < Voterable::Voter
|
|
11
|
+
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
class Vote < Voterable::Vote
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
FactoryGirl.define do
|
|
18
|
+
|
|
19
|
+
factory :voter do
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
factory :voteable do
|
|
23
|
+
association :voter, :factory => :voter
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
factory :vote do
|
|
27
|
+
created_at Time.now
|
|
28
|
+
updated_at Time.now
|
|
29
|
+
association :voter
|
|
30
|
+
association :voteable
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# spec_helper
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'bundler/setup'
|
|
5
|
+
# Bundler.setup
|
|
6
|
+
|
|
7
|
+
require 'voterable' # and any other gems you need
|
|
8
|
+
|
|
9
|
+
require 'voterable/functions'
|
|
10
|
+
|
|
11
|
+
require 'rspec'
|
|
12
|
+
require 'factory_girl'
|
|
13
|
+
FactoryGirl.find_definitions
|
|
14
|
+
|
|
15
|
+
Mongoid.configure do |config|
|
|
16
|
+
name = 'voterable_test'
|
|
17
|
+
host = 'localhost'
|
|
18
|
+
config.master = Mongo::Connection.new.db(name)
|
|
19
|
+
config.autocreate_indexes = true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
RSpec.configure do |config|
|
|
23
|
+
# == Mock Framework
|
|
24
|
+
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
|
|
25
|
+
config.mock_with :rspec
|
|
26
|
+
|
|
27
|
+
#Focus on one test with :focus
|
|
28
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
|
29
|
+
config.filter_run :focus => true
|
|
30
|
+
config.run_all_when_everything_filtered = true
|
|
31
|
+
end
|
data/spec/voter_spec.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
require 'spec_helper'
|
|
3
|
+
|
|
4
|
+
describe Voterable::Voter do
|
|
5
|
+
|
|
6
|
+
context "Voter has voted on thngs" do
|
|
7
|
+
|
|
8
|
+
before(:each) do
|
|
9
|
+
@voter = Factory(:voter)
|
|
10
|
+
@now = Factory(:vote, updated_at: Time.now,
|
|
11
|
+
voter: @voter)
|
|
12
|
+
@half_day = Factory(:vote, updated_at: Time.now-0.5.days_in_seconds,
|
|
13
|
+
voter: @voter)
|
|
14
|
+
@two_day = Factory(:vote, updated_at: Time.now-2.days_in_seconds,
|
|
15
|
+
voter: @voter)
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
it{@voter.vote_count().should == 2}
|
|
19
|
+
it{@voter.vote_count([0,3.days_in_seconds]).should == 3}
|
|
20
|
+
it{@voter.vote_count([0.25.days_in_seconds,2.5.days_in_seconds]).should == 2}
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
data/spec/voting_spec.rb
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "Voting" do
|
|
4
|
+
|
|
5
|
+
before(:each) do
|
|
6
|
+
@voteable = Factory.create(:voteable)
|
|
7
|
+
@owner = Factory.create(:voter)
|
|
8
|
+
@voter = Factory.create(:voter)
|
|
9
|
+
@owner.voteables << @voteable
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it{@voteable.should respond_to(:votes_point)}
|
|
13
|
+
it{@voter.should respond_to(:reputation)}
|
|
14
|
+
|
|
15
|
+
context "when up voted by voter" do
|
|
16
|
+
before(:each) do
|
|
17
|
+
@voteable.vote(@voter,:up)
|
|
18
|
+
end
|
|
19
|
+
it{@voteable.point.should == 5}
|
|
20
|
+
it{@voteable.up.should == 1}
|
|
21
|
+
it{@voteable.down.should == 0}
|
|
22
|
+
it{@voteable.count.should == 1}
|
|
23
|
+
|
|
24
|
+
it{@owner.reputation.should == 5}
|
|
25
|
+
it{@voter.reputation.should == 1}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context "when down voted by voter" do
|
|
29
|
+
before(:each) do
|
|
30
|
+
@voteable.vote(@voter,:down)
|
|
31
|
+
end
|
|
32
|
+
it{@voteable.point.should == -2}
|
|
33
|
+
it{@voteable.up.should == 0}
|
|
34
|
+
it{@voteable.down.should == 1}
|
|
35
|
+
it{@voteable.count.should == 1}
|
|
36
|
+
|
|
37
|
+
it{@owner.reputation.should == -2}
|
|
38
|
+
it{@voter.reputation.should == -2}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
data/voterable.gemspec
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
require "voterable/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = "voterable"
|
|
7
|
+
s.version = Voterable::VERSION
|
|
8
|
+
s.authors = ["Ben"]
|
|
9
|
+
s.email = ["benguest@gmail.com"]
|
|
10
|
+
s.homepage = ""
|
|
11
|
+
s.summary = %q{Mongoid dependant user voting rating}
|
|
12
|
+
s.description = %q{Hackish implementaiton of voting on of voteable objects by a voter}
|
|
13
|
+
|
|
14
|
+
s.rubyforge_project = "voterable"
|
|
15
|
+
|
|
16
|
+
s.files = `git ls-files`.split("\n")
|
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
19
|
+
s.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
# specify any dependencies here; for example:
|
|
22
|
+
|
|
23
|
+
# General Dependency's
|
|
24
|
+
s.add_dependency "mongoid", ["2.3.0"]
|
|
25
|
+
s.add_dependency "bson", ["= 1.4.0"]
|
|
26
|
+
s.add_dependency "bson_ext", ["= 1.4.0"]
|
|
27
|
+
|
|
28
|
+
#Testing
|
|
29
|
+
s.add_development_dependency "rspec"
|
|
30
|
+
s.add_development_dependency "factory_girl", ["~> 2.1.0"]
|
|
31
|
+
|
|
32
|
+
#Automated Testing
|
|
33
|
+
s.add_development_dependency "spork", [ "> 0.9.0.rc"]
|
|
34
|
+
s.add_development_dependency "guard"
|
|
35
|
+
s.add_development_dependency "guard-rspec"
|
|
36
|
+
s.add_development_dependency "guard-spork"
|
|
37
|
+
s.add_development_dependency "database_cleaner"
|
|
38
|
+
|
|
39
|
+
s.add_development_dependency "rb-fsevent"
|
|
40
|
+
s.add_development_dependency "growl"
|
|
41
|
+
|
|
42
|
+
# s.add_runtime_dependency "rest-client"
|
|
43
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: voterable
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Ben
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2011-12-06 00:00:00.000000000Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: mongoid
|
|
16
|
+
requirement: &70277287991300 !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - =
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: 2.3.0
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: *70277287991300
|
|
25
|
+
- !ruby/object:Gem::Dependency
|
|
26
|
+
name: bson
|
|
27
|
+
requirement: &70277287990780 !ruby/object:Gem::Requirement
|
|
28
|
+
none: false
|
|
29
|
+
requirements:
|
|
30
|
+
- - =
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 1.4.0
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: *70277287990780
|
|
36
|
+
- !ruby/object:Gem::Dependency
|
|
37
|
+
name: bson_ext
|
|
38
|
+
requirement: &70277287990300 !ruby/object:Gem::Requirement
|
|
39
|
+
none: false
|
|
40
|
+
requirements:
|
|
41
|
+
- - =
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: 1.4.0
|
|
44
|
+
type: :runtime
|
|
45
|
+
prerelease: false
|
|
46
|
+
version_requirements: *70277287990300
|
|
47
|
+
- !ruby/object:Gem::Dependency
|
|
48
|
+
name: rspec
|
|
49
|
+
requirement: &70277287989900 !ruby/object:Gem::Requirement
|
|
50
|
+
none: false
|
|
51
|
+
requirements:
|
|
52
|
+
- - ! '>='
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
type: :development
|
|
56
|
+
prerelease: false
|
|
57
|
+
version_requirements: *70277287989900
|
|
58
|
+
- !ruby/object:Gem::Dependency
|
|
59
|
+
name: factory_girl
|
|
60
|
+
requirement: &70277287989320 !ruby/object:Gem::Requirement
|
|
61
|
+
none: false
|
|
62
|
+
requirements:
|
|
63
|
+
- - ~>
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: 2.1.0
|
|
66
|
+
type: :development
|
|
67
|
+
prerelease: false
|
|
68
|
+
version_requirements: *70277287989320
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: spork
|
|
71
|
+
requirement: &70277287988800 !ruby/object:Gem::Requirement
|
|
72
|
+
none: false
|
|
73
|
+
requirements:
|
|
74
|
+
- - ! '>'
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: 0.9.0.rc
|
|
77
|
+
type: :development
|
|
78
|
+
prerelease: false
|
|
79
|
+
version_requirements: *70277287988800
|
|
80
|
+
- !ruby/object:Gem::Dependency
|
|
81
|
+
name: guard
|
|
82
|
+
requirement: &70277287988420 !ruby/object:Gem::Requirement
|
|
83
|
+
none: false
|
|
84
|
+
requirements:
|
|
85
|
+
- - ! '>='
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
version: '0'
|
|
88
|
+
type: :development
|
|
89
|
+
prerelease: false
|
|
90
|
+
version_requirements: *70277287988420
|
|
91
|
+
- !ruby/object:Gem::Dependency
|
|
92
|
+
name: guard-rspec
|
|
93
|
+
requirement: &70277287987960 !ruby/object:Gem::Requirement
|
|
94
|
+
none: false
|
|
95
|
+
requirements:
|
|
96
|
+
- - ! '>='
|
|
97
|
+
- !ruby/object:Gem::Version
|
|
98
|
+
version: '0'
|
|
99
|
+
type: :development
|
|
100
|
+
prerelease: false
|
|
101
|
+
version_requirements: *70277287987960
|
|
102
|
+
- !ruby/object:Gem::Dependency
|
|
103
|
+
name: guard-spork
|
|
104
|
+
requirement: &70277287987540 !ruby/object:Gem::Requirement
|
|
105
|
+
none: false
|
|
106
|
+
requirements:
|
|
107
|
+
- - ! '>='
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
110
|
+
type: :development
|
|
111
|
+
prerelease: false
|
|
112
|
+
version_requirements: *70277287987540
|
|
113
|
+
- !ruby/object:Gem::Dependency
|
|
114
|
+
name: database_cleaner
|
|
115
|
+
requirement: &70277287987120 !ruby/object:Gem::Requirement
|
|
116
|
+
none: false
|
|
117
|
+
requirements:
|
|
118
|
+
- - ! '>='
|
|
119
|
+
- !ruby/object:Gem::Version
|
|
120
|
+
version: '0'
|
|
121
|
+
type: :development
|
|
122
|
+
prerelease: false
|
|
123
|
+
version_requirements: *70277287987120
|
|
124
|
+
- !ruby/object:Gem::Dependency
|
|
125
|
+
name: rb-fsevent
|
|
126
|
+
requirement: &70277287986700 !ruby/object:Gem::Requirement
|
|
127
|
+
none: false
|
|
128
|
+
requirements:
|
|
129
|
+
- - ! '>='
|
|
130
|
+
- !ruby/object:Gem::Version
|
|
131
|
+
version: '0'
|
|
132
|
+
type: :development
|
|
133
|
+
prerelease: false
|
|
134
|
+
version_requirements: *70277287986700
|
|
135
|
+
- !ruby/object:Gem::Dependency
|
|
136
|
+
name: growl
|
|
137
|
+
requirement: &70277287986260 !ruby/object:Gem::Requirement
|
|
138
|
+
none: false
|
|
139
|
+
requirements:
|
|
140
|
+
- - ! '>='
|
|
141
|
+
- !ruby/object:Gem::Version
|
|
142
|
+
version: '0'
|
|
143
|
+
type: :development
|
|
144
|
+
prerelease: false
|
|
145
|
+
version_requirements: *70277287986260
|
|
146
|
+
description: Hackish implementaiton of voting on of voteable objects by a voter
|
|
147
|
+
email:
|
|
148
|
+
- benguest@gmail.com
|
|
149
|
+
executables: []
|
|
150
|
+
extensions: []
|
|
151
|
+
extra_rdoc_files: []
|
|
152
|
+
files:
|
|
153
|
+
- .gitignore
|
|
154
|
+
- .rspec
|
|
155
|
+
- .rvmrc
|
|
156
|
+
- Gemfile
|
|
157
|
+
- Guardfile
|
|
158
|
+
- Rakefile
|
|
159
|
+
- lib/voterable.rb
|
|
160
|
+
- lib/voterable/functions.rb
|
|
161
|
+
- lib/voterable/tally.rb
|
|
162
|
+
- lib/voterable/version.rb
|
|
163
|
+
- lib/voterable/vote.rb
|
|
164
|
+
- lib/voterable/voteable.rb
|
|
165
|
+
- lib/voterable/voter.rb
|
|
166
|
+
- spec/factories.rb
|
|
167
|
+
- spec/spec_helper.rb
|
|
168
|
+
- spec/voter_spec.rb
|
|
169
|
+
- spec/voting_spec.rb
|
|
170
|
+
- voterable.gemspec
|
|
171
|
+
homepage: ''
|
|
172
|
+
licenses: []
|
|
173
|
+
post_install_message:
|
|
174
|
+
rdoc_options: []
|
|
175
|
+
require_paths:
|
|
176
|
+
- lib
|
|
177
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
178
|
+
none: false
|
|
179
|
+
requirements:
|
|
180
|
+
- - ! '>='
|
|
181
|
+
- !ruby/object:Gem::Version
|
|
182
|
+
version: '0'
|
|
183
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
184
|
+
none: false
|
|
185
|
+
requirements:
|
|
186
|
+
- - ! '>='
|
|
187
|
+
- !ruby/object:Gem::Version
|
|
188
|
+
version: '0'
|
|
189
|
+
requirements: []
|
|
190
|
+
rubyforge_project: voterable
|
|
191
|
+
rubygems_version: 1.8.10
|
|
192
|
+
signing_key:
|
|
193
|
+
specification_version: 3
|
|
194
|
+
summary: Mongoid dependant user voting rating
|
|
195
|
+
test_files:
|
|
196
|
+
- spec/factories.rb
|
|
197
|
+
- spec/spec_helper.rb
|
|
198
|
+
- spec/voter_spec.rb
|
|
199
|
+
- spec/voting_spec.rb
|