thumbs_up 0.3.2 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
1
  *.gem
2
2
  pkg/*
3
+ Gemfile.lock
data/README.markdown CHANGED
@@ -65,7 +65,7 @@ Usage
65
65
  voter.vote(voteable, vote) # Adds either a +1 or -1 vote: vote => true (+1), vote => false (-1)
66
66
 
67
67
  voter.vote_exclusively_for(voteable) # Removes any previous votes by that particular voter, and votes for.
68
- voter.vote_exclusively_for(voteable) # Removes any previous votes by that particular voter, and votes against.
68
+ voter.vote_exclusively_against(voteable) # Removes any previous votes by that particular voter, and votes against.
69
69
 
70
70
  ### Querying votes
71
71
 
@@ -98,6 +98,21 @@ 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
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.
106
+
107
+ ##### Rank_Tally Options:
108
+ :start_at - Restrict the votes to those created after a certain time
109
+ :end_at - Restrict the votes to those created before a certain time
110
+ :conditions - A piece of SQL conditions to add to the query
111
+ :limit - The maximum number of voteables to return
112
+ :ascending - Boolean Default false. If specified true, results will be returned in ascending order (from bottom up)
113
+ :at_least - Item must have at least X votes
114
+ :at_most - Item may not have more than X votes
115
+
101
116
  #### Lower level queries
102
117
 
103
118
  positiveVoteCount = voteable.votes_for
@@ -123,6 +138,9 @@ ThumbsUp by default only allows one vote per user. This can be changed by removi
123
138
 
124
139
  add_index :votes, ["voter_id", "voter_type", "voteable_id", "voteable_type"], :unique => true, :name => "uniq_one_vote_only"
125
140
 
141
+ You can also use `--unique-voting false` when running the generator command:
142
+
143
+ rails generate thumbs_up --unique-voting false
126
144
 
127
145
  Credits
128
146
  =======
data/Rakefile CHANGED
@@ -1,19 +1,50 @@
1
1
  # encoding: UTF-8
2
2
  require 'rubygems'
3
- require 'rake'
3
+ require 'bundler'
4
4
 
5
5
  begin
6
- require 'jeweler'
7
- Jeweler::Tasks.new do |gem|
8
- gem.name = "thumbs_up"
9
- gem.summary = "Voting for ActiveRecord with multiple vote sources and karma calculation."
10
- gem.description = "ThumbsUp provides dead-simple voting capabilities to ActiveRecord models with karma calculation, a la stackoverflow.com."
11
- gem.email = "brady@ldawn.com"
12
- gem.homepage = "http://github.com/brady8/thumbs_up"
13
- gem.authors = ["Brady Bouchard", "Peter Jackson", "Cosmin Radoi", "Bence Nagy", "Rob Maddox", "Wojciech Wnętrzak"]
14
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
15
- end
16
- Jeweler::GemcutterTasks.new
17
- rescue LoadError
18
- puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
19
- end
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
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
+ require 'rake/testtask'
27
+ Rake::TestTask.new(:test) do |test|
28
+ test.libs << 'lib' << 'test'
29
+ test.pattern = 'test/**/test_*.rb'
30
+ test.verbose = true
31
+ end
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'
41
+ Rake::RDocTask.new do |rdoc|
42
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
43
+
44
+ rdoc.rdoc_dir = 'rdoc'
45
+ rdoc.title = "leaderboard #{version}"
46
+ rdoc.rdoc_files.include('README*')
47
+ rdoc.rdoc_files.include('lib/**/*.rb')
48
+ end
49
+
50
+ task :default => :test
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.2
1
+ 0.4
@@ -15,6 +15,60 @@ module ThumbsUp
15
15
  end
16
16
 
17
17
  module SingletonMethods
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
+ # :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")
63
+ : t.order("joined_#{Vote.table_name}.Vote_Total DESC")
64
+
65
+ t = t.having(["COUNT(joined_#{Vote.table_name}.voteable_id) > 0",
66
+ (options[:at_least] ? "joined_votes.Vote_Total >= #{sanitize(options[:at_least])}" : nil),
67
+ (options[:at_most] ? "joined_votes.Vote_Total <= #{sanitize(options[:at_most])}" : nil)
68
+ ].compact.join(' AND '))
69
+
70
+ t.select("#{self.table_name}.*, joined_#{Vote.table_name}.Vote_Total")
71
+ end
18
72
 
