thumbs_up 0.4.1 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,13 @@
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
data/README.markdown CHANGED
@@ -87,7 +87,7 @@ You can easily retrieve voteable object collections based on the properties of t
87
87
  :order => "items.name DESC"
88
88
  })
89
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.
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
91
 
92
92
  ##### Tally Options:
93
93
  :start_at - Restrict the votes to those created after a certain time
@@ -98,13 +98,12 @@ This will select the Items with between 1 and 10,000 votes, the votes having bee
98
98
  :at_least - Item must have at least X votes
99
99
  :at_most - Item may not have more than X votes
100
100
 
101
- ##### Tallying Rank
101
+ ##### Tallying Rank ("Plusminus")
102
102
 
103
- Similar to tallying votes, but this will actually return voteable object collections based on a rating
104
- system where up votes and down votes get equal rating. For Instance, a voteable with 3 upvotes and 2
105
- downvotes will have a rating in this instance of 1.
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.
106
105
 
107
- ##### Rank_Tally Options:
106
+ ##### Plusminus Tally Options:
108
107
  :start_at - Restrict the votes to those created after a certain time
109
108
  :end_at - Restrict the votes to those created before a certain time
110
109
  :conditions - A piece of SQL conditions to add to the query
@@ -117,7 +116,7 @@ downvotes will have a rating in this instance of 1.
117
116
 
118
117
  positiveVoteCount = voteable.votes_for
119
118
  negativeVoteCount = voteable.votes_against
120
- plusminus = voteable.plusminus # Votes for minus votes against.
119
+ plusminus = voteable.plusminus # Votes for, minus votes against.
121
120
 
122
121
  voter.voted_for?(voteable) # True if the voter voted for this object.
123
122
  voter.vote_count(:up | :down | :all) # returns the count of +1, -1, or all votes
@@ -134,7 +133,7 @@ ThumbsUp by default only allows one vote per user. This can be changed by removi
134
133
 
135
134
  validates_uniqueness_of :voteable_id, :scope => [:voteable_type, :voter_type, :voter_id]
136
135
 
137
- #### In the migration:
136
+ #### In the migration, the unique index:
138
137
 
139
138
  add_index :votes, ["voter_id", "voter_type", "voteable_id", "voteable_type"], :unique => true, :name => "uniq_one_vote_only"
140
139
 
data/Rakefile CHANGED
@@ -26,21 +26,13 @@ Jeweler::RubygemsDotOrgTasks.new
26
26
  require 'rake/testtask'
27
27
  Rake::TestTask.new(:test) do |test|
28
28
  test.libs << 'lib' << 'test'
29
- test.pattern = 'test/**/test_*.rb'
29
+ test.test_files = Dir.glob("test/**/*_test.rb")
30
30
  test.verbose = true
31
31
  end
32
32
 
33
- require 'rcov/rcovtask'
34
- Rcov::RcovTask.new do |test|
35
- test.libs << 'test'
36
- test.pattern = 'test/**/test_*.rb'
37
- test.verbose = true
38
- end
39
-
40
- require 'rake/rdoctask'
33
+ require 'rdoc/task'
41
34
  Rake::RDocTask.new do |rdoc|
42
35
  version = File.exist?('VERSION') ? File.read('VERSION') : ""
43
-
44
36
  rdoc.rdoc_dir = 'rdoc'
45
37
  rdoc.title = "leaderboard #{version}"
46
38
  rdoc.rdoc_files.include('README*')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.1
1
+ 0.4.3
@@ -17,57 +17,61 @@ module ThumbsUp
17
17
  module SingletonMethods
18
18
 
19
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.
20
+ # assuming equal weighting (i.e. a user with 1 up vote and 1 down vote has a Vote_Total of 0.
21
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
22
+ # Then this table is joined against the specific table passed to this function to allow for
23
23
  # ranking of the items within that table based on the difference between up and down votes.
