voter_love 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +7 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +114 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +28 -0
- data/lib/generators/voter_love/templates/migration.rb +25 -0
- data/lib/generators/voter_love/voter_love_generator.rb +20 -0
- data/lib/tasks/voter_love_tasks.rake +4 -0
- data/lib/voter_love/exceptions.rb +29 -0
- data/lib/voter_love/version.rb +3 -0
- data/lib/voter_love/votable.rb +20 -0
- data/lib/voter_love/voter.rb +138 -0
- data/lib/voter_love/votes.rb +8 -0
- data/lib/voter_love.rb +29 -0
- data/spec/database.yml +3 -0
- data/spec/database.yml.sample +3 -0
- data/spec/generators/voter_love_generator_spec.rb +28 -0
- data/spec/lib/voter_love_spec.rb +236 -0
- data/spec/models.rb +10 -0
- data/spec/schema.rb +31 -0
- data/spec/spec_helper.rb +37 -0
- data/voter_love.gemspec +29 -0
- metadata +112 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
# Declare your gem's dependencies in voter_love.gemspec.
|
4
|
+
# Bundler will treat runtime dependencies like base dependencies, and
|
5
|
+
# development dependencies will be added by default to the :development group.
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
# Declare any dependencies that are still in development here instead of in
|
9
|
+
# your gemspec. These might include edge Rails or gems from your path or
|
10
|
+
# Git. Remember to move these dependencies to your gemspec before releasing
|
11
|
+
# your gem to rubygems.org.
|
12
|
+
|
13
|
+
# To use debugger
|
14
|
+
# gem 'ruby-debug19', :require => 'ruby-debug'
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
voter_love (0.0.1)
|
5
|
+
rails (~> 3.1.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
actionmailer (3.1.0)
|
11
|
+
actionpack (= 3.1.0)
|
12
|
+
mail (~> 2.3.0)
|
13
|
+
actionpack (3.1.0)
|
14
|
+
activemodel (= 3.1.0)
|
15
|
+
activesupport (= 3.1.0)
|
16
|
+
builder (~> 3.0.0)
|
17
|
+
erubis (~> 2.7.0)
|
18
|
+
i18n (~> 0.6)
|
19
|
+
rack (~> 1.3.2)
|
20
|
+
rack-cache (~> 1.0.3)
|
21
|
+
rack-mount (~> 0.8.2)
|
22
|
+
rack-test (~> 0.6.1)
|
23
|
+
sprockets (~> 2.0.0)
|
24
|
+
activemodel (3.1.0)
|
25
|
+
activesupport (= 3.1.0)
|
26
|
+
bcrypt-ruby (~> 3.0.0)
|
27
|
+
builder (~> 3.0.0)
|
28
|
+
i18n (~> 0.6)
|
29
|
+
activerecord (3.1.0)
|
30
|
+
activemodel (= 3.1.0)
|
31
|
+
activesupport (= 3.1.0)
|
32
|
+
arel (~> 2.2.1)
|
33
|
+
tzinfo (~> 0.3.29)
|
34
|
+
activeresource (3.1.0)
|
35
|
+
activemodel (= 3.1.0)
|
36
|
+
activesupport (= 3.1.0)
|
37
|
+
activesupport (3.1.0)
|
38
|
+
multi_json (~> 1.0)
|
39
|
+
arel (2.2.1)
|
40
|
+
bcrypt-ruby (3.0.1)
|
41
|
+
builder (3.0.0)
|
42
|
+
diff-lcs (1.1.3)
|
43
|
+
erubis (2.7.0)
|
44
|
+
generator_spec (0.8.4)
|
45
|
+
rails (>= 3.0, < 4.0)
|
46
|
+
rspec-rails
|
47
|
+
hike (1.2.1)
|
48
|
+
i18n (0.6.0)
|
49
|
+
mail (2.3.0)
|
50
|
+
i18n (>= 0.4.0)
|
51
|
+
mime-types (~> 1.16)
|
52
|
+
treetop (~> 1.4.8)
|
53
|
+
mime-types (1.16)
|
54
|
+
multi_json (1.0.3)
|
55
|
+
polyglot (0.3.2)
|
56
|
+
rack (1.3.3)
|
57
|
+
rack-cache (1.0.3)
|
58
|
+
rack (>= 0.4)
|
59
|
+
rack-mount (0.8.3)
|
60
|
+
rack (>= 1.0.0)
|
61
|
+
rack-ssl (1.3.2)
|
62
|
+
rack
|
63
|
+
rack-test (0.6.1)
|
64
|
+
rack (>= 1.0)
|
65
|
+
rails (3.1.0)
|
66
|
+
actionmailer (= 3.1.0)
|
67
|
+
actionpack (= 3.1.0)
|
68
|
+
activerecord (= 3.1.0)
|
69
|
+
activeresource (= 3.1.0)
|
70
|
+
activesupport (= 3.1.0)
|
71
|
+
bundler (~> 1.0)
|
72
|
+
railties (= 3.1.0)
|
73
|
+
railties (3.1.0)
|
74
|
+
actionpack (= 3.1.0)
|
75
|
+
activesupport (= 3.1.0)
|
76
|
+
rack-ssl (~> 1.3.2)
|
77
|
+
rake (>= 0.8.7)
|
78
|
+
rdoc (~> 3.4)
|
79
|
+
thor (~> 0.14.6)
|
80
|
+
rake (0.9.2)
|
81
|
+
rdoc (3.9.4)
|
82
|
+
rspec (2.5.0)
|
83
|
+
rspec-core (~> 2.5.0)
|
84
|
+
rspec-expectations (~> 2.5.0)
|
85
|
+
rspec-mocks (~> 2.5.0)
|
86
|
+
rspec-core (2.5.2)
|
87
|
+
rspec-expectations (2.5.0)
|
88
|
+
diff-lcs (~> 1.1.2)
|
89
|
+
rspec-mocks (2.5.0)
|
90
|
+
rspec-rails (2.5.0)
|
91
|
+
actionpack (~> 3.0)
|
92
|
+
activesupport (~> 3.0)
|
93
|
+
railties (~> 3.0)
|
94
|
+
rspec (~> 2.5.0)
|
95
|
+
sprockets (2.0.0)
|
96
|
+
hike (~> 1.2)
|
97
|
+
rack (~> 1.0)
|
98
|
+
tilt (!= 1.3.0, ~> 1.1)
|
99
|
+
sqlite3 (1.3.4)
|
100
|
+
thor (0.14.6)
|
101
|
+
tilt (1.3.3)
|
102
|
+
treetop (1.4.10)
|
103
|
+
polyglot
|
104
|
+
polyglot (>= 0.3.1)
|
105
|
+
tzinfo (0.3.29)
|
106
|
+
|
107
|
+
PLATFORMS
|
108
|
+
ruby
|
109
|
+
|
110
|
+
DEPENDENCIES
|
111
|
+
generator_spec (~> 0.8.2)
|
112
|
+
rspec (~> 2.5.0)
|
113
|
+
sqlite3
|
114
|
+
voter_love!
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2011 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'VoterLove'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
Bundler::GemHelper.install_tasks
|
24
|
+
|
25
|
+
require 'rspec/core/rake_task'
|
26
|
+
RSpec::Core::RakeTask.new(:spec)
|
27
|
+
|
28
|
+
task :default => :spec
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class CreateVoterLoveTables < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :votes do |t|
|
4
|
+
t.string :votable_type
|
5
|
+
t.integer :votable_id
|
6
|
+
t.string :voter_type
|
7
|
+
t.integer :voter_id
|
8
|
+
t.boolean :up_vote, :null => false
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
|
13
|
+
add_index :votes, [:votable_type, :votable_id]
|
14
|
+
add_index :votes, [:voter_type, :voter_id]
|
15
|
+
add_index :votes, [:votable_type, :votable_id, :voter_type, :voter_id], :name => "unique_voters", :unique => true
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.down
|
19
|
+
remove_index :votes, :column => [:votable_type, :votable_id]
|
20
|
+
remove_index :votes, :column => [:voter_type, :voter_id]
|
21
|
+
remove_index :votes, :name => "unique_voters"
|
22
|
+
|
23
|
+
drop_table :votes
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rails/generators/migration'
|
2
|
+
require 'rails/generators/active_record'
|
3
|
+
|
4
|
+
class VoterLoveGenerator < Rails::Generators::Base
|
5
|
+
include Rails::Generators::Migration
|
6
|
+
|
7
|
+
desc "Generates a migration for the Vote model"
|
8
|
+
|
9
|
+
def self.source_root
|
10
|
+
@source_root ||= File.dirname(__FILE__) + '/templates'
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.next_migration_number(path)
|
14
|
+
ActiveRecord::Generators::Base.next_migration_number(path)
|
15
|
+
end
|
16
|
+
|
17
|
+
def generate_migration
|
18
|
+
migration_template 'migration.rb', 'db/migrate/create_voter_love_tables'
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module VoterLove
|
2
|
+
module Exceptions
|
3
|
+
class AlreadyVotedError < StandardError
|
4
|
+
attr_reader :up_vote
|
5
|
+
|
6
|
+
def initialize(up_vote)
|
7
|
+
vote = if up_vote
|
8
|
+
"up voted"
|
9
|
+
else
|
10
|
+
"down voted"
|
11
|
+
end
|
12
|
+
|
13
|
+
super "The votable was already #{vote} by the voter."
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class NotVotedError < StandardError
|
18
|
+
def initialize
|
19
|
+
super "The votable was not voted by the voter."
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class InvalidVotableError < StandardError
|
24
|
+
def initialize
|
25
|
+
super "Invalid votable."
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module VoterLove
|
2
|
+
module Votable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
has_many :votes, :class_name => "VoterLove::Votes", :as => :votable
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def votable?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the difference of down and up votes.
|
16
|
+
def score
|
17
|
+
self.up_votes - self.down_votes
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module VoterLove
|
2
|
+
module Voter
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
has_many :votes, :class_name => "VoterLove::Vote", :as => :voter
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def voter?
|
11
|
+
true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Up vote any "votable" object.
|
16
|
+
# Raises an AlreadyVotedError if the voter already voted on the object.
|
17
|
+
def up_vote(votable)
|
18
|
+
is_votable?(votable)
|
19
|
+
|
20
|
+
vote = get_vote(votable)
|
21
|
+
|
22
|
+
if vote
|
23
|
+
if vote.up_vote
|
24
|
+
raise Exceptions::AlreadyVotedError.new(true)
|
25
|
+
end
|
26
|
+
vote.up_vote = true
|
27
|
+
votable.down_votes -= 1
|
28
|
+
self.down_votes -= 1 if has_attribute?(:down_votes)
|
29
|
+
end
|
30
|
+
else
|
31
|
+
vote = Vote.create(:votable => votable, :voter => self, :up_vote => true)
|
32
|
+
end
|
33
|
+
|
34
|
+
votable.up_votes += 1
|
35
|
+
self.up_votes += 1 if has_attribute?(:up_votes)
|
36
|
+
|
37
|
+
Vote.transaction do
|
38
|
+
save
|
39
|
+
votable.save
|
40
|
+
vote.save
|
41
|
+
end
|
42
|
+
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
# Up vote any "votable" object without raising an error. Vote is ignored.
|
47
|
+
def up_vote!(votable)
|
48
|
+
begin
|
49
|
+
up_vote(votable)
|
50
|
+
success = true
|
51
|
+
rescue Exceptions::AlreadyVotedError
|
52
|
+
success = false
|
53
|
+
end
|
54
|
+
success
|
55
|
+
end
|
56
|
+
|
57
|
+
# Down vote a "votable" object.
|
58
|
+
# Raises an AlreadyVotedError if the voter already voted on the object.
|
59
|
+
def down_vote(votable)
|
60
|
+
is_votable?(votable)
|
61
|
+
|
62
|
+
vote = get_vote(votable)
|
63
|
+
|
64
|
+
if vote
|
65
|
+
unless vote.up_vote
|
66
|
+
raise Exceptions::AlreadyVotedError.new(false)
|
67
|
+
else
|
68
|
+
vote.up_vote = false
|
69
|
+
votable.up_votes -= 1
|
70
|
+
self.up_votes -= 1 if has_attribute?(:up_votes)
|
71
|
+
end
|
72
|
+
else
|
73
|
+
vote = Vote.create(:votable => votable, :voter => self, :up_vote => false)
|
74
|
+
end
|
75
|
+
|
76
|
+
votable.down_votes += 1
|
77
|
+
self.down_votes += 1 if has_attribute?(:down_votes)
|
78
|
+
|
79
|
+
Vote.transaction do
|
80
|
+
save
|
81
|
+
votable.save
|
82
|
+
vote.save
|
83
|
+
end
|
84
|
+
|
85
|
+
true
|
86
|
+
end
|
87
|
+
|
88
|
+
# Down vote a "votable" object without raising an error. Vote is ignored.
|
89
|
+
def down_vote!(votable)
|
90
|
+
begin
|
91
|
+
down_vote(votable)
|
92
|
+
success = true
|
93
|
+
rescue Exceptions::AlreadyVotedError
|
94
|
+
success = false
|
95
|
+
end
|
96
|
+
success
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns true if the voter voted for the "votable".
|
100
|
+
def voted?(votable)
|
101
|
+
is_votable?(votable)
|
102
|
+
vote = get_vote(votable)
|
103
|
+
!vote.nil?
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns true if the voter up voted the "votable".
|
107
|
+
def up_voted?(votable)
|
108
|
+
is_votable?(votable)
|
109
|
+
vote = get_vote(votable)
|
110
|
+
return false if vote.nil?
|
111
|
+
return true if vote.has_attribute?(:up_vote) && vote.up_vote
|
112
|
+
false
|
113
|
+
end
|
114
|
+
|
115
|
+
# Returns true if the voter down voted the "votable".
|
116
|
+
def down_voted?(votable)
|
117
|
+
is_votable?(votable)
|
118
|
+
vote = get_vote(votable)
|
119
|
+
return false if vote.nil?
|
120
|
+
return true if vote.has_attribute?(:up_vote) && !vote.up_vote
|
121
|
+
false
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
def get_vote(votable)
|
127
|
+
Vote.where(
|
128
|
+
:votable_type => votable.class.to_s,
|
129
|
+
:votable_id => votable.id,
|
130
|
+
:voter_type => self.class.to_s,
|
131
|
+
:voter_id => self.id).try(:first)
|
132
|
+
end
|
133
|
+
|
134
|
+
def is_votable?(votable)
|
135
|
+
raise Exceptions::InvalidVotableError unless votable.class.votable?
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/lib/voter_love.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'voter_love/votes'
|
2
|
+
require 'voter_love/votable'
|
3
|
+
require 'voter_love/voter'
|
4
|
+
require 'voter_love/exceptions'
|
5
|
+
|
6
|
+
module VoterLove
|
7
|
+
def votable?
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
def voter?
|
12
|
+
false
|
13
|
+
end
|
14
|
+
|
15
|
+
# add this to the model you want to be able to vote on.
|
16
|
+
# Example:
|
17
|
+
# class Links < ActiveRecord::Base
|
18
|
+
# acts_as_votable
|
19
|
+
# end
|
20
|
+
def acts_as_votable
|
21
|
+
include Votable
|
22
|
+
end
|
23
|
+
|
24
|
+
def acts_as_voter
|
25
|
+
include Voter
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
ActiveRecord::Base.extend VoterLove
|
data/spec/database.yml
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'action_controller'
|
3
|
+
require 'generator_spec/test_case'
|
4
|
+
require 'generators/voter_love/voter_love_generator'
|
5
|
+
|
6
|
+
describe VoterLoveGenerator do
|
7
|
+
include GeneratorSpec::TestCase
|
8
|
+
destination File.expand_path("/tmp", __FILE__)
|
9
|
+
tests VoterLoveGenerator
|
10
|
+
|
11
|
+
before do
|
12
|
+
prepare_destination
|
13
|
+
run_generator
|
14
|
+
end
|
15
|
+
|
16
|
+
specify do
|
17
|
+
destination_root.should have_structure {
|
18
|
+
directory "db" do
|
19
|
+
directory "migrate" do
|
20
|
+
migration "create_voter_love_tables" do
|
21
|
+
contains "class CreateVoterLoveTables"
|
22
|
+
contains "create_table :votes"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe "Voter Love" do
|
4
|
+
before(:each) do
|
5
|
+
@votable = VotableModel.create(:name => "Votable 1")
|
6
|
+
@voter = VoterModel.create(:name => "Voter 1")
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should create a votable instance" do
|
10
|
+
@votable.class.should == VotableModel
|
11
|
+
@votable.class.votable?.should == true
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should create a voter instance" do
|
15
|
+
@voter.class.should == VoterModel
|
16
|
+
@voter.class.voter?.should == true
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should get correct vote summary" do
|
20
|
+
@voter.up_vote(@votable).should == true
|
21
|
+
@votable.votes.should == 1
|
22
|
+
@voter.down_vote(@votable).should == true
|
23
|
+
@votable.votes.should == -1
|
24
|
+
@voter.unvote(@votable).should == true
|
25
|
+
@votable.votes.should == 0
|
26
|
+
end
|
27
|
+
|
28
|
+
it "votable should have up vote votes" do
|
29
|
+
@votable.votes.length.should == 0
|
30
|
+
@voter.up_vote(@votable)
|
31
|
+
@votable.votes.reload.length.should == 1
|
32
|
+
@votable.votes[0].up_vote?.should be_true
|
33
|
+
end
|
34
|
+
|
35
|
+
it "voter should have up vote votes" do
|
36
|
+
@voter.votes.length.should == 0
|
37
|
+
@voter.up_vote(@votable)
|
38
|
+
@voter.votes.reload.length.should == 1
|
39
|
+
@voter.votes[0].up_vote?.should be_true
|
40
|
+
end
|
41
|
+
|
42
|
+
it "votable should have down vote votes" do
|
43
|
+
@votable.votes.length.should == 0
|
44
|
+
@voter.down_vote(@votable)
|
45
|
+
@votable.votes.reload.length.should == 1
|
46
|
+
@votable.votes[0].up_vote?.should be_false
|
47
|
+
end
|
48
|
+
|
49
|
+
it "voter should have down vote votes" do
|
50
|
+
@voter.votes.length.should == 0
|
51
|
+
@voter.down_vote(@votable)
|
52
|
+
@voter.votes.reload.length.should == 1
|
53
|
+
@voter.votes[0].up_vote?.should be_false
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "up vote" do
|
57
|
+
it "should increase up votes of votable by one" do
|
58
|
+
@votable.up_votes.should == 0
|
59
|
+
@voter.up_vote(@votable)
|
60
|
+
@votable.up_votes.should == 1
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should increase up votes of voter by one" do
|
64
|
+
@voter.up_votes.should == 0
|
65
|
+
@voter.up_vote(@votable)
|
66
|
+
@voter.up_votes.should == 1
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should create a voting" do
|
70
|
+
VoterLove::Votes.count.should == 0
|
71
|
+
@voter.up_vote(@votable)
|
72
|
+
VoterLove::Votes.count.should == 1
|
73
|
+
voting = VoterLove::Votes.first
|
74
|
+
voting.votable.should == @votable
|
75
|
+
voting.voter.should == @voter
|
76
|
+
voting.up_vote.should == true
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should only allow a voter to up vote a votable once" do
|
80
|
+
@voter.up_vote(@votable)
|
81
|
+
lambda { @voter.up_vote(@votable) }.should raise_error(VoterLove::Exceptions::AlreadyVotedError)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should only allow a voter to up vote a votable once without raising an error" do
|
85
|
+
@voter.up_vote!(@votable)
|
86
|
+
lambda {
|
87
|
+
@voter.up_vote!(@votable).should == false
|
88
|
+
}.should_not raise_error(VoterLove::Exceptions::AlreadyVotedError)
|
89
|
+
VoterLove::Votes.count.should == 1
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should change a down vote to an up vote" do
|
93
|
+
@voter.down_vote(@votable)
|
94
|
+
@votable.up_votes.should == 0
|
95
|
+
@votable.down_votes.should == 1
|
96
|
+
@voter.up_votes.should == 0
|
97
|
+
@voter.down_votes.should == 1
|
98
|
+
VoterLove::Votes.count.should == 1
|
99
|
+
VoterLove::Votes.first.up_vote.should be_false
|
100
|
+
@voter.up_vote(@votable)
|
101
|
+
@votable.up_votes.should == 1
|
102
|
+
@votable.down_votes.should == 0
|
103
|
+
@voter.up_votes.should == 1
|
104
|
+
@voter.down_votes.should == 0
|
105
|
+
VoterLove::Votes.count.should == 1
|
106
|
+
VoterLove::Votes.first.up_vote.should be_true
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should allow up votes from different voters" do
|
110
|
+
@voter2 = VoterModel.create(:name => "Voter 2")
|
111
|
+
@voter.up_vote(@votable)
|
112
|
+
@voter2.up_vote(@votable)
|
113
|
+
@votable.up_votes.should == 2
|
114
|
+
VoterLove::Votes.count.should == 2
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should raise an error for an invalid votable" do
|
118
|
+
invalid_votable = InvalidVotableModel.create
|
119
|
+
lambda { @voter.up_vote(invalid_votable) }.should raise_error(VoterLove::Exceptions::InvalidVotableError)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should check if voter up voted votable" do
|
123
|
+
@voter.up_vote(@votable)
|
124
|
+
@voter.voted?(@votable).should be_true
|
125
|
+
@voter.up_voted?(@votable).should be_true
|
126
|
+
@voter.down_voted?(@votable).should be_false
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "vote down" do
|
131
|
+
it "should decrease down votes of votable by one" do
|
132
|
+
@votable.down_votes.should == 0
|
133
|
+
@voter.down_vote(@votable)
|
134
|
+
@votable.down_votes.should == 1
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should decrease down votes of voter by one" do
|
138
|
+
@voter.down_votes.should == 0
|
139
|
+
@voter.down_vote(@votable)
|
140
|
+
@voter.down_votes.should == 1
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should create a voting" do
|
144
|
+
VoterLove::Votes.count.should == 0
|
145
|
+
@voter.down_vote(@votable)
|
146
|
+
VoterLove::Votes.count.should == 1
|
147
|
+
voting = VoterLove::Votes.first
|
148
|
+
voting.votable.should == @votable
|
149
|
+
voting.voter.should == @voter
|
150
|
+
voting.up_vote.should == false
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should only allow a voter to down vote a votable once" do
|
154
|
+
@voter.down_vote(@votable)
|
155
|
+
lambda { @voter.down_vote(@votable) }.should raise_error(VoterLove::Exceptions::AlreadyVotedError)
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should only allow a voter to down vote a votable once without raising an error" do
|
159
|
+
@voter.down_vote!(@votable)
|
160
|
+
lambda {
|
161
|
+
@voter.down_vote!(@votable).should == false
|
162
|
+
}.should_not raise_error(VoterLove::Exceptions::AlreadyVotedError)
|
163
|
+
VoterLove::Votes.count.should == 1
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should change an up vote to a down vote" do
|
167
|
+
@voter.up_vote(@votable)
|
168
|
+
@votable.up_votes.should == 1
|
169
|
+
@votable.down_votes.should == 0
|
170
|
+
@voter.up_votes.should == 1
|
171
|
+
@voter.down_votes.should == 0
|
172
|
+
VoterLove::Votes.count.should == 1
|
173
|
+
VoterLove::Votes.first.up_vote.should be_true
|
174
|
+
@voter.down_vote(@votable)
|
175
|
+
@votable.up_votes.should == 0
|
176
|
+
@votable.down_votes.should == 1
|
177
|
+
@voter.up_votes.should == 0
|
178
|
+
@voter.down_votes.should == 1
|
179
|
+
VoterLove::Votes.count.should == 1
|
180
|
+
VoterLove::Votes.first.up_vote.should be_false
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should allow down votes from different voters" do
|
184
|
+
@voter2 = VoterModel.create(:name => "Voter 2")
|
185
|
+
@voter.down_vote(@votable)
|
186
|
+
@voter2.down_vote(@votable)
|
187
|
+
@votable.down_votes.should == 2
|
188
|
+
VoterLove::Votes.count.should == 2
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should raise an error for an invalid votable" do
|
192
|
+
invalid_votable = InvalidVotableModel.create
|
193
|
+
lambda { @voter.down_vote(invalid_votable) }.should raise_error(VoterLove::Exceptions::InvalidVotableError)
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should check if voter down voted votable" do
|
197
|
+
@voter.down_vote(@votable)
|
198
|
+
@voter.voted?(@votable).should be_true
|
199
|
+
@voter.up_voted?(@votable).should be_false
|
200
|
+
@voter.down_voted?(@votable).should be_true
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe "unvote" do
|
205
|
+
it "should decrease the up votes if up voted before" do
|
206
|
+
@voter.up_vote(@votable)
|
207
|
+
@votable.up_votes.should == 1
|
208
|
+
@voter.up_votes.should == 1
|
209
|
+
@voter.unvote(@votable)
|
210
|
+
@votable.up_votes.should == 0
|
211
|
+
@voter.up_votes.should == 0
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should remove the voting" do
|
215
|
+
@voter.up_vote(@votable)
|
216
|
+
VoterLove::Votes.count.should == 1
|
217
|
+
@voter.unvote(@votable)
|
218
|
+
VoterLove::Votes.count.should == 0
|
219
|
+
end
|
220
|
+
|
221
|
+
it "should raise an error if voter didn't vote for the votable" do
|
222
|
+
lambda { @voter.unvote(@votable) }.should raise_error(VoterLove::Exceptions::NotVotedError)
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should not raise error if voter didn't vote for the votable and unvote! is called" do
|
226
|
+
lambda {
|
227
|
+
@voter.unvote!(@votable).should == false
|
228
|
+
}.should_not raise_error(VoterLove::Exceptions::NotVotedError)
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should raise an error for an invalid votable" do
|
232
|
+
invalid_votable = InvalidVotableModel.create
|
233
|
+
lambda { @voter.unvote(invalid_votable) }.should raise_error(VoterLove::Exceptions::InvalidVotableError)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
data/spec/models.rb
ADDED
data/spec/schema.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
ActiveRecord::Schema.define :version => 0 do
|
2
|
+
create_table :votable_models, :force => true do |t|
|
3
|
+
t.string :name
|
4
|
+
t.integer :up_votes, :null => false, :default => 0
|
5
|
+
t.integer :down_votes, :null => false, :default => 0
|
6
|
+
end
|
7
|
+
|
8
|
+
create_table :voter_models, :force => true do |t|
|
9
|
+
t.string :name
|
10
|
+
t.integer :up_votes, :null => false, :default => 0
|
11
|
+
t.integer :down_votes, :null => false, :default => 0
|
12
|
+
end
|
13
|
+
|
14
|
+
create_table :invalid_votable_models, :force => true do |t|
|
15
|
+
t.string :name
|
16
|
+
end
|
17
|
+
|
18
|
+
create_table :votes, :force => true do |t|
|
19
|
+
t.string :votable_type
|
20
|
+
t.integer :votable_id
|
21
|
+
t.string :voter_type
|
22
|
+
t.integer :voter_id
|
23
|
+
t.boolean :up_vote, :null => false
|
24
|
+
|
25
|
+
t.timestamps
|
26
|
+
end
|
27
|
+
|
28
|
+
add_index :votes, [:votable_type, :votable_id]
|
29
|
+
add_index :votes, [:voter_type, :voter_id]
|
30
|
+
add_index :votes, [:votable_type, :votable_id, :voter_type, :voter_id], :name => "unique_voters", :unique => true
|
31
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require 'logger'
|
4
|
+
require 'rspec'
|
5
|
+
require 'active_record'
|
6
|
+
require 'database_cleaner'
|
7
|
+
|
8
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
|
9
|
+
require 'acts_as_votable'
|
10
|
+
|
11
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + '/debug.log')
|
12
|
+
ActiveRecord::Base.configurations = YAML::load_file(File.dirname(__FILE__) + '/database.yml')
|
13
|
+
ActiveRecord::Base.establish_connection(ENV['DB'] || 'sqlite3')
|
14
|
+
|
15
|
+
ActiveRecord::Base.silence do
|
16
|
+
ActiveRecord::Migration.verbose = false
|
17
|
+
|
18
|
+
load(File.dirname(__FILE__) + '/schema.rb')
|
19
|
+
load(File.dirname(__FILE__) + '/models.rb')
|
20
|
+
end
|
21
|
+
|
22
|
+
RSpec.configure do |config|
|
23
|
+
config.filter_run :focus => true
|
24
|
+
config.run_all_when_everything_filtered = true
|
25
|
+
config.filter_run_excluding :exclude => true
|
26
|
+
|
27
|
+
config.mock_with :rspec
|
28
|
+
|
29
|
+
config.before(:suite) do
|
30
|
+
DatabaseCleaner.strategy = :truncation
|
31
|
+
DatabaseCleaner.clean
|
32
|
+
end
|
33
|
+
|
34
|
+
config.after(:each) do
|
35
|
+
DatabaseCleaner.clean
|
36
|
+
end
|
37
|
+
end
|
data/voter_love.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
|
3
|
+
# Maintain your gem's version:
|
4
|
+
require "voter_love/version"
|
5
|
+
|
6
|
+
# Describe your gem and declare its dependencies:
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "voter_love"
|
9
|
+
s.version = VoterLove::VERSION
|
10
|
+
s.authors = ["Karl Gusner"]
|
11
|
+
s.email = ["karlgusner@gmail.com"]
|
12
|
+
s.homepage = "https://github.com/ramz15/voter_love"
|
13
|
+
s.summary = "An easy to use voting gem for Rails 3"
|
14
|
+
s.description = "The voter_love Gem allows users to easily vote on objects"
|
15
|
+
|
16
|
+
s.files = Dir["{app,config,db,lib}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.rdoc"]
|
17
|
+
s.test_files = Dir["test/**/*"]
|
18
|
+
|
19
|
+
s.add_dependency "rails", "~> 3.1.0"
|
20
|
+
|
21
|
+
s.add_development_dependency "sqlite3"
|
22
|
+
s.add_development_dependency "rspec", "~> 2.5.0"
|
23
|
+
s.add_development_dependency "generator_spec", "~> 0.8.2"
|
24
|
+
|
25
|
+
s.files = `git ls-files`.split("\n")
|
26
|
+
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
|
27
|
+
s.require_path = 'lib'
|
28
|
+
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: voter_love
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Karl Gusner
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-18 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: &2157386880 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.1.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2157386880
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: sqlite3
|
27
|
+
requirement: &2157386460 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2157386460
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &2157423020 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.5.0
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2157423020
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: generator_spec
|
49
|
+
requirement: &2157422520 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.8.2
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2157422520
|
58
|
+
description: The voter_love Gem allows users to easily vote on objects
|
59
|
+
email:
|
60
|
+
- karlgusner@gmail.com
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- .gitignore
|
66
|
+
- Gemfile
|
67
|
+
- Gemfile.lock
|
68
|
+
- MIT-LICENSE
|
69
|
+
- README.rdoc
|
70
|
+
- Rakefile
|
71
|
+
- lib/generators/voter_love/templates/migration.rb
|
72
|
+
- lib/generators/voter_love/voter_love_generator.rb
|
73
|
+
- lib/tasks/voter_love_tasks.rake
|
74
|
+
- lib/voter_love.rb
|
75
|
+
- lib/voter_love/exceptions.rb
|
76
|
+
- lib/voter_love/version.rb
|
77
|
+
- lib/voter_love/votable.rb
|
78
|
+
- lib/voter_love/voter.rb
|
79
|
+
- lib/voter_love/votes.rb
|
80
|
+
- spec/database.yml
|
81
|
+
- spec/database.yml.sample
|
82
|
+
- spec/generators/voter_love_generator_spec.rb
|
83
|
+
- spec/lib/voter_love_spec.rb
|
84
|
+
- spec/models.rb
|
85
|
+
- spec/schema.rb
|
86
|
+
- spec/spec_helper.rb
|
87
|
+
- voter_love.gemspec
|
88
|
+
homepage: https://github.com/ramz15/voter_love
|
89
|
+
licenses: []
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options: []
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ! '>='
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ! '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
requirements: []
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 1.8.11
|
109
|
+
signing_key:
|
110
|
+
specification_version: 3
|
111
|
+
summary: An easy to use voting gem for Rails 3
|
112
|
+
test_files: []
|