thumbs_up 0.4.6 → 0.5.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.markdown → CHANGELOG.md} +0 -0
- data/Gemfile +1 -13
- data/MIT-LICENSE +1 -1
- data/{README.markdown → README.md} +38 -35
- data/Rakefile +10 -20
- data/lib/acts_as_voteable.rb +24 -98
- data/lib/acts_as_voter.rb +2 -2
- data/lib/thumbs_up/version.rb +3 -0
- data/test/test_helper.rb +12 -4
- data/test/{test_thumbs_up.rb → thumbs_up_test.rb} +58 -28
- metadata +38 -25
- data/VERSION +0 -1
- data/thumbs_up.gemspec +0 -63
|
File without changes
|
data/Gemfile
CHANGED
data/MIT-LICENSE
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
ThumbsUp
|
|
2
2
|
=======
|
|
3
3
|
|
|
4
|
+
**Note: Version 0.5.x is a breaking change for #plusminus_tally and #tally, with > 50% speedups.**
|
|
5
|
+
|
|
4
6
|
A ridiculously straightforward and simple package 'o' code to enable voting in your application, a la stackoverflow.com, etc.
|
|
5
7
|
Allows an arbitrary number of entities (users, etc.) to vote on models.
|
|
6
8
|
|
|
@@ -67,50 +69,38 @@ Usage
|
|
|
67
69
|
voter.vote_exclusively_for(voteable) # Removes any previous votes by that particular voter, and votes for.
|
|
68
70
|
voter.vote_exclusively_against(voteable) # Removes any previous votes by that particular voter, and votes against.
|
|
69
71
|
|
|
72
|
+
vote.unvote_for(voteable) # Clears all votes for that user
|
|
73
|
+
|
|
70
74
|
### Querying votes
|
|
71
75
|
|
|
72
76
|
Did the first user vote for the Car with id = 2 already?
|
|
73
77
|
|
|
74
78
|
u = User.first
|
|
75
|
-
|
|
79
|
+
u.vote_for(Car.find(2))
|
|
80
|
+
u.voted_on?(Car.find(2)) #=> true
|
|
81
|
+
|
|
82
|
+
Did the first user vote for or against the Car with id = 2?
|
|
83
|
+
|
|
84
|
+
u = User.first
|
|
85
|
+
u.vote_for(Car.find(2))
|
|
86
|
+
u.voted_for?(Car.find(2)) #=> true
|
|
87
|
+
u.voted_against?(Car.find(2)) #=> false
|
|
76
88
|
|
|
77
89
|
#### Tallying Votes
|
|
78
90
|
|
|
79
91
|
You can easily retrieve voteable object collections based on the properties of their votes:
|
|
80
92
|
|
|
81
|
-
@items = Item.tally(
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
##### Tally Options:
|
|
93
|
-
:start_at - Restrict the votes to those created after a certain time
|
|
94
|
-
:end_at - Restrict the votes to those created before a certain time
|
|
95
|
-
:conditions - A piece of SQL conditions to add to the query
|
|
96
|
-
:limit - The maximum number of voteables to return
|
|
97
|
-
:order - A piece of SQL to order by. Eg 'votes.count desc' or 'voteable.created_at desc'
|
|
98
|
-
:at_least - Item must have at least X votes
|
|
99
|
-
:at_most - Item may not have more than X votes
|
|
100
|
-
|
|
101
|
-
##### Tallying Rank ("Plusminus")
|
|
102
|
-
|
|
103
|
-
This is similar to tallying votes, but this will return voteable object collections based on the sum of the differences between up and down votes (ups are +1, downs are -1). For Instance, a voteable with 3 upvotes and 2
|
|
104
|
-
downvotes will have a plusminus of 1.
|
|
105
|
-
|
|
106
|
-
##### Plusminus Tally Options:
|
|
107
|
-
:start_at - Restrict the votes to those created after a certain time
|
|
108
|
-
:end_at - Restrict the votes to those created before a certain time
|
|
109
|
-
:conditions - A piece of SQL conditions to add to the query
|
|
110
|
-
:limit - The maximum number of voteables to return
|
|
111
|
-
:ascending - Boolean Default false. If specified true, results will be returned in ascending order (from bottom up)
|
|
112
|
-
:at_least - Item must have at least X votes
|
|
113
|
-
:at_most - Item may not have more than X votes
|
|
93
|
+
@items = Item.tally.limit(10).where('created_at > ?', 2.days.ago).having('vote_count < 10')
|
|
94
|
+
|
|
95
|
+
This will select the Items with less than 10 votes, the votes having been cast within the last two days, with a limit of 10 items. *This tallies all votes, regardless of whether they are +1 (up) or -1 (down).* The #tally method returns an ActiveRecord Relation, so you can chain the normal method calls on to it.
|
|
96
|
+
|
|
97
|
+
#### Tallying Rank ("Plusminus")
|
|
98
|
+
|
|
99
|
+
**You most likely want to use this over the normal tally**
|
|
100
|
+
|
|
101
|
+
This is similar to tallying votes, but this will return voteable object collections based on the sum of the differences between up and down votes (ups are +1, downs are -1). For Instance, a voteable with 3 upvotes and 2 downvotes will have a plusminus of 1.
|
|
102
|
+
|
|
103
|
+
@items = Item.plusminus_tally.limit(10).where('created_at > ?', 2.days.ago).having('plusminus > 10')
|
|
114
104
|
|
|
115
105
|
#### Lower level queries
|
|
116
106
|
|
|
@@ -141,7 +131,20 @@ You can also use `--unique-voting false` when running the generator command:
|
|
|
141
131
|
|
|
142
132
|
rails generate thumbs_up --unique-voting false
|
|
143
133
|
|
|
134
|
+
#### Testing ThumbsUp
|
|
135
|
+
|
|
136
|
+
Testing is a bit more than trivial now as our #tally and #plusminus_tally queries don't function properly under SQLite. To set up for testing:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
$ mysql -uroot # You may have set a password locally. Change as needed.
|
|
140
|
+
> GRANT ALL PRIVILEGES ON 'thumbs_up_test' to 'test'@'localhost' IDENTIFIED BY 'test';
|
|
141
|
+
> CREATE DATABASE 'thumbs_up_test';
|
|
142
|
+
> exit;
|
|
143
|
+
|
|
144
|
+
$ rake # Runs the test suite.
|
|
145
|
+
```
|
|
146
|
+
|
|
144
147
|
Credits
|
|
145
148
|
=======
|
|
146
149
|
|
|
147
|
-
Basic scaffold is from Peter Jackson's work on VoteFu / ActsAsVoteable. All code updated for Rails 3, cleaned up for speed and clarity, karma calculation fixed, and (hopefully) zero introduced bugs.
|
|
150
|
+
Basic scaffold is from Peter Jackson's work on VoteFu / ActsAsVoteable. All code updated for Rails 3, cleaned up for speed and clarity, karma calculation fixed, and (hopefully) zero introduced bugs.
|
data/Rakefile
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# encoding: UTF-8
|
|
2
2
|
require 'rubygems'
|
|
3
|
-
require 'bundler'
|
|
3
|
+
require 'bundler' unless defined?(Bundler)
|
|
4
|
+
|
|
5
|
+
$LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
|
|
6
|
+
require 'thumbs_up/version'
|
|
4
7
|
|
|
5
8
|
begin
|
|
6
9
|
Bundler.setup(:default, :development)
|
|
@@ -11,18 +14,6 @@ rescue Bundler::BundlerError => e
|
|
|
11
14
|
end
|
|
12
15
|
require 'rake'
|
|
13
16
|
|
|
14
|
-
require 'jeweler'
|
|
15
|
-
Jeweler::Tasks.new do |gem|
|
|
16
|
-
gem.name = "thumbs_up"
|
|
17
|
-
gem.summary = "Voting for ActiveRecord with multiple vote sources and karma calculation."
|
|
18
|
-
gem.description = "ThumbsUp provides dead-simple voting capabilities to ActiveRecord models with karma calculation, a la stackoverflow.com."
|
|
19
|
-
gem.email = "brady@ldawn.com"
|
|
20
|
-
gem.homepage = "http://github.com/brady8/thumbs_up"
|
|
21
|
-
gem.authors = ["Brady Bouchard", "Peter Jackson", "Cosmin Radoi", "Bence Nagy", "Rob Maddox", "Wojciech Wnętrzak"]
|
|
22
|
-
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
|
23
|
-
end
|
|
24
|
-
Jeweler::RubygemsDotOrgTasks.new
|
|
25
|
-
|
|
26
17
|
require 'rake/testtask'
|
|
27
18
|
Rake::TestTask.new(:test) do |test|
|
|
28
19
|
test.libs << 'lib' << 'test'
|
|
@@ -30,13 +21,12 @@ Rake::TestTask.new(:test) do |test|
|
|
|
30
21
|
test.verbose = true
|
|
31
22
|
end
|
|
32
23
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
24
|
+
task :build do
|
|
25
|
+
system "gem build thumbs_up.gemspec"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
task :release => :build do
|
|
29
|
+
system "gem push thumbs_up-#{ThumbsUp::VERSION}.gem"
|
|
40
30
|
end
|
|
41
31
|
|
|
42
32
|
task :default => :test
|
data/lib/acts_as_voteable.rb
CHANGED
|
@@ -16,108 +16,35 @@ module ThumbsUp
|
|
|
16
16
|
|
|
17
17
|
module SingletonMethods
|
|
18
18
|
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# :conditions - (string) Extra conditions, if you'd like.
|
|
31
|
-
def plusminus_tally(*args)
|
|
32
|
-
options = args.extract_options!
|
|
33
|
-
|
|
34
|
-
tsub0 = Vote
|
|
35
|
-
tsub0 = tsub0.where("vote = ?", false)
|
|
36
|
-
tsub0 = tsub0.where("voteable_type = ?", self.name)
|
|
37
|
-
tsub0 = tsub0.group("voteable_id")
|
|
38
|
-
tsub0 = tsub0.select("DISTINCT voteable_id, COUNT(vote) as votes_against")
|
|
39
|
-
|
|
40
|
-
tsub1 = Vote
|
|
41
|
-
tsub1 = tsub1.where("vote = ?", true)
|
|
42
|
-
tsub1 = tsub1.where("voteable_type = ?", self.name)
|
|
43
|
-
tsub1 = tsub1.group("voteable_id")
|
|
44
|
-
tsub1 = tsub1.select("DISTINCT voteable_id, COUNT(vote) as votes_for")
|
|
45
|
-
|
|
46
|
-
t = self.joins("LEFT OUTER JOIN (SELECT DISTINCT #{Vote.table_name}.*,
|
|
47
|
-
(COALESCE(vfor.votes_for, 0)-COALESCE(against.votes_against, 0)) AS vote_total
|
|
48
|
-
FROM (#{Vote.table_name} LEFT JOIN
|
|
49
|
-
(#{tsub0.to_sql}) AS against ON #{Vote.table_name}.voteable_id = against.voteable_id)
|
|
50
|
-
LEFT JOIN
|
|
51
|
-
(#{tsub1.to_sql}) as vfor ON #{Vote.table_name}.voteable_id = vfor.voteable_id)
|
|
52
|
-
AS joined_#{Vote.table_name} ON #{self.table_name}.#{self.primary_key} =
|
|
53
|
-
joined_#{Vote.table_name}.voteable_id")
|
|
54
|
-
|
|
55
|
-
t = t.group("joined_#{Vote.table_name}.voteable_id, joined_#{Vote.table_name}.vote_total, #{column_names_for_tally}")
|
|
56
|
-
t = t.limit(options[:limit]) if options[:limit]
|
|
57
|
-
t = t.where("joined_#{Vote.table_name}.voteable_type = '#{self.name}'")
|
|
58
|
-
t = t.where("joined_#{Vote.table_name}.created_at >= ?", options[:start_at]) if options[:start_at]
|
|
59
|
-
t = t.where("joined_#{Vote.table_name}.created_at <= ?", options[:end_at]) if options[:end_at]
|
|
60
|
-
t = t.where(options[:conditions]) if options[:conditions]
|
|
61
|
-
t = options[:ascending] ? t.order("joined_#{Vote.table_name}.vote_total") : t.order("joined_#{Vote.table_name}.vote_total DESC")
|
|
62
|
-
|
|
63
|
-
t = t.having([
|
|
64
|
-
"COUNT(joined_#{Vote.table_name}.voteable_id) > 0",
|
|
65
|
-
(options[:at_least] ?
|
|
66
|
-
"joined_#{Vote.table_name}.vote_total >= #{sanitize(options[:at_least])}" : nil
|
|
67
|
-
),
|
|
68
|
-
(options[:at_most] ?
|
|
69
|
-
"joined_#{Vote.table_name}.vote_total <= #{sanitize(options[:at_most])}" : nil
|
|
70
|
-
)
|
|
71
|
-
].compact.join(' AND '))
|
|
72
|
-
|
|
73
|
-
t.select("#{self.table_name}.*, joined_#{Vote.table_name}.vote_total")
|
|
19
|
+
# Calculate the plusminus for a group of voteables in one database query.
|
|
20
|
+
# This returns an Arel relation, so you can add conditions as you like chained on to
|
|
21
|
+
# this method call.
|
|
22
|
+
# i.e. Posts.tally.where('votes.created_at > ?', 2.days.ago)
|
|
23
|
+
def plusminus_tally
|
|
24
|
+
t = self.joins("LEFT OUTER JOIN #{Vote.table_name} ON #{self.table_name}.id = #{Vote.table_name}.voteable_id")
|
|
25
|
+
t = t.order("plusminus DESC")
|
|
26
|
+
t = t.group("#{self.table_name}.id")
|
|
27
|
+
t = t.select("#{self.table_name}.*")
|
|
28
|
+
t = t.select("SUM(CASE CAST(#{Vote.table_name}.vote AS UNSIGNED) WHEN 1 THEN 1 WHEN 0 THEN -1 ELSE 0 END) AS plusminus")
|
|
29
|
+
t = t.select("COUNT(#{Vote.table_name}.id) AS vote_count")
|
|
74
30
|
end
|
|
75
|
-
|
|
31
|
+
|
|
76
32
|
# #rank_tally is depreciated.
|
|
77
33
|
alias_method :rank_tally, :plusminus_tally
|
|
78
34
|
|
|
79
35
|
# Calculate the vote counts for all voteables of my type.
|
|
80
|
-
# This method returns all voteables
|
|
36
|
+
# This method returns all voteables (even without any votes) by default.
|
|
81
37
|
# The vote count for each voteable is available as #vote_count.
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
# :end_at - Restrict the votes to those created before a certain time
|
|
86
|
-
# :conditions - A piece of SQL conditions to add to the query
|
|
87
|
-
# :limit - The maximum number of voteables to return
|
|
88
|
-
# :order - A piece of SQL to order by. Eg 'vote_count DESC' or 'voteable.created_at DESC'
|
|
89
|
-
# :at_least - Item must have at least X votes
|
|
90
|
-
# :at_most - Item may not have more than X votes
|
|
38
|
+
# This returns an Arel relation, so you can add conditions as you like chained on to
|
|
39
|
+
# this method call.
|
|
40
|
+
# i.e. Posts.tally.where('votes.created_at > ?', 2.days.ago)
|
|
91
41
|
def tally(*args)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
t =
|
|
98
|
-
|
|
99
|
-
# We join so that you can order by columns on the voteable model.
|
|
100
|
-
t = t.joins("LEFT OUTER JOIN #{Vote.table_name} ON #{self.table_name}.#{self.primary_key} = #{Vote.table_name}.voteable_id")
|
|
101
|
-
|
|
102
|
-
t = t.group("#{Vote.table_name}.voteable_id, #{column_names_for_tally}")
|
|
103
|
-
t = t.limit(options[:limit]) if options[:limit]
|
|
104
|
-
t = t.where("#{Vote.table_name}.created_at >= ?", options[:start_at]) if options[:start_at]
|
|
105
|
-
t = t.where("#{Vote.table_name}.created_at <= ?", options[:end_at]) if options[:end_at]
|
|
106
|
-
t = t.where(options[:conditions]) if options[:conditions]
|
|
107
|
-
t = options[:order] ? t.order(options[:order]) : t.order("#{vote_count} DESC")
|
|
108
|
-
|
|
109
|
-
# I haven't been able to confirm this bug yet, but Arel (2.0.7) currently blows up
|
|
110
|
-
# with multiple 'having' clauses. So we hack them all into one for now.
|
|
111
|
-
# If you have a more elegant solution, a pull request on Github would be greatly appreciated.
|
|
112
|
-
t = t.having([
|
|
113
|
-
"#{vote_count} > 0",
|
|
114
|
-
(options[:at_least] ? "#{vote_count} >= #{sanitize(options[:at_least])}" : nil),
|
|
115
|
-
(options[:at_most] ? "#{vote_count} <= #{sanitize(options[:at_most])}" : nil)
|
|
116
|
-
].compact.join(' AND '))
|
|
117
|
-
# t = t.having("#{vote_count} > 0")
|
|
118
|
-
# t = t.having(["#{vote_count} >= ?", options[:at_least]]) if options[:at_least]
|
|
119
|
-
# t = t.having(["#{vote_count} <= ?", options[:at_most]]) if options[:at_most]
|
|
120
|
-
t.select("#{self.table_name}.*, COUNT(#{Vote.table_name}.voteable_id) AS vote_count")
|
|
42
|
+
t = self.joins("LEFT OUTER JOIN #{Vote.table_name} ON #{self.table_name}.id = #{Vote.table_name}.voteable_id")
|
|
43
|
+
t = t.order("vote_count DESC")
|
|
44
|
+
t = t.group("#{self.table_name}.id")
|
|
45
|
+
t = t.select("#{self.table_name}.*")
|
|
46
|
+
t = t.select("#{Vote.table_name}.*")
|
|
47
|
+
t = t.select("COUNT(#{Vote.table_name}.id) AS vote_count")
|
|
121
48
|
end
|
|
122
49
|
|
|
123
50
|
def column_names_for_tally
|
|
@@ -129,11 +56,11 @@ module ThumbsUp
|
|
|
129
56
|
module InstanceMethods
|
|
130
57
|
|
|
131
58
|
def votes_for
|
|
132
|
-
|
|
59
|
+
self.votes.where(:vote => true).count
|
|
133
60
|
end
|
|
134
61
|
|
|
135
62
|
def votes_against
|
|
136
|
-
|
|
63
|
+
self.votes.where(:vote => false).count
|
|
137
64
|
end
|
|
138
65
|
|
|
139
66
|
def percent_for
|
|
@@ -162,7 +89,6 @@ module ThumbsUp
|
|
|
162
89
|
0 < Vote.where(
|
|
163
90
|
:voteable_id => self.id,
|
|
164
91
|
:voteable_type => self.class.name,
|
|
165
|
-
:voter_type => voter.class.name,
|
|
166
92
|
:voter_id => voter.id
|
|
167
93
|
).count
|
|
168
94
|
end
|
data/lib/acts_as_voter.rb
CHANGED
|
@@ -77,13 +77,13 @@ module ThumbsUp #:nodoc:
|
|
|
77
77
|
def vote(voteable, options = {})
|
|
78
78
|
raise ArgumentError, "you must specify :up or :down in order to vote" unless options[:direction] && [:up, :down].include?(options[:direction].to_sym)
|
|
79
79
|
if options[:exclusive]
|
|
80
|
-
self.
|
|
80
|
+
self.unvote_for(voteable)
|
|
81
81
|
end
|
|
82
82
|
direction = (options[:direction].to_sym == :up)
|
|
83
83
|
Vote.create!(:vote => direction, :voteable => voteable, :voter => self)
|
|
84
84
|
end
|
|
85
85
|
|
|
86
|
-
def
|
|
86
|
+
def unvote_for(voteable)
|
|
87
87
|
Vote.where(
|
|
88
88
|
:voter_id => self.id,
|
|
89
89
|
:voter_type => self.class.name,
|
data/test/test_helper.rb
CHANGED
|
@@ -7,10 +7,18 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
|
7
7
|
|
|
8
8
|
require 'active_record'
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
:adapter =>
|
|
12
|
-
:database =>
|
|
13
|
-
|
|
10
|
+
config = {
|
|
11
|
+
:adapter => 'mysql2',
|
|
12
|
+
:database => 'thumbs_up_test',
|
|
13
|
+
:username => 'test',
|
|
14
|
+
:password => 'test',
|
|
15
|
+
:socket => '/tmp/mysql.sock'
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
ActiveRecord::Base.establish_connection(config)
|
|
19
|
+
ActiveRecord::Base.connection.drop_database config[:database] rescue nil
|
|
20
|
+
ActiveRecord::Base.connection.create_database config[:database]
|
|
21
|
+
ActiveRecord::Base.establish_connection(config)
|
|
14
22
|
|
|
15
23
|
ActiveRecord::Migration.verbose = false
|
|
16
24
|
|
|
@@ -50,10 +50,10 @@ class TestThumbsUp < Test::Unit::TestCase
|
|
|
50
50
|
assert_not_nil user_for.vote_exclusively_against(item)
|
|
51
51
|
assert_equal true, user_for.voted_against?(item)
|
|
52
52
|
|
|
53
|
-
user_for.
|
|
53
|
+
user_for.unvote_for(item)
|
|
54
54
|
assert_equal 0, user_for.vote_count
|
|
55
55
|
|
|
56
|
-
user_against.
|
|
56
|
+
user_against.unvote_for(item)
|
|
57
57
|
assert_equal 0, user_against.vote_count
|
|
58
58
|
|
|
59
59
|
assert_raises(ArgumentError) do
|
|
@@ -100,8 +100,7 @@ class TestThumbsUp < Test::Unit::TestCase
|
|
|
100
100
|
|
|
101
101
|
def test_tally_empty
|
|
102
102
|
item = Item.create(:name => 'XBOX', :description => 'XBOX console')
|
|
103
|
-
|
|
104
|
-
assert_equal 0, Item.tally.length
|
|
103
|
+
assert_equal 0, Item.tally.having('vote_count > 0').length
|
|
105
104
|
end
|
|
106
105
|
|
|
107
106
|
def test_tally_starts_at
|
|
@@ -112,8 +111,8 @@ class TestThumbsUp < Test::Unit::TestCase
|
|
|
112
111
|
vote.created_at = 3.days.ago
|
|
113
112
|
vote.save
|
|
114
113
|
|
|
115
|
-
assert_equal 0, Item.tally(
|
|
116
|
-
assert_equal 1, Item.tally(
|
|
114
|
+
assert_equal 0, Item.tally.where('created_at > ?', 2.days.ago).length
|
|
115
|
+
assert_equal 1, Item.tally.where('created_at > ?', 4.days.ago).length
|
|
117
116
|
end
|
|
118
117
|
|
|
119
118
|
def test_tally_end_at
|
|
@@ -124,8 +123,8 @@ class TestThumbsUp < Test::Unit::TestCase
|
|
|
124
123
|
vote.created_at = 3.days.from_now
|
|
125
124
|
vote.save
|
|
126
125
|
|
|
127
|
-
assert_equal 0, Item.tally(
|
|
128
|
-
assert_equal 1, Item.tally(
|
|
126
|
+
assert_equal 0, Item.tally.where('created_at < ?', 2.days.from_now).length
|
|
127
|
+
assert_equal 1, Item.tally.where('created_at < ?', 4.days.from_now).length
|
|
129
128
|
end
|
|
130
129
|
|
|
131
130
|
def test_tally_between_start_at_end_at
|
|
@@ -141,14 +140,18 @@ class TestThumbsUp < Test::Unit::TestCase
|
|
|
141
140
|
vote.created_at = 3.days.from_now
|
|
142
141
|
vote.save
|
|
143
142
|
|
|
144
|
-
assert_equal 1, Item.tally(
|
|
145
|
-
assert_equal 2, Item.tally(
|
|
143
|
+
assert_equal 1, Item.tally.where('created_at > ?', 3.days.ago).where('created_at < ?', 2.days.from_now).length
|
|
144
|
+
assert_equal 2, Item.tally.where('created_at > ?', 3.days.ago).where('created_at < ?', 4.days.from_now).length
|
|
146
145
|
end
|
|
147
146
|
|
|
148
|
-
def
|
|
147
|
+
def test_plusminus_tally_not_empty_without_conditions
|
|
149
148
|
item = Item.create(:name => 'XBOX', :description => 'XBOX console')
|
|
149
|
+
assert_equal 1, Item.plusminus_tally.length
|
|
150
|
+
end
|
|
150
151
|
|
|
151
|
-
|
|
152
|
+
def test_plusminus_tally_empty
|
|
153
|
+
item = Item.create(:name => 'XBOX', :description => 'XBOX console')
|
|
154
|
+
assert_equal 0, Item.plusminus_tally.having('vote_count > 0').length
|
|
152
155
|
end
|
|
153
156
|
|
|
154
157
|
def test_plusminus_tally_starts_at
|
|
@@ -159,8 +162,8 @@ class TestThumbsUp < Test::Unit::TestCase
|
|
|
159
162
|
vote.created_at = 3.days.ago
|
|
160
163
|
vote.save
|
|
161
164
|
|
|
162
|
-
assert_equal 0, Item.plusminus_tally(
|
|
163
|
-
assert_equal 1, Item.plusminus_tally(
|
|
165
|
+
assert_equal 0, Item.plusminus_tally.where('created_at > ?', 2.days.ago).length
|
|
166
|
+
assert_equal 1, Item.plusminus_tally.where('created_at > ?', 4.days.ago).length
|
|
164
167
|
end
|
|
165
168
|
|
|
166
169
|
def test_plusminus_tally_end_at
|
|
@@ -171,8 +174,8 @@ class TestThumbsUp < Test::Unit::TestCase
|
|
|
171
174
|
vote.created_at = 3.days.from_now
|
|
172
175
|
vote.save
|
|
173
176
|
|
|
174
|
-
assert_equal 0, Item.plusminus_tally(
|
|
175
|
-
assert_equal 1, Item.plusminus_tally(
|
|
177
|
+
assert_equal 0, Item.plusminus_tally.where('created_at < ?', 2.days.from_now).length
|
|
178
|
+
assert_equal 1, Item.plusminus_tally.where('created_at < ?', 4.days.from_now).length
|
|
176
179
|
end
|
|
177
180
|
|
|
178
181
|
def test_plusminus_tally_between_start_at_end_at
|
|
@@ -188,8 +191,8 @@ class TestThumbsUp < Test::Unit::TestCase
|
|
|
188
191
|
vote.created_at = 3.days.from_now
|
|
189
192
|
vote.save
|
|
190
193
|
|
|
191
|
-
assert_equal 1, Item.plusminus_tally(
|
|
192
|
-
assert_equal 2, Item.plusminus_tally(
|
|
194
|
+
assert_equal 1, Item.plusminus_tally.where('created_at > ?', 3.days.ago).where('created_at < ?', 2.days.from_now).length
|
|
195
|
+
assert_equal 2, Item.plusminus_tally.where('created_at > ?', 3.days.ago).where('created_at < ?', 4.days.from_now).length
|
|
193
196
|
end
|
|
194
197
|
|
|
195
198
|
def test_plusminus_tally_inclusion
|
|
@@ -199,20 +202,47 @@ class TestThumbsUp < Test::Unit::TestCase
|
|
|
199
202
|
|
|
200
203
|
assert_not_nil user.vote_for(item)
|
|
201
204
|
|
|
202
|
-
assert (Item.plusminus_tally.include? item)
|
|
203
|
-
assert (not Item.plusminus_tally.include? item_not_included)
|
|
205
|
+
assert (Item.plusminus_tally.having('vote_count > 0').include? item)
|
|
206
|
+
assert (not Item.plusminus_tally.having('vote_count > 0').include? item_not_included)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def test_plusminus_tally_voting_for
|
|
210
|
+
user1 = User.create(:name => 'david')
|
|
211
|
+
item = Item.create(:name => 'Playstation', :description => 'Playstation console')
|
|
212
|
+
|
|
213
|
+
assert_not_nil user1.vote_for(item)
|
|
214
|
+
|
|
215
|
+
assert_equal 1, Item.plusminus_tally[0].vote_count
|
|
216
|
+
assert_equal 1, Item.plusminus_tally[0].plusminus
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def test_plusminus_tally_voting_against
|
|
220
|
+
user1 = User.create(:name => 'david')
|
|
221
|
+
user2 = User.create(:name => 'john')
|
|
222
|
+
item = Item.create(:name => 'Playstation', :description => 'Playstation console')
|
|
223
|
+
|
|
224
|
+
assert_not_nil user1.vote_against(item)
|
|
225
|
+
assert_not_nil user2.vote_against(item)
|
|
226
|
+
|
|
227
|
+
assert_equal 2, Item.plusminus_tally[0].vote_count
|
|
228
|
+
assert_equal -2, Item.plusminus_tally[0].plusminus
|
|
204
229
|
end
|
|
205
230
|
|
|
206
231
|
def test_plusminus_tally_default_ordering
|
|
207
|
-
|
|
232
|
+
user1 = User.create(:name => 'david')
|
|
233
|
+
user2 = User.create(:name => 'john')
|
|
234
|
+
item_twice_for = Item.create(:name => 'XBOX2', :description => 'XBOX2 console')
|
|
208
235
|
item_for = Item.create(:name => 'XBOX', :description => 'XBOX console')
|
|
209
236
|
item_against = Item.create(:name => 'Playstation', :description => 'Playstation console')
|
|
210
237
|
|
|
211
|
-
assert_not_nil
|
|
212
|
-
assert_not_nil
|
|
238
|
+
assert_not_nil user1.vote_for(item_for)
|
|
239
|
+
assert_not_nil user1.vote_for(item_twice_for)
|
|
240
|
+
assert_not_nil user2.vote_for(item_twice_for)
|
|
241
|
+
assert_not_nil user1.vote_against(item_against)
|
|
213
242
|
|
|
214
|
-
assert_equal
|
|
215
|
-
assert_equal
|
|
243
|
+
assert_equal item_twice_for, Item.plusminus_tally[0]
|
|
244
|
+
assert_equal item_for, Item.plusminus_tally[1]
|
|
245
|
+
assert_equal item_against, Item.plusminus_tally[2]
|
|
216
246
|
end
|
|
217
247
|
|
|
218
248
|
def test_plusminus_tally_limit
|
|
@@ -220,7 +250,7 @@ class TestThumbsUp < Test::Unit::TestCase
|
|
|
220
250
|
items = (0..9).map{ |u| Item.create(:name => "Item #{u}", :description => "Item #{u}") }
|
|
221
251
|
users.each{ |u| items.each { |i| u.vote_for(i) } }
|
|
222
252
|
assert_equal 10, Item.plusminus_tally.length
|
|
223
|
-
assert_equal 2, Item.plusminus_tally(
|
|
253
|
+
assert_equal 2, Item.plusminus_tally.limit(2).length
|
|
224
254
|
end
|
|
225
255
|
|
|
226
256
|
def test_plusminus_tally_ascending_ordering
|
|
@@ -231,8 +261,8 @@ class TestThumbsUp < Test::Unit::TestCase
|
|
|
231
261
|
assert_not_nil user.vote_for(item_for)
|
|
232
262
|
assert_not_nil user.vote_against(item_against)
|
|
233
263
|
|
|
234
|
-
assert_equal item_for, Item.plusminus_tally(
|
|
235
|
-
assert_equal item_against, Item.plusminus_tally(
|
|
264
|
+
assert_equal item_for, Item.plusminus_tally.reorder('plusminus ASC')[1]
|
|
265
|
+
assert_equal item_against, Item.plusminus_tally.reorder('plusminus ASC')[0]
|
|
236
266
|
end
|
|
237
267
|
|
|
238
268
|
def test_karma
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: thumbs_up
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -14,11 +14,11 @@ authors:
|
|
|
14
14
|
autorequire:
|
|
15
15
|
bindir: bin
|
|
16
16
|
cert_chain: []
|
|
17
|
-
date:
|
|
17
|
+
date: 2012-02-17 00:00:00.000000000 Z
|
|
18
18
|
dependencies:
|
|
19
19
|
- !ruby/object:Gem::Dependency
|
|
20
20
|
name: activerecord
|
|
21
|
-
requirement: &
|
|
21
|
+
requirement: &70283885105360 !ruby/object:Gem::Requirement
|
|
22
22
|
none: false
|
|
23
23
|
requirements:
|
|
24
24
|
- - ! '>='
|
|
@@ -26,10 +26,21 @@ dependencies:
|
|
|
26
26
|
version: '0'
|
|
27
27
|
type: :runtime
|
|
28
28
|
prerelease: false
|
|
29
|
-
version_requirements: *
|
|
29
|
+
version_requirements: *70283885105360
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: simplecov
|
|
32
|
+
requirement: &70283885104200 !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ! '>='
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '0'
|
|
38
|
+
type: :development
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: *70283885104200
|
|
30
41
|
- !ruby/object:Gem::Dependency
|
|
31
42
|
name: bundler
|
|
32
|
-
requirement: &
|
|
43
|
+
requirement: &70283885103200 !ruby/object:Gem::Requirement
|
|
33
44
|
none: false
|
|
34
45
|
requirements:
|
|
35
46
|
- - ! '>='
|
|
@@ -37,10 +48,10 @@ dependencies:
|
|
|
37
48
|
version: '0'
|
|
38
49
|
type: :development
|
|
39
50
|
prerelease: false
|
|
40
|
-
version_requirements: *
|
|
51
|
+
version_requirements: *70283885103200
|
|
41
52
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
43
|
-
requirement: &
|
|
53
|
+
name: mysql2
|
|
54
|
+
requirement: &70283885118060 !ruby/object:Gem::Requirement
|
|
44
55
|
none: false
|
|
45
56
|
requirements:
|
|
46
57
|
- - ! '>='
|
|
@@ -48,10 +59,10 @@ dependencies:
|
|
|
48
59
|
version: '0'
|
|
49
60
|
type: :development
|
|
50
61
|
prerelease: false
|
|
51
|
-
version_requirements: *
|
|
62
|
+
version_requirements: *70283885118060
|
|
52
63
|
- !ruby/object:Gem::Dependency
|
|
53
|
-
name:
|
|
54
|
-
requirement: &
|
|
64
|
+
name: rake
|
|
65
|
+
requirement: &70283885115780 !ruby/object:Gem::Requirement
|
|
55
66
|
none: false
|
|
56
67
|
requirements:
|
|
57
68
|
- - ! '>='
|
|
@@ -59,32 +70,31 @@ dependencies:
|
|
|
59
70
|
version: '0'
|
|
60
71
|
type: :development
|
|
61
72
|
prerelease: false
|
|
62
|
-
version_requirements: *
|
|
73
|
+
version_requirements: *70283885115780
|
|
63
74
|
description: ThumbsUp provides dead-simple voting capabilities to ActiveRecord models
|
|
64
75
|
with karma calculation, a la stackoverflow.com.
|
|
65
|
-
email:
|
|
76
|
+
email:
|
|
77
|
+
- brady@thewellinspired.com
|
|
66
78
|
executables: []
|
|
67
79
|
extensions: []
|
|
68
|
-
extra_rdoc_files:
|
|
69
|
-
- README.markdown
|
|
80
|
+
extra_rdoc_files: []
|
|
70
81
|
files:
|
|
71
|
-
- CHANGELOG.markdown
|
|
72
|
-
- Gemfile
|
|
73
|
-
- MIT-LICENSE
|
|
74
|
-
- README.markdown
|
|
75
|
-
- Rakefile
|
|
76
|
-
- VERSION
|
|
77
82
|
- lib/acts_as_voteable.rb
|
|
78
83
|
- lib/acts_as_voter.rb
|
|
79
84
|
- lib/generators/thumbs_up/templates/migration.rb
|
|
80
85
|
- lib/generators/thumbs_up/templates/vote.rb
|
|
81
86
|
- lib/generators/thumbs_up/thumbs_up_generator.rb
|
|
82
87
|
- lib/has_karma.rb
|
|
88
|
+
- lib/thumbs_up/version.rb
|
|
83
89
|
- lib/thumbs_up.rb
|
|
84
90
|
- rails/init.rb
|
|
85
91
|
- test/test_helper.rb
|
|
86
|
-
- test/
|
|
87
|
-
-
|
|
92
|
+
- test/thumbs_up_test.rb
|
|
93
|
+
- CHANGELOG.md
|
|
94
|
+
- Gemfile
|
|
95
|
+
- MIT-LICENSE
|
|
96
|
+
- README.md
|
|
97
|
+
- Rakefile
|
|
88
98
|
homepage: http://github.com/brady8/thumbs_up
|
|
89
99
|
licenses: []
|
|
90
100
|
post_install_message:
|
|
@@ -97,15 +107,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
97
107
|
- - ! '>='
|
|
98
108
|
- !ruby/object:Gem::Version
|
|
99
109
|
version: '0'
|
|
110
|
+
segments:
|
|
111
|
+
- 0
|
|
112
|
+
hash: 2487690309587182641
|
|
100
113
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
114
|
none: false
|
|
102
115
|
requirements:
|
|
103
116
|
- - ! '>='
|
|
104
117
|
- !ruby/object:Gem::Version
|
|
105
|
-
version:
|
|
118
|
+
version: 1.8.10
|
|
106
119
|
requirements: []
|
|
107
120
|
rubyforge_project:
|
|
108
|
-
rubygems_version: 1.8.
|
|
121
|
+
rubygems_version: 1.8.16
|
|
109
122
|
signing_key:
|
|
110
123
|
specification_version: 3
|
|
111
124
|
summary: Voting for ActiveRecord with multiple vote sources and karma calculation.
|
data/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
0.4.6
|
data/thumbs_up.gemspec
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
# Generated by jeweler
|
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
|
4
|
-
# -*- encoding: utf-8 -*-
|
|
5
|
-
|
|
6
|
-
Gem::Specification.new do |s|
|
|
7
|
-
s.name = "thumbs_up"
|
|
8
|
-
s.version = File.read('./VERSION').strip
|
|
9
|
-
|
|
10
|
-
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
11
|
-
s.authors = ["Brady Bouchard", "Peter Jackson", "Cosmin Radoi", "Bence Nagy", "Rob Maddox", "Wojciech Wnetrzak"]
|
|
12
|
-
s.date = "2011-09-15"
|
|
13
|
-
s.description = "ThumbsUp provides dead-simple voting capabilities to ActiveRecord models with karma calculation, a la stackoverflow.com."
|
|
14
|
-
s.email = "brady@ldawn.com"
|
|
15
|
-
s.extra_rdoc_files = [
|
|
16
|
-
"README.markdown"
|
|
17
|
-
]
|
|
18
|
-
s.files = [
|
|
19
|
-
"CHANGELOG.markdown",
|
|
20
|
-
"Gemfile",
|
|
21
|
-
"MIT-LICENSE",
|
|
22
|
-
"README.markdown",
|
|
23
|
-
"Rakefile",
|
|
24
|
-
"VERSION",
|
|
25
|
-
"lib/acts_as_voteable.rb",
|
|
26
|
-
"lib/acts_as_voter.rb",
|
|
27
|
-
"lib/generators/thumbs_up/templates/migration.rb",
|
|
28
|
-
"lib/generators/thumbs_up/templates/vote.rb",
|
|
29
|
-
"lib/generators/thumbs_up/thumbs_up_generator.rb",
|
|
30
|
-
"lib/has_karma.rb",
|
|
31
|
-
"lib/thumbs_up.rb",
|
|
32
|
-
"rails/init.rb",
|
|
33
|
-
"test/test_helper.rb",
|
|
34
|
-
"test/test_thumbs_up.rb",
|
|
35
|
-
"thumbs_up.gemspec"
|
|
36
|
-
]
|
|
37
|
-
s.homepage = "http://github.com/brady8/thumbs_up"
|
|
38
|
-
s.require_paths = ["lib"]
|
|
39
|
-
s.rubygems_version = "1.8.10"
|
|
40
|
-
s.summary = "Voting for ActiveRecord with multiple vote sources and karma calculation."
|
|
41
|
-
|
|
42
|
-
if s.respond_to? :specification_version then
|
|
43
|
-
s.specification_version = 3
|
|
44
|
-
|
|
45
|
-
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
|
46
|
-
s.add_runtime_dependency(%q<activerecord>, [">= 0"])
|
|
47
|
-
s.add_development_dependency(%q<bundler>, [">= 0"])
|
|
48
|
-
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
|
49
|
-
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
|
50
|
-
else
|
|
51
|
-
s.add_dependency(%q<activerecord>, [">= 0"])
|
|
52
|
-
s.add_dependency(%q<bundler>, [">= 0"])
|
|
53
|
-
s.add_dependency(%q<jeweler>, [">= 0"])
|
|
54
|
-
s.add_dependency(%q<simplecov>, [">= 0"])
|
|
55
|
-
end
|
|
56
|
-
else
|
|
57
|
-
s.add_dependency(%q<activerecord>, [">= 0"])
|
|
58
|
-
s.add_dependency(%q<bundler>, [">= 0"])
|
|
59
|
-
s.add_dependency(%q<jeweler>, [">= 0"])
|
|
60
|
-
s.add_dependency(%q<simplecov>, [">= 0"])
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|