19
73
  # Calculate the vote counts for all voteables of my type.
20
74
  # This method returns all voteables with at least one vote.
data/lib/acts_as_voter.rb CHANGED
@@ -75,7 +75,7 @@ module ThumbsUp #:nodoc:
75
75
  end
76
76
 
77
77
  def vote(voteable, options = {})
78
- raise ArgumentError "you must specify :up or :down in order to vote" unless options[:direction] && [:up, :down].include?(options[:direction].to_sym)
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
80
  self.clear_votes(voteable)
81
81
  end
@@ -12,8 +12,10 @@ class ThumbsUpMigration < ActiveRecord::Migration
12
12
  add_index :votes, [:voter_id, :voter_type]
13
13
  add_index :votes, [:voteable_id, :voteable_type]
14
14
 
15
- # Comment out the line below to allow multiple votes per voter on a single entity.
15
+ <% if options[:unique_voting] == true %>
16
+ # Comment out the line below to allow multiple votes per voter on a single entity.
16
17
  add_index :votes, [:voter_id, :voter_type, :voteable_id, :voteable_type], :unique => true, :name => 'fk_one_vote_per_user_per_entity'
18
+ <% end %>
17
19
  end
18
20
 
19
21
  def self.down
@@ -10,7 +10,8 @@ class Vote < ActiveRecord::Base
10
10
 
11
11
  attr_accessible :vote, :voter, :voteable
12
12
 
13
+ <% if options[:unique_voting] == true %>
13
14
  # Comment out the line below to allow multiple votes per user.
14
15
  validates_uniqueness_of :voteable_id, :scope => [:voteable_type, :voter_type, :voter_id]
15
-
16
+ <% end %>
16
17
  end
@@ -5,6 +5,8 @@ class ThumbsUpGenerator < Rails::Generators::Base
5
5
  include Rails::Generators::Migration
6
6
 
7
7
  source_root File.expand_path('../templates', __FILE__)
8
+
9
+ class_option :unique_voting, :type => :boolean, :default => true, :desc => 'Do you want only one vote allowed per voter? (default: true)'
8
10
 
9
11
  # Implement the required interface for Rails::Generators::Migration.
10
12
  def self.next_migration_number(dirname) #:nodoc:
data/rails/init.rb CHANGED
@@ -3,8 +3,8 @@ RAILS_DEFAULT_LOGGER.info "** thumbs_up: setting up load paths **"
3
3
  %w{ models controllers helpers }.each do |dir|
4
4
  path = File.join(File.dirname(__FILE__) , 'lib', dir)
5
5
  $LOAD_PATH << path
6
- ActiveSupport::Dependencies.load_paths << path
7
- ActiveSupport::Dependencies.load_once_paths.delete(path)
6
+ ActiveSupport::Dependencies.autoload_paths << path
7
+ ActiveSupport::Dependencies.autoload_once_paths.delete(path)
8
8
  end
9
9
 
10
- require 'thumbs_up'
10
+ require 'thumbs_up'
metadata CHANGED
@@ -1,12 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: thumbs_up
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 3
8
- - 2
9
- version: 0.3.2
4
+ prerelease:
5
+ version: "0.4"
10
6
  platform: ruby
11
7
  authors:
12
8
  - Brady Bouchard
@@ -19,7 +15,7 @@ autorequire:
19
15
  bindir: bin
20
16
  cert_chain: []
21
17
 
22
- date: 2010-12-16 00:00:00 -07:00
18
+ date: 2011-04-01 00:00:00 +10:00
23
19
  default_executable:
24
20
  dependencies: []
25
21
 
@@ -61,21 +57,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
61
57
  requirements:
62
58
  - - ">="
63
59
  - !ruby/object:Gem::Version
64
- segments:
65
- - 0
66
60
  version: "0"
67
61
  required_rubygems_version: !ruby/object:Gem::Requirement
68
62
  none: false
69
63
  requirements:
70
64
  - - ">="
71
65
  - !ruby/object:Gem::Version
72
- segments:
73
- - 0
74
66
  version: "0"
75
67
  requirements: []
76
68
 
77
69
  rubyforge_project:
78
- rubygems_version: 1.3.7
70
+ rubygems_version: 1.5.3
79
71
  signing_key:
80
72
  specification_version: 3
81
73
  summary: Voting for ActiveRecord with multiple vote sources and karma calculation.