thumbs_up 0.4.6 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
|