24
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
- # :conditions - A piece of SQL conditions to add to the query
28
- # :limit - The maximum number of voteables to return
29
- # :ascending - Default false - normal order DESC (i.e. highest rank to lowest)
30
- # :at_least - Item must have at least X votes
31
- # :at_most - Item may not have more than X votes
32
- def rank_tally(*args)
33
- options = args.extract_options!
34
-
35
- tsub0 = Vote
36
- tsub0 = tsub0.where("vote = ?", false)
37
- tsub0 = tsub0.where("voteable_type = ?", self.name)
38
- tsub0 = tsub0.group("voteable_id")
39
- tsub0 = tsub0.select("DISTINCT voteable_id, COUNT(vote) as Votes_Against")
40
-
41
- tsub1 = Vote
42
- tsub1 = tsub1.where("vote = ?", true)
43
- tsub1 = tsub1.where("voteable_type = ?", self.name)
44
- tsub1 = tsub1.group("voteable_id")
45
- tsub1 = tsub1.select("DISTINCT voteable_id, COUNT(vote) as Votes_For")
46
-
47
- t = self.joins("LEFT OUTER JOIN (SELECT DISTINCT #{Vote.table_name}.*,
48
- (COALESCE(vfor.Votes_For, 0)-COALESCE(against.Votes_Against, 0)) AS Vote_Total
49
- FROM (#{Vote.table_name} LEFT JOIN
50
- (#{tsub0.to_sql}) AS against ON #{Vote.table_name}.voteable_id = against.voteable_id)
51
- LEFT JOIN
52
- (#{tsub1.to_sql}) as vfor ON #{Vote.table_name}.voteable_id = vfor.voteable_id)
53
- AS joined_#{Vote.table_name} ON #{self.table_name}.#{self.primary_key} =
54
- joined_#{Vote.table_name}.voteable_id")
55
-
56
- t = t.where("joined_#{Vote.table_name}.voteable_type = '#{self.name}'")
57
- t = t.group("joined_#{Vote.table_name}.voteable_id, joined_#{Vote.table_name}.Vote_Total, #{column_names_for_tally}")
58
- t = t.limit(options[:limit]) if options[:limit]
59
- t = t.where("joined_#{Vote.table_name}.created_at >= ?", options[:start_at]) if options[:start_at]
60
- t = t.where("joined_#{Vote.table_name}.created_at <= ?", options[:end_at]) if options[:end_at]
61
- t = t.where(options[:conditions]) if options[:conditions]
62
- t = options[:ascending] ? t.order("joined_#{Vote.table_name}.Vote_Total") : t.order("joined_#{Vote.table_name}.Vote_Total DESC")
63
-
64
- t = t.having(["COUNT(joined_#{Vote.table_name}.voteable_id) > 0",
65
- (options[:at_least] ? "joined_votes.Vote_Total >= #{sanitize(options[:at_least])}" : nil),
66
- (options[:at_most] ? "joined_votes.Vote_Total <= #{sanitize(options[:at_most])}" : nil)
67
- ].compact.join(' AND '))
68
-
69
- t.select("#{self.table_name}.*, joined_#{Vote.table_name}.Vote_Total")
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
+ def plusminus_tally(*args)
31
+ options = args.extract_options!
32
+
33
+ tsub0 = Vote
34
+ tsub0 = tsub0.where("vote = ?", false)
35
+ tsub0 = tsub0.where("voteable_type = ?", self.name)
36
+ tsub0 = tsub0.group("voteable_id")
37
+ tsub0 = tsub0.select("DISTINCT voteable_id, COUNT(vote) as votes_against")
38
+
39
+ tsub1 = Vote
40
+ tsub1 = tsub1.where("vote = ?", true)
41
+ tsub1 = tsub1.where("voteable_type = ?", self.name)
42
+ tsub1 = tsub1.group("voteable_id")
43
+ tsub1 = tsub1.select("DISTINCT voteable_id, COUNT(vote) as votes_for")
44
+
45
+ t = self.joins("LEFT OUTER JOIN (SELECT DISTINCT #{Vote.table_name}.*,
46
+ (COALESCE(vfor.votes_for, 0)-COALESCE(against.votes_against, 0)) AS vote_total
47
+ FROM (#{Vote.table_name} LEFT JOIN
48
+ (#{tsub0.to_sql}) AS against ON #{Vote.table_name}.voteable_id = against.voteable_id)
49
+ LEFT JOIN
50
+ (#{tsub1.to_sql}) as vfor ON #{Vote.table_name}.voteable_id = vfor.voteable_id)
51
+ AS joined_#{Vote.table_name} ON #{self.table_name}.#{self.primary_key} =
52
+ joined_#{Vote.table_name}.voteable_id")
53
+
54
+ t = t.where("joined_#{Vote.table_name}.voteable_type = '#{self.name}'")
55
+ t = t.group("joined_#{Vote.table_name}.voteable_id, joined_#{Vote.table_name}.vote_total, #{column_names_for_tally}")
56
+ t = t.where("joined_#{Vote.table_name}.created_at >= ?", options[:start_at]) if options[:start_at]
57
+ t = t.where("joined_#{Vote.table_name}.created_at <= ?", options[:end_at]) if options[:end_at]
58
+ t = options[:ascending] ? t.order("joined_#{Vote.table_name}.vote_total") : t.order("joined_#{Vote.table_name}.vote_total DESC")
59
+
60
+ t = t.having([
61
+ "COUNT(joined_#{Vote.table_name}.voteable_id) > 0",
62
+ (options[:at_least] ?
63
+ "joined_#{Vote.table_name}.vote_total >= #{sanitize(options[:at_least])}" : nil
64
+ ),
65
+ (options[:at_most] ?
66
+ "joined_#{Vote.table_name}.vote_total <= #{sanitize(options[:at_most])}" : nil
67
+ )
68
+ ].compact.join(' AND '))
69
+
70
+ t.select("#{self.table_name}.*, joined_#{Vote.table_name}.vote_total")
70
71
  end
72
+
73
+ # #rank_tally is depreciated.
74
+ alias_method :rank_tally, :plusminus_tally
71
75
 
72
76
  # Calculate the vote counts for all voteables of my type.
73
77
  # This method returns all voteables with at least one vote.
@@ -83,22 +87,22 @@ module ThumbsUp
83
87
  # :at_most - Item may not have more than X votes
84
88
  def tally(*args)
85
89
  options = args.extract_options!
86
-
90
+
87
91
  # Use the explicit SQL statement throughout for Postgresql compatibility.
88
92
  vote_count = "COUNT(#{Vote.table_name}.voteable_id)"
89
-
93
+
90
94
  t = self.where("#{Vote.table_name}.voteable_type = '#{self.name}'")
91
95
 
92
96
  # We join so that you can order by columns on the voteable model.
93
97
  t = t.joins("LEFT OUTER JOIN #{Vote.table_name} ON #{self.table_name}.#{self.primary_key} = #{Vote.table_name}.voteable_id")
94
-
98
+
95
99
  t = t.group("#{Vote.table_name}.voteable_id, #{column_names_for_tally}")
96
100
  t = t.limit(options[:limit]) if options[:limit]
97
101
  t = t.where("#{Vote.table_name}.created_at >= ?", options[:start_at]) if options[:start_at]
98
102
  t = t.where("#{Vote.table_name}.created_at <= ?", options[:end_at]) if options[:end_at]
99
103
  t = t.where(options[:conditions]) if options[:conditions]
100
104
  t = options[:order] ? t.order(options[:order]) : t.order("#{vote_count} DESC")
101
-
105
+
102
106
  # I haven't been able to confirm this bug yet, but Arel (2.0.7) currently blows up
103
107
  # with multiple 'having' clauses. So we hack them all into one for now.
104
108
  # If you have a more elegant solution, a pull request on Github would be greatly appreciated.
@@ -129,6 +133,14 @@ module ThumbsUp
129
133
  Vote.where(:voteable_id => id, :voteable_type => self.class.name, :vote => false).count
130
134
  end
131
135
 
136
+ def percent_for
137
+ (votes_for.to_f * 100 / (self.votes.size + 0.0001)).round
138
+ end
139
+
140
+ def percent_against
141
+ (votes_against.to_f * 100 / (self.votes.size + 0.0001)).round
142
+ end
143
+
132
144
  # You'll probably want to use this method to display how 'good' a particular voteable
133
145
  # is, and/or sort based on it.
134
146
  def plusminus
data/lib/has_karma.rb CHANGED
@@ -22,7 +22,7 @@ module ThumbsUp #:nodoc:
22
22
  ## Not yet implemented. Don't use it!
23
23
  # Find the most popular users
24
24
  def find_most_karmic
25
- find(:all)
25
+ self.all
26
26
  end
27
27
 
28
28
  end
@@ -0,0 +1,69 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+ require 'test/unit'
4
+
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+
8
+ require 'active_record'
9
+
10
+ ActiveRecord::Base.establish_connection(
11
+ :adapter => "sqlite3",
12
+ :database => ":memory:"
13
+ )
14
+
15
+ ActiveRecord::Migration.verbose = false
16
+
17
+ ActiveRecord::Schema.define do
18
+ create_table :votes, :force => true do |t|
19
+ t.boolean :vote, :default => false
20
+ t.references :voteable, :polymorphic => true, :null => false
21
+ t.references :voter, :polymorphic => true
22
+ t.timestamps
23
+ end
24
+
25
+ add_index :votes, [:voter_id, :voter_type]
26
+ add_index :votes, [:voteable_id, :voteable_type]
27
+
28
+ # Comment out the line below to allow multiple votes per voter on a single entity.
29
+ add_index :votes, [:voter_id, :voter_type, :voteable_id, :voteable_type], :unique => true, :name => 'fk_one_vote_per_user_per_entity'
30
+
31
+ create_table :users, :force => true do |t|
32
+ t.string :name
33
+ t.timestamps
34
+ end
35
+
36
+ create_table :items, :force => true do |t|
37
+ t.string :name
38
+ t.string :description
39
+ end
40
+ end
41
+
42
+ require 'thumbs_up'
43
+
44
+ class Vote < ActiveRecord::Base
45
+
46
+ scope :for_voter, lambda { |*args| where(["voter_id = ? AND voter_type = ?", args.first.id, args.first.class.name]) }
47
+ scope :for_voteable, lambda { |*args| where(["voteable_id = ? AND voteable_type = ?", args.first.id, args.first.class.name]) }
48
+ scope :recent, lambda { |*args| where(["created_at > ?", (args.first || 2.weeks.ago)]) }
49
+ scope :descending, order("created_at DESC")
50
+
51
+ belongs_to :voteable, :polymorphic => true
52
+ belongs_to :voter, :polymorphic => true
53
+
54
+ attr_accessible :vote, :voter, :voteable
55
+
56
+ # Comment out the line below to allow multiple votes per user.
57
+ validates_uniqueness_of :voteable_id, :scope => [:voteable_type, :voter_type, :voter_id]
58
+ end
59
+
60
+ class User < ActiveRecord::Base
61
+ acts_as_voter
62
+ end
63
+
64
+ class Item < ActiveRecord::Base
65
+ acts_as_voteable
66
+ end
67
+
68
+ class Test::Unit::TestCase
69
+ end
@@ -0,0 +1,229 @@
1
+ require File.join(File.expand_path(File.dirname(__FILE__)), 'test_helper')
2
+
3
+ class TestThumbsUp < Test::Unit::TestCase
4
+ def setup
5
+ Vote.delete_all
6
+ User.delete_all
7
+ Item.delete_all
8
+ end
9
+
10
+ def test_acts_as_voter_instance_methods
11
+ user_for = User.create(:name => 'david')
12
+ user_against = User.create(:name => 'brady')
13
+ item = Item.create(:name => 'XBOX', :description => 'XBOX console')
14
+
15
+ assert_not_nil user_for.vote_for(item)
16
+ assert_raises(ActiveRecord::RecordInvalid) do
17
+ user_for.vote_for(item)
18
+ end
19
+ assert_equal true, user_for.voted_for?(item)
20
+ assert_equal false, user_for.voted_against?(item)
21
+ assert_equal true, user_for.voted_on?(item)
22
+ assert_equal 1, user_for.vote_count
23
+ assert_equal 1, user_for.vote_count(:up)
24
+ assert_equal 0, user_for.vote_count(:down)
25
+ assert_equal true, user_for.voted_which_way?(item, :up)
26
+ assert_equal false, user_for.voted_which_way?(item, :down)
27
+ assert_raises(ArgumentError) do
28
+ user_for.voted_which_way?(item, :foo)
29
+ end
30
+
31
+ assert_not_nil user_against.vote_against(item)
32
+ assert_raises(ActiveRecord::RecordInvalid) do
33
+ user_against.vote_against(item)
34
+ end
35
+ assert_equal false, user_against.voted_for?(item)
36
+ assert_equal true, user_against.voted_against?(item)
37
+ assert_equal true, user_against.voted_on?(item)
38
+ assert_equal 1, user_against.vote_count
39
+ assert_equal 0, user_against.vote_count(:up)
40
+ assert_equal 1, user_against.vote_count(:down)
41
+ assert_equal false, user_against.voted_which_way?(item, :up)
42
+ assert_equal true, user_against.voted_which_way?(item, :down)
43
+ assert_raises(ArgumentError) do
44
+ user_against.voted_which_way?(item, :foo)
45
+ end
46
+
47
+ assert_not_nil user_against.vote_exclusively_for(item)
48
+ assert_equal true, user_against.voted_for?(item)
49
+
50
+ assert_not_nil user_for.vote_exclusively_against(item)
51
+ assert_equal true, user_for.voted_against?(item)
52
+
53
+ user_for.clear_votes(item)
54
+ assert_equal 0, user_for.vote_count
55
+
56
+ user_against.clear_votes(item)
57
+ assert_equal 0, user_against.vote_count
58
+
59
+ assert_raises(ArgumentError) do
60
+ user_for.vote(item, {:direction => :foo})
61
+ end
62
+ end
63
+
64
+ def test_acts_as_voteable_instance_methods
65
+ user_for = User.create(:name => 'david')
66
+ another_user_for = User.create(:name => 'name')
67
+ user_against = User.create(:name => 'brady')
68
+ item = Item.create(:name => 'XBOX', :description => 'XBOX console')
69
+
70
+ user_for.vote_for(item)
71
+ another_user_for.vote_for(item)
72
+
73
+ assert_equal 2, item.votes_for
74
+ assert_equal 0, item.votes_against
75
+ assert_equal 2, item.plusminus
76
+
77
+ user_against.vote_against(item)
78
+
79
+ assert_equal 1, item.votes_against
80
+ assert_equal 1, item.plusminus
81
+
82
+ assert_equal 3, item.votes_count
83
+
84
+ assert_equal 67, item.percent_for
85
+ assert_equal 33, item.percent_against
86
+
87
+ voters_who_voted = item.voters_who_voted
88
+ assert_equal 3, voters_who_voted.size
89
+ assert voters_who_voted.include?(user_for)
90
+ assert voters_who_voted.include?(another_user_for)
91
+ assert voters_who_voted.include?(user_against)
92
+
93
+ non_voting_user = User.create(:name => 'random')
94
+
95
+ assert_equal true, item.voted_by?(user_for)
96
+ assert_equal true, item.voted_by?(another_user_for)
97
+ assert_equal true, item.voted_by?(user_against)
98
+ assert_equal false, item.voted_by?(non_voting_user)
99
+ end
100
+
101
+ def test_tally_empty
102
+ item = Item.create(:name => 'XBOX', :description => 'XBOX console')
103
+
104
+ assert_equal 0, Item.tally.length
105
+ end
106
+
107
+ def test_tally_starts_at
108
+ item = Item.create(:name => 'XBOX', :description => 'XBOX console')
109
+ user = User.create(:name => 'david')
110
+
111
+ vote = user.vote_for(item)
112
+ vote.created_at = 3.days.ago
113
+ vote.save
114
+
115
+ assert_equal 0, Item.tally(:start_at => 2.days.ago).length
116
+ assert_equal 1, Item.tally(:start_at => 4.days.ago).length
117
+ end
118
+
119
+ def test_tally_end_at
120
+ item = Item.create(:name => 'XBOX', :description => 'XBOX console')
121
+ user = User.create(:name => 'david')
122
+
123
+ vote = user.vote_for(item)
124
+ vote.created_at = 3.days.from_now
125
+ vote.save
126
+
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
129
+ end
130
+
131
+ def test_tally_between_start_at_end_at
132
+ item = Item.create(:name => 'XBOX', :description => 'XBOX console')
133
+ another_item = Item.create(:name => 'XBOX', :description => 'XBOX console')
134
+ user = User.create(:name => 'david')
135
+
136
+ vote = user.vote_for(item)
137
+ vote.created_at = 2.days.ago
138
+ vote.save
139
+
140
+ vote = user.vote_for(another_item)
141
+ vote.created_at = 3.days.from_now
142
+ vote.save
143
+
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
146
+ end
147
+
148
+ def test_rank_tally_empty
149
+ item = Item.create(:name => 'XBOX', :description => 'XBOX console')
150
+
151
+ assert_equal 0, Item.rank_tally.length
152
+ end
153
+
154
+ def test_rank_tally_starts_at
155
+ item = Item.create(:name => 'XBOX', :description => 'XBOX console')
156
+ user = User.create(:name => 'david')
157
+
158
+ vote = user.vote_for(item)
159
+ vote.created_at = 3.days.ago
160
+ vote.save
161
+
162
+ assert_equal 0, Item.rank_tally(:start_at => 2.days.ago).length
163
+ assert_equal 1, Item.rank_tally(:start_at => 4.days.ago).length
164
+ end
165
+
166
+ def test_rank_tally_end_at
167
+ item = Item.create(:name => 'XBOX', :description => 'XBOX console')
168
+ user = User.create(:name => 'david')
169
+
170
+ vote = user.vote_for(item)
171
+ vote.created_at = 3.days.from_now
172
+ vote.save
173
+
174
+ assert_equal 0, Item.rank_tally(:end_at => 2.days.from_now).length
175
+ assert_equal 1, Item.rank_tally(:end_at => 4.days.from_now).length
176
+ end
177
+
178
+ def test_rank_tally_between_start_at_end_at
179
+ item = Item.create(:name => 'XBOX', :description => 'XBOX console')
180
+ another_item = Item.create(:name => 'XBOX', :description => 'XBOX console')
181
+ user = User.create(:name => 'david')
182
+
183
+ vote = user.vote_for(item)
184
+ vote.created_at = 2.days.ago
185
+ vote.save
186
+
187
+ vote = user.vote_for(another_item)
188
+ vote.created_at = 3.days.from_now
189
+ vote.save
190
+
191
+ assert_equal 1, Item.rank_tally(:start_at => 3.days.ago, :end_at => 2.days.from_now).length
192
+ assert_equal 2, Item.rank_tally(:start_at => 3.days.ago, :end_at => 4.days.from_now).length
193
+ end
194
+
195
+ def test_rank_tally_inclusion
196
+ user = User.create(:name => 'david')
197
+ item = Item.create(:name => 'XBOX', :description => 'XBOX console')
198
+ item_not_included = Item.create(:name => 'Playstation', :description => 'Playstation console')
199
+
200
+ assert_not_nil user.vote_for(item)
201
+
202
+ assert (Item.rank_tally.include? item)
203
+ assert (not Item.rank_tally.include? item_not_included)
204
+ end
205
+
206
+ def test_rank_tally_default_ordering
207
+ user = User.create(:name => 'david')
208
+ item_for = Item.create(:name => 'XBOX', :description => 'XBOX console')
209
+ item_against = Item.create(:name => 'Playstation', :description => 'Playstation console')
210
+
211
+ assert_not_nil user.vote_for(item_for)
212
+ assert_not_nil user.vote_against(item_against)
213
+
214
+ assert_equal item_for, Item.rank_tally[0]
215
+ assert_equal item_against, Item.rank_tally[1]
216
+ end
217
+
218
+ def test_rank_tally_ascending_ordering
219
+ user = User.create(:name => 'david')
220
+ item_for = Item.create(:name => 'XBOX', :description => 'XBOX console')
221
+ item_against = Item.create(:name => 'Playstation', :description => 'Playstation console')
222
+
223
+ assert_not_nil user.vote_for(item_for)
224
+ assert_not_nil user.vote_against(item_against)
225
+
226
+ assert_equal item_for, Item.rank_tally(:ascending => true)[1]
227
+ assert_equal item_against, Item.rank_tally(:ascending => true)[0]
228
+ end
229
+ end
data/thumbs_up.gemspec CHANGED
@@ -1,51 +1,63 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
- s.name = %q{thumbs_up}
8
- s.version = IO.read('./VERSION')
7
+ s.name = "thumbs_up"
8
+ s.version = "0.4.3"
9
9
 
10
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 Wnętrzak"]
12
- s.date = Date.today.to_s
13
- s.description = %q{ThumbsUp provides dead-simple voting capabilities to ActiveRecord models with karma calculation, a la stackoverflow.com.}
14
- s.email = %q{brady@ldawn.com}
11
+ s.authors = ["Brady Bouchard", "Peter Jackson", "Cosmin Radoi", "Bence Nagy", "Rob Maddox", "Wojciech Wn\u{119}trzak"]
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
15
  s.extra_rdoc_files = [
16
16
  "README.markdown"
17
17
  ]
18
18
  s.files = [
19
- ".gitignore",
20
- "CHANGELOG.markdown",
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
- "thumbs_up.gemspec"
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"
34
36
  ]
35
- s.homepage = %q{http://github.com/brady8/thumbs_up}
36
- s.rdoc_options = ["--charset=UTF-8"]
37
+ s.homepage = "http://github.com/brady8/thumbs_up"
37
38
  s.require_paths = ["lib"]
38
- s.rubygems_version = %q{1.3.7}
39
- s.summary = %q{Voting for ActiveRecord with multiple vote sources and karma calculation.}
39
+ s.rubygems_version = "1.8.10"
40
+ s.summary = "Voting for ActiveRecord with multiple vote sources and karma calculation."
40
41
 
41
42
  if s.respond_to? :specification_version then
42
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
43
43
  s.specification_version = 3
44
44
 
45
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"])
46
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"])
47
55
  end
48
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"])
49
61
  end
50
62
  end
51
63
 
metadata CHANGED
@@ -1,35 +1,75 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: thumbs_up
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.3
4
5
  prerelease:
5
- version: 0.4.1
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Brady Bouchard
9
9
  - Peter Jackson
10
10
  - Cosmin Radoi
11
11
  - Bence Nagy
12
12
  - Rob Maddox
13
- - "Wojciech Wn\xC4\x99trzak"
13
+ - Wojciech Wnętrzak
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
-
18
- date: 2011-04-04 00:00:00 +10:00
19
- default_executable:
20
- dependencies: []
21
-
22
- description: ThumbsUp provides dead-simple voting capabilities to ActiveRecord models with karma calculation, a la stackoverflow.com.
17
+ date: 2011-09-15 00:00:00.000000000 Z
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: activerecord
21
+ requirement: &70315678927000 !ruby/object:Gem::Requirement
22
+ none: false
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ type: :runtime
28
+ prerelease: false
29
+ version_requirements: *70315678927000
30
+ - !ruby/object:Gem::Dependency
31
+ name: bundler
32
+ requirement: &70315678926440 !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: *70315678926440
41
+ - !ruby/object:Gem::Dependency
42
+ name: jeweler
43
+ requirement: &70315678925900 !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: *70315678925900
52
+ - !ruby/object:Gem::Dependency
53
+ name: simplecov
54
+ requirement: &70315678925220 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ! '>='
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ type: :development
61
+ prerelease: false
62
+ version_requirements: *70315678925220
63
+ description: ThumbsUp provides dead-simple voting capabilities to ActiveRecord models
64
+ with karma calculation, a la stackoverflow.com.
23
65
  email: brady@ldawn.com
24
66
  executables: []
25
-
26
67
  extensions: []
27
-
28
- extra_rdoc_files:
68
+ extra_rdoc_files:
29
69
  - README.markdown
30
- files:
31
- - .gitignore
70
+ files:
32
71
  - CHANGELOG.markdown
72
+ - Gemfile
33
73
  - MIT-LICENSE
34
74
  - README.markdown
35
75
  - Rakefile
@@ -42,34 +82,31 @@ files:
42
82
  - lib/has_karma.rb
43
83
  - lib/thumbs_up.rb
44
84
  - rails/init.rb
85
+ - test/test_helper.rb
86
+ - test/test_thumbs_up.rb
45
87
  - thumbs_up.gemspec
46
- has_rdoc: true
47
88
  homepage: http://github.com/brady8/thumbs_up
48
89
  licenses: []
49
-
50
90
  post_install_message:
51
- rdoc_options:
52
- - --charset=UTF-8
53
- require_paths:
91
+ rdoc_options: []
92
+ require_paths:
54
93
  - lib
55
- required_ruby_version: !ruby/object:Gem::Requirement
94
+ required_ruby_version: !ruby/object:Gem::Requirement
56
95
  none: false
57
- requirements:
58
- - - ">="
59
- - !ruby/object:Gem::Version
60
- version: "0"
61
- required_rubygems_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ! '>='
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
101
  none: false
63
- requirements:
64
- - - ">="
65
- - !ruby/object:Gem::Version
66
- version: "0"
102
+ requirements:
103
+ - - ! '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
67
106
  requirements: []
68
-
69
107
  rubyforge_project:
70
- rubygems_version: 1.5.3
108
+ rubygems_version: 1.8.10
71
109
  signing_key:
72
110
  specification_version: 3
73
111
  summary: Voting for ActiveRecord with multiple vote sources and karma calculation.
74
112
  test_files: []
75
-
data/.gitignore DELETED
@@ -1,3 +0,0 @@
1
- *.gem
2
- pkg/*
3
- Gemfile.lock