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.
File without changes
data/Gemfile CHANGED
@@ -1,13 +1 @@
1
- source :rubygems
2
-
3
- gem 'activerecord'
4
-
5
- group :development do
6
- gem 'bundler'
7
- gem 'jeweler'
8
- gem 'simplecov'
9
- end
10
-
11
- group :test do
12
- gem 'sqlite3'
13
- end
1
+ gemspec
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Brady Bouchard (ldawn.com)
1
+ Copyright (c) 2011 Brady Bouchard (thewellinspired.com)
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -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
- u.voted_on?(Car.find(2))
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
- { :at_least => 1,
83
- :at_most => 10000,
84
- :start_at => 2.weeks.ago,
85
- :end_at => 1.day.ago,
86
- :limit => 10,
87
- :order => "items.name DESC"
88
- })
89
-
90
- This will select the Items with between 1 and 10,000 votes, the votes having been cast within the last two weeks (not including today), then display the 10 last items in an alphabetical list. This tallies all votes, regardless of whether they are +1 (up) or -1 (down).
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
- require 'rdoc/task'
34
- Rake::RDocTask.new do |rdoc|
35
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
36
- rdoc.rdoc_dir = 'rdoc'
37
- rdoc.title = "leaderboard #{version}"
38
- rdoc.rdoc_files.include('README*')
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
@@ -16,108 +16,35 @@ module ThumbsUp
16
16
 
17
17
  module SingletonMethods
18
18
 
19
- # The point of this function is to return rankings based on the difference between up and down votes
20
- # assuming equal weighting (i.e. a user with 1 up vote and 1 down vote has a Vote_Total of 0.
21
- # First the votes table is joined twiced so that the Vote_Total can be calculated for every ID
22
- # Then this table is joined against the specific table passed to this function to allow for
23
- # ranking of the items within that table based on the difference between up and down votes.
24
- # Options:
25
- # :start_at - Restrict the votes to those created after a certain time
26
- # :end_at - Restrict the votes to those created before a certain time
27
- # :ascending - Default false - normal order DESC (i.e. highest rank to lowest)
28
- # :at_least - Default 1 - Item must have at least X votes
29
- # :at_most - Item may not have more than X votes
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 with at least one vote.
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
- # Options:
84
- # :start_at - Restrict the votes to those created after a certain time
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
- options = args.extract_options!
93
-
94
- # Use the explicit SQL statement throughout for Postgresql compatibility.
95
- vote_count = "COUNT(#{Vote.table_name}.voteable_id)"
96
-
97
- t = self.where("#{Vote.table_name}.voteable_type = '#{self.name}'")
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
- Vote.where(:voteable_id => id, :voteable_type => self.class.name, :vote => true).count
59
+ self.votes.where(:vote => true).count
133
60
  end
134
61
 
135
62
  def votes_against
136
- Vote.where(:voteable_id => id, :voteable_type => self.class.name, :vote => false).count
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.clear_votes(voteable)
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 clear_votes(voteable)
86
+ def unvote_for(voteable)
87
87
  Vote.where(
88
88
  :voter_id => self.id,
89
89
  :voter_type => self.class.name,
@@ -0,0 +1,3 @@
1
+ module ThumbsUp
2
+ VERSION = '0.5.0'
3
+ end
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
- ActiveRecord::Base.establish_connection(
11
- :adapter => "sqlite3",
12
- :database => ":memory:"
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.clear_votes(item)
53
+ user_for.unvote_for(item)
54
54
  assert_equal 0, user_for.vote_count
55
55
 
56
- user_against.clear_votes(item)
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(:start_at => 2.days.ago).length
116
- assert_equal 1, Item.tally(:start_at => 4.days.ago).length
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(:end_at => 2.days.from_now).length
128
- assert_equal 1, Item.tally(:end_at => 4.days.from_now).length
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(:start_at => 3.days.ago, :end_at => 2.days.from_now).length
145
- assert_equal 2, Item.tally(:start_at => 3.days.ago, :end_at => 4.days.from_now).length
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 test_plusminus_tally_empty
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
- assert_equal 0, Item.plusminus_tally.length
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(:start_at => 2.days.ago).length
163
- assert_equal 1, Item.plusminus_tally(:start_at => 4.days.ago).length
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(:end_at => 2.days.from_now).length
175
- assert_equal 1, Item.plusminus_tally(:end_at => 4.days.from_now).length
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(:start_at => 3.days.ago, :end_at => 2.days.from_now).length
192
- assert_equal 2, Item.plusminus_tally(:start_at => 3.days.ago, :end_at => 4.days.from_now).length
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
- user = User.create(:name => 'david')
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 user.vote_for(item_for)
212
- assert_not_nil user.vote_against(item_against)
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 item_for, Item.plusminus_tally[0]
215
- assert_equal item_against, Item.plusminus_tally[1]
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(:limit => 2).length
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(:ascending => true)[1]
235
- assert_equal item_against, Item.plusminus_tally(:ascending => true)[0]
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.6
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: 2011-09-15 00:00:00.000000000 Z
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: &70119174895060 !ruby/object:Gem::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: *70119174895060
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: &70119174894280 !ruby/object:Gem::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: *70119174894280
51
+ version_requirements: *70283885103200
41
52
  - !ruby/object:Gem::Dependency
42
- name: jeweler
43
- requirement: &70119174893320 !ruby/object:Gem::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: *70119174893320
62
+ version_requirements: *70283885118060
52
63
  - !ruby/object:Gem::Dependency
53
- name: simplecov
54
- requirement: &70119174892540 !ruby/object:Gem::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: *70119174892540
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: brady@ldawn.com
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/test_thumbs_up.rb
87
- - thumbs_up.gemspec
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: '0'
118
+ version: 1.8.10
106
119
  requirements: []
107
120
  rubyforge_project:
108
- rubygems_version: 1.8.13
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
-