make_voteable 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ Gemfile.lock
2
+ nbproject/*
3
+ pkg/*
4
+ doc/*
5
+ *.gem
6
+ *.log
7
+ *.sqlite3
8
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :gemcutter
2
+
3
+ # Specify your gem's dependencies in make_voteable.gemspec
4
+ gemspec
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010-2011 by Kai Schlamp
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
@@ -0,0 +1,100 @@
1
+ = MakeVoteable
2
+
3
+ MakeVoteable is an extension for building a user-centric voting system for Rails 3 applications.
4
+ It currently supports ActiveRecord models.
5
+
6
+ == Installation
7
+
8
+ add MakeVoteable to your Gemfile
9
+
10
+ gem 'make_voteable'
11
+
12
+ afterwards execute
13
+
14
+ bundle install
15
+
16
+ generate the required migration file
17
+
18
+ rails generate make_voteable
19
+
20
+ also add +up_votes+ and +down_votes+ columns to the voter (e.g. User) and voteable (e.g. Question) model migrations
21
+
22
+ add_column :users, :up_votes, :integer, :null => false, :default => 0
23
+ add_column :users, :down_votes, :integer, :null => false, :default => 0
24
+ add_column :questions, :up_votes, :integer, :null => false, :default => 0
25
+ add_column :questions, :down_votes, :integer, :null => false, :default => 0
26
+
27
+ migrate the database
28
+
29
+ rails db:migrate
30
+
31
+ == Usage
32
+
33
+ # Specify a voteable model.
34
+ class Question < ActiveRecord::Base
35
+ make_voteable
36
+ end
37
+
38
+ # Specify a voter model.
39
+ class User < ActiveRecord::Base
40
+ make_voter
41
+ end
42
+
43
+ # Votes up the question by the user.
44
+ # If the user already voted the question up then an AlreadyVotedError is raised.
45
+ # If the same user already voted the question down then the vote is changed to an up vote.
46
+ user.up_vote(question)
47
+
48
+ # Votes the question up, but without raising an AlreadyVotedError when the user
49
+ # already voted the question up (it just ignores the vote).
50
+ user.up_vote!(question)
51
+
52
+ # Votes down the question by the user.
53
+ # If the user already voted the question down then an AlreadyVotedError is raised.
54
+ # If the same user already voted the question up then the vote is changed to an down vote.
55
+ user.down_vote(question)
56
+
57
+ # Votes the question down, but without raising an AlreadyVotedError when the user
58
+ # already voted the question down (it just ignores the vote).
59
+ user.down_vote!(question)
60
+
61
+ # Clears a already done vote by an user.
62
+ # If the user didn't vote for the question then a NotVotedError is raised.
63
+ user.unvote(question)
64
+
65
+ # Does not raise a NotVotedError if the user didn't vote for the question
66
+ # (it just ignores the unvote).
67
+ user.unvote!(question)
68
+
69
+ # The number of up votes for this question.
70
+ question.up_votes
71
+
72
+ # The number of down votes for this question.
73
+ question.down_votes
74
+
75
+ # The number of up votes the user did.
76
+ user.up_votes
77
+
78
+ # The number of down votes the user did.
79
+ user.down_votes
80
+
81
+ # up votes - down votes (may also be negative if there are more down votes than up votes)
82
+ question.votes
83
+
84
+ # Returns true if the question was voted by the user
85
+ user.voted?(question)
86
+
87
+ # Returns true if the question was up voted by the user, false otherwise
88
+ user.up_voted?(question)
89
+
90
+ # Returns true if the question was down voted by the user, false otherwise
91
+ user.down_voted?(question)
92
+
93
+ == Testing
94
+
95
+ MakeVoteable uses RSpec for testing and has a rake task for executing the provided specs
96
+
97
+ rake spec
98
+
99
+
100
+ Copyright © 2010-2011 Kai Schlamp (http://www.medihack.org), released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,20 @@
1
+ require 'rails/generators/migration'
2
+ require 'rails/generators/active_record'
3
+
4
+ class MakeVoteableGenerator < 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_make_voteable_tables'
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ class CreateMakeVoteableTables < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :votings do |t|
4
+ t.string :voteable_type
5
+ t.integer :voteable_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 :votings, [:voteable_type, :voteable_id]
14
+ add_index :votings, [:voter_type, :voter_id]
15
+ add_index :votings, [:voteable_type, :voteable_id, :voter_type, :voter_id], :name => "unique_voters", :unique => true
16
+ end
17
+
18
+ def self.down
19
+ remove_index :votings, :column => [:voteable_type, :voteable_id]
20
+ remove_index :votings, :column => [:voter_type, :voter_id]
21
+ remove_index :votings, :name => "unique_voters"
22
+
23
+ drop_table :votings
24
+ end
25
+ end
@@ -0,0 +1,36 @@
1
+ require 'make_voteable/voting'
2
+ require 'make_voteable/voteable'
3
+ require 'make_voteable/voter'
4
+ require 'make_voteable/exceptions'
5
+
6
+ module MakeVoteable
7
+ def voteable?
8
+ false
9
+ end
10
+
11
+ def voter?
12
+ false
13
+ end
14
+
15
+ # Specify a model as voteable.
16
+ #
17
+ # Example:
18
+ # class Question < ActiveRecord::Base
19
+ # make_voteable
20
+ # end
21
+ def make_voteable
22
+ include Voteable
23
+ end
24
+
25
+ # Specify a model as voter.
26
+ #
27
+ # Example:
28
+ # class User < ActiveRecord::Base
29
+ # make_voter
30
+ # end
31
+ def make_voter
32
+ include Voter
33
+ end
34
+ end
35
+
36
+ ActiveRecord::Base.extend MakeVoteable
@@ -0,0 +1,33 @@
1
+ module MakeVoteable
2
+ module Exceptions
3
+ class AlreadyVotedError < StandardError
4
+ attr_reader :up_vote
5
+
6
+ def initialize(up_vote)
7
+ @up_vote = up_vote
8
+ end
9
+
10
+ def message
11
+ if @up_vote
12
+ vote = "up voted"
13
+ else
14
+ vote = "down voted"
15
+ end
16
+
17
+ "The voteable was already #{vote} by the voter."
18
+ end
19
+ end
20
+
21
+ class NotVotedError < StandardError
22
+ def message
23
+ "The voteable was not voted by the voter."
24
+ end
25
+ end
26
+
27
+ class InvalidVoteableError < StandardError
28
+ def message
29
+ "Invalid voteable."
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,3 @@
1
+ module MakeVoteable
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,17 @@
1
+ module MakeVoteable
2
+ module Voteable
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def voteable?
7
+ true
8
+ end
9
+ end
10
+
11
+ # Return the difference of down and up votes.
12
+ # May be negative if there are more down than up votes.
13
+ def votes
14
+ self.up_votes - self.down_votes
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,159 @@
1
+ module MakeVoteable
2
+ module Voter
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ def voter?
7
+ true
8
+ end
9
+ end
10
+
11
+ # Up vote a +voteable+.
12
+ # Raises an AlreadyVotedError if the voter already up voted the voteable.
13
+ # Changes a down vote to an up vote if the the voter already down voted the voteable.
14
+ def up_vote(voteable)
15
+ check_voteable(voteable)
16
+
17
+ voting = fetch_voting(voteable)
18
+
19
+ if voting
20
+ if voting.up_vote
21
+ raise MakeVoteable::Exceptions::AlreadyVotedError.new(true)
22
+ else
23
+ voting.up_vote = true
24
+ voteable.down_votes -= 1
25
+ self.down_votes -= 1 if self.has_attribute?(:down_votes)
26
+ end
27
+ else
28
+ voting = Voting.create(:voteable => voteable, :voter => self, :up_vote => true)
29
+ end
30
+
31
+ voteable.up_votes += 1
32
+ self.up_votes += 1 if self.has_attribute?(:up_votes)
33
+
34
+ MakeVoteable::Voting.transaction do
35
+ self.save
36
+ voteable.save
37
+ voting.save
38
+ end
39
+ end
40
+
41
+ # Up votes the +voteable+, but doesn't raise an error if the votelable was already up voted.
42
+ # The vote is simply ignored then.
43
+ def up_vote!(voteable)
44
+ begin
45
+ up_vote(voteable)
46
+ rescue MakeVoteable::Exceptions::AlreadyVotedError
47
+ end
48
+ end
49
+
50
+ # Down vote a +voteable+.
51
+ # Raises an AlreadyVotedError if the voter already down voted the voteable.
52
+ # Changes an up vote to a down vote if the the voter already up voted the voteable.
53
+ def down_vote(voteable)
54
+ check_voteable(voteable)
55
+
56
+ voting = fetch_voting(voteable)
57
+
58
+ if voting
59
+ unless voting.up_vote
60
+ raise MakeVoteable::Exceptions::AlreadyVotedError.new(false)
61
+ else
62
+ voting.up_vote = false
63
+ voteable.up_votes -= 1
64
+ self.up_votes -= 1 if self.has_attribute?(:up_votes)
65
+ end
66
+ else
67
+ voting = Voting.create(:voteable => voteable, :voter => self, :up_vote => false)
68
+ end
69
+
70
+ voteable.down_votes += 1
71
+ self.down_votes += 1 if self.has_attribute?(:down_votes)
72
+
73
+ MakeVoteable::Voting.transaction do
74
+ self.save
75
+ voteable.save
76
+ voting.save
77
+ end
78
+ end
79
+
80
+ # Down votes the +voteable+, but doesn't raise an error if the votelable was already down voted.
81
+ # The vote is simply ignored then.
82
+ def down_vote!(voteable)
83
+ begin
84
+ down_vote(voteable)
85
+ rescue MakeVoteable::Exceptions::AlreadyVotedError
86
+ end
87
+ end
88
+
89
+ # Clears an already done vote on a +voteable+.
90
+ # Raises a NotVotedError if the voter didn't voted for the voteable.
91
+ def unvote(voteable)
92
+ check_voteable(voteable)
93
+
94
+ voting = fetch_voting(voteable)
95
+
96
+ raise MakeVoteable::Exceptions::NotVotedError unless voting
97
+
98
+ if voting.up_vote
99
+ voteable.up_votes -= 1
100
+ self.up_votes -= 1 if self.has_attribute?(:up_votes)
101
+ else
102
+ voteable.down_votes -= 1
103
+ self.down_votes -= 1 if self.has_attribute?(:down_votes)
104
+ end
105
+
106
+ MakeVoteable::Voting.transaction do
107
+ self.save
108
+ voteable.save
109
+ voting.destroy
110
+ end
111
+ end
112
+
113
+ # Clears an already done vote on a +voteable+, but doesn't raise an error if
114
+ # the voteable was not voted. It ignores the unvote then.
115
+ def unvote!(voteable)
116
+ begin
117
+ unvote(voteable)
118
+ rescue MakeVoteable::Exceptions::NotVotedError
119
+ end
120
+ end
121
+
122
+ # Returns true if the voter voted for the +voteable+.
123
+ def voted?(voteable)
124
+ check_voteable(voteable)
125
+ voting = fetch_voting(voteable)
126
+ !voting.nil?
127
+ end
128
+
129
+ # Returns true if the voter up voted the +voteable+.
130
+ def up_voted?(voteable)
131
+ check_voteable(voteable)
132
+ voting = fetch_voting(voteable)
133
+ return true if voting.has_attribute?(:up_vote) && voting.up_vote
134
+ false
135
+ end
136
+
137
+ # Returns true if the voter down voted the +voteable+.
138
+ def down_voted?(voteable)
139
+ check_voteable(voteable)
140
+ voting = fetch_voting(voteable)
141
+ return true if voting.has_attribute?(:up_vote) && !voting.up_vote
142
+ false
143
+ end
144
+
145
+ private
146
+
147
+ def fetch_voting(voteable)
148
+ Voting.where(
149
+ :voteable_type => voteable.class.to_s,
150
+ :voteable_id => voteable.id,
151
+ :voter_type => self.class.to_s,
152
+ :voter_id => self.id).try(:first)
153
+ end
154
+
155
+ def check_voteable(voteable)
156
+ raise MakeVoteable::Exceptions::InvalidVoteableError unless voteable.class.voteable?
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,8 @@
1
+ module MakeVoteable
2
+ class Voting < ActiveRecord::Base
3
+ attr_accessible :voteable, :voter, :up_vote
4
+
5
+ belongs_to :voteable, :polymorphic => true
6
+ belongs_to :voter, :polymorphic => true
7
+ end
8
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path("../lib/make_voteable/version", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "make_voteable"
6
+ s.version = MakeVoteable::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["Kai Schlamp"]
9
+ s.email = ["schlamp@gmx.de"]
10
+ s.homepage = "http://github.com/medihack/make_voteable"
11
+ s.summary = "Rails 3 voting extension"
12
+ s.description = "A user-centric voting extension for Rails 3 applications."
13
+
14
+ s.required_rubygems_version = ">= 1.3.6"
15
+ s.rubyforge_project = "make_voteable"
16
+
17
+ s.add_dependency "activerecord", ">= 3.0.0"
18
+ s.add_development_dependency "bundler", ">= 1.0.0"
19
+ s.add_development_dependency "rspec", ">= 2.0.0"
20
+ s.add_development_dependency "database_cleaner", "0.5.2"
21
+ s.add_development_dependency "sqlite3-ruby", ">= 1.3.0"
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
25
+ s.require_path = 'lib'
26
+ end
data/spec/database.yml ADDED
@@ -0,0 +1,3 @@
1
+ sqlite3:
2
+ adapter: sqlite3
3
+ database: make_voteable.sqlite3
@@ -0,0 +1,3 @@
1
+ sqlite3:
2
+ adapter: sqlite3
3
+ database: make_voteable.sqlite3
@@ -0,0 +1,202 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe "Make Voteable" do
4
+ before(:each) do
5
+ @voteable = VoteableModel.create(:name => "Votable 1")
6
+ @voter = VoterModel.create(:name => "Voter 1")
7
+ end
8
+
9
+ it "should create a voteable instance" do
10
+ @voteable.class.should == VoteableModel
11
+ @voteable.class.voteable?.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(@voteable)
21
+ @voteable.votes.should == 1
22
+ @voter.down_vote(@voteable)
23
+ @voteable.votes.should == -1
24
+ @voter.unvote(@voteable)
25
+ @voteable.votes.should == 0
26
+ end
27
+
28
+ describe "up vote" do
29
+ it "should increase up votes of voteable by one" do
30
+ @voteable.up_votes.should == 0
31
+ @voter.up_vote(@voteable)
32
+ @voteable.up_votes.should == 1
33
+ end
34
+
35
+ it "should increase up votes of voter by one" do
36
+ @voter.up_votes.should == 0
37
+ @voter.up_vote(@voteable)
38
+ @voter.up_votes.should == 1
39
+ end
40
+
41
+ it "should create a voting" do
42
+ MakeVoteable::Voting.count.should == 0
43
+ @voter.up_vote(@voteable)
44
+ MakeVoteable::Voting.count.should == 1
45
+ voting = MakeVoteable::Voting.first
46
+ voting.voteable.should == @voteable
47
+ voting.voter.should == @voter
48
+ voting.up_vote.should == true
49
+ end
50
+
51
+ it "should only allow a voter to up vote a voteable once" do
52
+ @voter.up_vote(@voteable)
53
+ lambda { @voter.up_vote(@voteable) }.should raise_error(MakeVoteable::Exceptions::AlreadyVotedError)
54
+ end
55
+
56
+ it "should only allow a voter to up vote a voteable once without raising an error" do
57
+ @voter.up_vote!(@voteable)
58
+ lambda { @voter.up_vote!(@voteable) }.should_not raise_error(MakeVoteable::Exceptions::AlreadyVotedError)
59
+ MakeVoteable::Voting.count.should == 1
60
+ end
61
+
62
+ it "should change a down vote to an up vote" do
63
+ @voter.down_vote(@voteable)
64
+ @voteable.up_votes.should == 0
65
+ @voteable.down_votes.should == 1
66
+ @voter.up_votes.should == 0
67
+ @voter.down_votes.should == 1
68
+ MakeVoteable::Voting.count.should == 1
69
+ MakeVoteable::Voting.first.up_vote.should be_false
70
+ @voter.up_vote(@voteable)
71
+ @voteable.up_votes.should == 1
72
+ @voteable.down_votes.should == 0
73
+ @voter.up_votes.should == 1
74
+ @voter.down_votes.should == 0
75
+ MakeVoteable::Voting.count.should == 1
76
+ MakeVoteable::Voting.first.up_vote.should be_true
77
+ end
78
+
79
+ it "should allow up votes from different voters" do
80
+ @voter2 = VoterModel.create(:name => "Voter 2")
81
+ @voter.up_vote(@voteable)
82
+ @voter2.up_vote(@voteable)
83
+ @voteable.up_votes.should == 2
84
+ MakeVoteable::Voting.count.should == 2
85
+ end
86
+
87
+ it "should raise an error for an invalid voteable" do
88
+ invalid_voteable = InvalidVoteableModel.create
89
+ lambda { @voter.up_vote(invalid_voteable) }.should raise_error(MakeVoteable::Exceptions::InvalidVoteableError)
90
+ end
91
+
92
+ it "should check if voter up voted voteable" do
93
+ @voter.up_vote(@voteable)
94
+ @voter.voted?(@voteable).should be_true
95
+ @voter.up_voted?(@voteable).should be_true
96
+ @voter.down_voted?(@voteable).should be_false
97
+ end
98
+ end
99
+
100
+ describe "vote down" do
101
+ it "should decrease down votes of voteable by one" do
102
+ @voteable.down_votes.should == 0
103
+ @voter.down_vote(@voteable)
104
+ @voteable.down_votes.should == 1
105
+ end
106
+
107
+ it "should decrease down votes of voter by one" do
108
+ @voter.down_votes.should == 0
109
+ @voter.down_vote(@voteable)
110
+ @voter.down_votes.should == 1
111
+ end
112
+
113
+ it "should create a voting" do
114
+ MakeVoteable::Voting.count.should == 0
115
+ @voter.down_vote(@voteable)
116
+ MakeVoteable::Voting.count.should == 1
117
+ voting = MakeVoteable::Voting.first
118
+ voting.voteable.should == @voteable
119
+ voting.voter.should == @voter
120
+ voting.up_vote.should == false
121
+ end
122
+
123
+ it "should only allow a voter to down vote a voteable once" do
124
+ @voter.down_vote(@voteable)
125
+ lambda { @voter.down_vote(@voteable) }.should raise_error(MakeVoteable::Exceptions::AlreadyVotedError)
126
+ end
127
+
128
+ it "should only allow a voter to down vote a voteable once without raising an error" do
129
+ @voter.down_vote!(@voteable)
130
+ lambda { @voter.down_vote!(@voteable) }.should_not raise_error(MakeVoteable::Exceptions::AlreadyVotedError)
131
+ MakeVoteable::Voting.count.should == 1
132
+ end
133
+
134
+ it "should change an up vote to a down vote" do
135
+ @voter.up_vote(@voteable)
136
+ @voteable.up_votes.should == 1
137
+ @voteable.down_votes.should == 0
138
+ @voter.up_votes.should == 1
139
+ @voter.down_votes.should == 0
140
+ MakeVoteable::Voting.count.should == 1
141
+ MakeVoteable::Voting.first.up_vote.should be_true
142
+ @voter.down_vote(@voteable)
143
+ @voteable.up_votes.should == 0
144
+ @voteable.down_votes.should == 1
145
+ @voter.up_votes.should == 0
146
+ @voter.down_votes.should == 1
147
+ MakeVoteable::Voting.count.should == 1
148
+ MakeVoteable::Voting.first.up_vote.should be_false
149
+ end
150
+
151
+ it "should allow down votes from different voters" do
152
+ @voter2 = VoterModel.create(:name => "Voter 2")
153
+ @voter.down_vote(@voteable)
154
+ @voter2.down_vote(@voteable)
155
+ @voteable.down_votes.should == 2
156
+ MakeVoteable::Voting.count.should == 2
157
+ end
158
+
159
+ it "should raise an error for an invalid voteable" do
160
+ invalid_voteable = InvalidVoteableModel.create
161
+ lambda { @voter.down_vote(invalid_voteable) }.should raise_error(MakeVoteable::Exceptions::InvalidVoteableError)
162
+ end
163
+
164
+ it "should check if voter down voted voteable" do
165
+ @voter.down_vote(@voteable)
166
+ @voter.voted?(@voteable).should be_true
167
+ @voter.up_voted?(@voteable).should be_false
168
+ @voter.down_voted?(@voteable).should be_true
169
+ end
170
+ end
171
+
172
+ describe "unvote" do
173
+ it "should decrease the up votes if up voted before" do
174
+ @voter.up_vote(@voteable)
175
+ @voteable.up_votes.should == 1
176
+ @voter.up_votes.should == 1
177
+ @voter.unvote(@voteable)
178
+ @voteable.up_votes.should == 0
179
+ @voter.up_votes.should == 0
180
+ end
181
+
182
+ it "should remove the voting" do
183
+ @voter.up_vote(@voteable)
184
+ MakeVoteable::Voting.count.should == 1
185
+ @voter.unvote(@voteable)
186
+ MakeVoteable::Voting.count.should == 0
187
+ end
188
+
189
+ it "should raise an error if voter didn't vote for the voteable" do
190
+ lambda { @voter.unvote(@voteable) }.should raise_error(MakeVoteable::Exceptions::NotVotedError)
191
+ end
192
+
193
+ it "should not raise error if voter didn't vote for the voteable and unvote! is called" do
194
+ lambda { @voter.unvote!(@voteable) }.should_not raise_error(MakeVoteable::Exceptions::NotVotedError)
195
+ end
196
+
197
+ it "should raise an error for an invalid voteable" do
198
+ invalid_voteable = InvalidVoteableModel.create
199
+ lambda { @voter.unvote(invalid_voteable) }.should raise_error(MakeVoteable::Exceptions::InvalidVoteableError)
200
+ end
201
+ end
202
+ end
data/spec/models.rb ADDED
@@ -0,0 +1,10 @@
1
+ class VoteableModel < ActiveRecord::Base
2
+ make_voteable
3
+ end
4
+
5
+ class VoterModel < ActiveRecord::Base
6
+ make_voter
7
+ end
8
+
9
+ class InvalidVoteableModel < ActiveRecord::Base
10
+ end
data/spec/schema.rb ADDED
@@ -0,0 +1,31 @@
1
+ ActiveRecord::Schema.define :version => 0 do
2
+ create_table :voteable_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_voteable_models, :force => true do |t|
15
+ t.string :name
16
+ end
17
+
18
+ create_table :votings, :force => true do |t|
19
+ t.string :voteable_type
20
+ t.integer :voteable_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 :votings, [:voteable_type, :voteable_id]
29
+ add_index :votings, [:voter_type, :voter_id]
30
+ add_index :votings, [:voteable_type, :voteable_id, :voter_type, :voter_id], :name => "unique_voters", :unique => true
31
+ end
@@ -0,0 +1,41 @@
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 'make_voteable'
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 = :transaction
31
+ DatabaseCleaner.clean_with(:truncation)
32
+ end
33
+
34
+ config.before(:each) do
35
+ DatabaseCleaner.start
36
+ end
37
+
38
+ config.after(:each) do
39
+ DatabaseCleaner.clean
40
+ end
41
+ end
metadata ADDED
@@ -0,0 +1,168 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: make_voteable
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 2
10
+ version: 0.0.2
11
+ platform: ruby
12
+ authors:
13
+ - Kai Schlamp
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-10 00:00:00 +01:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activerecord
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 7
30
+ segments:
31
+ - 3
32
+ - 0
33
+ - 0
34
+ version: 3.0.0
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: bundler
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 23
46
+ segments:
47
+ - 1
48
+ - 0
49
+ - 0
50
+ version: 1.0.0
51
+ type: :development
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: rspec
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 15
62
+ segments:
63
+ - 2
64
+ - 0
65
+ - 0
66
+ version: 2.0.0
67
+ type: :development
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: database_cleaner
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - "="
76
+ - !ruby/object:Gem::Version
77
+ hash: 15
78
+ segments:
79
+ - 0
80
+ - 5
81
+ - 2
82
+ version: 0.5.2
83
+ type: :development
84
+ version_requirements: *id004
85
+ - !ruby/object:Gem::Dependency
86
+ name: sqlite3-ruby
87
+ prerelease: false
88
+ requirement: &id005 !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ hash: 27
94
+ segments:
95
+ - 1
96
+ - 3
97
+ - 0
98
+ version: 1.3.0
99
+ type: :development
100
+ version_requirements: *id005
101
+ description: A user-centric voting extension for Rails 3 applications.
102
+ email:
103
+ - schlamp@gmx.de
104
+ executables: []
105
+
106
+ extensions: []
107
+
108
+ extra_rdoc_files: []
109
+
110
+ files:
111
+ - .gitignore
112
+ - Gemfile
113
+ - MIT-LICENSE
114
+ - README.rdoc
115
+ - Rakefile
116
+ - lib/generators/make_voteable/make_voteable_generator.rb
117
+ - lib/generators/make_voteable/templates/migration.rb
118
+ - lib/make_voteable.rb
119
+ - lib/make_voteable/exceptions.rb
120
+ - lib/make_voteable/version.rb
121
+ - lib/make_voteable/voteable.rb
122
+ - lib/make_voteable/voter.rb
123
+ - lib/make_voteable/voting.rb
124
+ - make_voteable.gemspec
125
+ - spec/database.yml
126
+ - spec/database.yml.sample
127
+ - spec/lib/make_voteable_spec.rb
128
+ - spec/models.rb
129
+ - spec/schema.rb
130
+ - spec/spec_helper.rb
131
+ has_rdoc: true
132
+ homepage: http://github.com/medihack/make_voteable
133
+ licenses: []
134
+
135
+ post_install_message:
136
+ rdoc_options: []
137
+
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ none: false
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ hash: 3
146
+ segments:
147
+ - 0
148
+ version: "0"
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ none: false
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ hash: 23
155
+ segments:
156
+ - 1
157
+ - 3
158
+ - 6
159
+ version: 1.3.6
160
+ requirements: []
161
+
162
+ rubyforge_project: make_voteable
163
+ rubygems_version: 1.4.2
164
+ signing_key:
165
+ specification_version: 3
166
+ summary: Rails 3 voting extension
167
+ test_files: []
168
+