make_voteable 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 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
+