jy-acts_as_votable 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
4
+ nbproject/*
5
+ bin
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in acts_as_votable.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,103 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ acts_as_votable (0.3.0)
5
+ rails (>= 3.0.0)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ actionmailer (3.2.3)
11
+ actionpack (= 3.2.3)
12
+ mail (~> 2.4.4)
13
+ actionpack (3.2.3)
14
+ activemodel (= 3.2.3)
15
+ activesupport (= 3.2.3)
16
+ builder (~> 3.0.0)
17
+ erubis (~> 2.7.0)
18
+ journey (~> 1.0.1)
19
+ rack (~> 1.4.0)
20
+ rack-cache (~> 1.2)
21
+ rack-test (~> 0.6.1)
22
+ sprockets (~> 2.1.2)
23
+ activemodel (3.2.3)
24
+ activesupport (= 3.2.3)
25
+ builder (~> 3.0.0)
26
+ activerecord (3.2.3)
27
+ activemodel (= 3.2.3)
28
+ activesupport (= 3.2.3)
29
+ arel (~> 3.0.2)
30
+ tzinfo (~> 0.3.29)
31
+ activeresource (3.2.3)
32
+ activemodel (= 3.2.3)
33
+ activesupport (= 3.2.3)
34
+ activesupport (3.2.3)
35
+ i18n (~> 0.6)
36
+ multi_json (~> 1.0)
37
+ arel (3.0.2)
38
+ builder (3.0.0)
39
+ diff-lcs (1.1.3)
40
+ erubis (2.7.0)
41
+ hike (1.2.1)
42
+ i18n (0.6.0)
43
+ journey (1.0.3)
44
+ json (1.6.6)
45
+ mail (2.4.4)
46
+ i18n (>= 0.4.0)
47
+ mime-types (~> 1.16)
48
+ treetop (~> 1.4.8)
49
+ mime-types (1.18)
50
+ multi_json (1.2.0)
51
+ polyglot (0.3.3)
52
+ rack (1.4.1)
53
+ rack-cache (1.2)
54
+ rack (>= 0.4)
55
+ rack-ssl (1.3.2)
56
+ rack
57
+ rack-test (0.6.1)
58
+ rack (>= 1.0)
59
+ rails (3.2.3)
60
+ actionmailer (= 3.2.3)
61
+ actionpack (= 3.2.3)
62
+ activerecord (= 3.2.3)
63
+ activeresource (= 3.2.3)
64
+ activesupport (= 3.2.3)
65
+ bundler (~> 1.0)
66
+ railties (= 3.2.3)
67
+ railties (3.2.3)
68
+ actionpack (= 3.2.3)
69
+ activesupport (= 3.2.3)
70
+ rack-ssl (~> 1.3.2)
71
+ rake (>= 0.8.7)
72
+ rdoc (~> 3.4)
73
+ thor (~> 0.14.6)
74
+ rake (0.9.2.2)
75
+ rdoc (3.12)
76
+ json (~> 1.4)
77
+ rspec (2.9.0)
78
+ rspec-core (~> 2.9.0)
79
+ rspec-expectations (~> 2.9.0)
80
+ rspec-mocks (~> 2.9.0)
81
+ rspec-core (2.9.0)
82
+ rspec-expectations (2.9.1)
83
+ diff-lcs (~> 1.1.3)
84
+ rspec-mocks (2.9.0)
85
+ sprockets (2.1.2)
86
+ hike (~> 1.2)
87
+ rack (~> 1.0)
88
+ tilt (~> 1.1, != 1.3.0)
89
+ sqlite3 (1.3.5)
90
+ thor (0.14.6)
91
+ tilt (1.3.3)
92
+ treetop (1.4.10)
93
+ polyglot
94
+ polyglot (>= 0.3.1)
95
+ tzinfo (0.3.33)
96
+
97
+ PLATFORMS
98
+ ruby
99
+
100
+ DEPENDENCIES
101
+ acts_as_votable!
102
+ rspec
103
+ sqlite3
data/README.markdown ADDED
@@ -0,0 +1,227 @@
1
+ # Acts As Votable (aka Acts As Likeable)
2
+
3
+ Acts As Votable is a Ruby Gem specifically written for Rails/ActiveRecord models.
4
+ The main goals of this gem are:
5
+
6
+ - Allow any model to be voted on, like/dislike, upvote/downvote, etc.
7
+ - Allow any model to vote. In other words, votes do not have to come from a user,
8
+ they can come from any model (such as a Group or Team).
9
+ - Provide an easy to write/read syntax.
10
+
11
+ ## Installation
12
+
13
+ ### Rails 3
14
+
15
+ Just add the following to your Gemfile.
16
+
17
+ gem 'acts_as_votable'
18
+
19
+ And follow that up with a ``bundle install``.
20
+
21
+ ### Database Migrations
22
+
23
+ Acts As Votable uses a votes table to store all voting information. To
24
+ generate and run the migration just use.
25
+
26
+ rails generate acts_as_votable:migration
27
+ rake db:migrate
28
+
29
+ You will get a performance increase by adding in cached columns to your model's
30
+ tables. You will have to do this manually through your own migrations. See the
31
+ caching section of this document for more information.
32
+
33
+ ## Usage
34
+
35
+ ### Votable Models
36
+
37
+ class Post < ActiveRecord::Base
38
+ acts_as_votable
39
+ end
40
+
41
+ @post = Post.new(:name => 'my post!')
42
+ @post.save
43
+
44
+ @post.liked_by @user
45
+ @post.votes.size # => 1
46
+
47
+ ### Like/Dislike Yes/No Up/Down
48
+
49
+ Here are some voting examples. All of these calls are valid and acceptable. The
50
+ more natural calls are the first few examples.
51
+
52
+ @post.liked_by @user1
53
+ @post.downvote_from @user2
54
+ @post.vote :voter => @user3
55
+ @post.vote :voter => @user4, :vote => 'bad'
56
+ @post.vote :voter => @user5, :vote => 'like'
57
+
58
+
59
+ By default all votes are positive, so @user3 has cast a 'good' vote for @post.
60
+
61
+ @user1, @user3, and @user5 all voted in favor of @post.
62
+
63
+ @user2 and @user4 on the other had has voted against @post.
64
+
65
+
66
+ Just about any word works for casting a vote in favor or against post. Up/Down,
67
+ Like/Dislike, Positive/Negative... the list goes on-and-on. Boolean flags ``true`` and
68
+ ``false`` are also applicable.
69
+
70
+ Revisiting the previous example of code.
71
+
72
+ # positive votes
73
+ @post.liked_by @user1
74
+ @post.vote :voter => @user3
75
+ @post.vote :voter => @user5, :vote => 'like'
76
+
77
+ # negative votes
78
+ @post.downvote_from @user2
79
+ @post.vote :voter => @user2, :vote => 'bad'
80
+
81
+ # tally them up!
82
+ @post.votes.size # => 5
83
+ @post.likes.size # => 3
84
+ @post.upvotes.size # => 3
85
+ @post.dislikes.size # => 2
86
+ @post.downvotes.size # => 2
87
+
88
+ Active Record scopes are provided to make life easier.
89
+
90
+ @post.votes.up.by_type(User)
91
+ @post.votes.down
92
+ @user1.votes.up
93
+ @user1.votes.down
94
+ @user1.votes.up.by_type(Post)
95
+
96
+ Once scoping is complete, you can also trigger a get for the
97
+ voter/votable
98
+
99
+ @post.votes.up.by_type(User).voters
100
+ @post.votes.down.by_type(User).voters
101
+
102
+ @user.votes.up.for_type(Post).votables
103
+ @user.votes.up.votables
104
+
105
+ You can also 'unvote' a model to remove a previous vote.
106
+
107
+ @post.liked_by @user1
108
+ @post.unlike_by @user1
109
+
110
+ @post.disliked_by @user1
111
+ @post.undisliked_by @user1
112
+
113
+ Unvoting works for both positive and negative votes.
114
+
115
+ ### The Voter
116
+
117
+ You can have your voters ``acts_as_voter`` to provide some reserve functionality.
118
+
119
+ class User < ActiveRecord::Base
120
+ acts_as_voter
121
+ end
122
+
123
+ @user.likes @article
124
+
125
+ @article.votes.size # => 1
126
+ @article.likes.size # => 1
127
+ @article.dislikes.size # => 0
128
+
129
+ To check if a voter has voted on a model, you can use ``voted_for?``. You can
130
+ check how the voter voted by using ``voted_as_when_voted_for``.
131
+
132
+ @user.likes @comment1
133
+ @user.up_votes @comment2
134
+ # user has not voted on @comment3
135
+
136
+ @user.voted_for? @comment1 # => true
137
+ @user.voted_for? @comment2 # => true
138
+ @user.voted_for? @comment3 # => false
139
+
140
+ @user.voted_as_when_voted_for @comment1 # => true, he liked it
141
+ @user.voted_as_when_voted_for @comment2 # => false, he didnt like it
142
+ @user.voted_as_when_voted_for @comment3 # => nil, he has yet to vote
143
+
144
+ You can also check whether the voter has voted up or down.
145
+
146
+ @user.likes @comment1
147
+ @user.dislikes @comment2
148
+ # user has not voted on @comment3
149
+
150
+ @user.voted_up_on? @comment1 # => true
151
+ @user.voted_down_on? @comment1 # => false
152
+
153
+ @user.voted_down_on? @comment2 # => true
154
+ @user.voted_up_on? @comment2 # => false
155
+
156
+ @user.voted_up_on? @comment3 # => false
157
+ @user.voted_down_on? @comment3 # => false
158
+
159
+ ### Registered Votes
160
+
161
+ Voters can only vote once per model. In this example the 2nd vote does not count
162
+ because @user has already voted for @shoe.
163
+
164
+ @user.likes @shoe
165
+ @user.likes @shoe
166
+
167
+ @shoe.votes # => 1
168
+ @shoe.likes # => 1
169
+
170
+ To check if a vote counted, or registered, use vote_registered? on your model
171
+ after voting. For example:
172
+
173
+ @hat.liked_by @user
174
+ @hat.vote_registered? # => true
175
+
176
+ @hat.liked_by => @user
177
+ @hat.vote_registered? # => false, because @user has already voted this way
178
+
179
+ @hat.disliked_by @user
180
+ @hat.vote_registered? # => true, because user changed their vote
181
+
182
+ @hat.votes.size # => 1
183
+ @hat.positives.size # => 0
184
+ @hat.negatives.size # => 1
185
+
186
+ ## Caching
187
+
188
+ To speed up perform you can add cache columns to your votable model's table. These
189
+ columns will automatically be updated after each vote. For example, if we wanted
190
+ to speed up @post we would use the following migration:
191
+
192
+ class AddCachedVotesToPosts < ActiveRecord::Migration
193
+ def self.up
194
+ add_column :posts, :cached_votes_total, :integer, :default => 0
195
+ add_column :posts, :cached_votes_up, :integer, :default => 0
196
+ add_column :posts, :cached_votes_down, :integer, :default => 0
197
+ add_index :posts, :cached_votes_total
198
+ add_index :posts, :cached_votes_up
199
+ add_index :posts, :cached_votes_down
200
+ end
201
+
202
+ def self.down
203
+ remove_column :posts, :cached_votes_total
204
+ remove_column :posts, :cached_votes_up
205
+ remove_column :posts, :cached_votes_down
206
+ end
207
+ end
208
+
209
+ ## Testing
210
+
211
+ All tests follow the RSpec format and are located in the spec directory
212
+
213
+ ## TODO
214
+
215
+ - Pass in a block of options when creating acts_as. Allow for things
216
+ like disabling the aliasing
217
+
218
+ - Smarter language syntax. Example: ``@user.likes`` will return all of the votables
219
+ that the user likes, while ``@user.likes @model`` will cast a vote for @model by
220
+ @user.
221
+
222
+ - Need to test a model that is votable as well as a voter
223
+
224
+ - The aliased methods are referred to by using the terms 'up/down' and/or
225
+ 'true/false'. Need to come up with guidelines for naming these methods.
226
+
227
+ - Create more aliases. Specifically for counting votes and finding votes.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "acts_as_votable/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "jy-acts_as_votable"
7
+ s.version = ActsAsVotable::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Ryan"]
10
+ s.email = ["ryanto"]
11
+ s.homepage = "http://rubygems.org/gems/acts_as_votable"
12
+ s.summary = %q{Rails gem to allowing records to be votable}
13
+ s.description = %q{Rails gem to allowing records to be votable}
14
+
15
+ s.rubyforge_project = "acts_as_votable"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+
23
+
24
+ s.add_development_dependency "rspec"
25
+ s.add_development_dependency "sqlite3"
26
+
27
+ s.add_dependency "rails", '>=3.0.0'
28
+
29
+ end
@@ -0,0 +1,16 @@
1
+ require 'active_record'
2
+ require 'active_support/inflector'
3
+
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+
6
+ module ActsAsVotable
7
+
8
+ if defined?(ActiveRecord::Base)
9
+ require 'acts_as_votable/extenders/votable'
10
+ require 'acts_as_votable/extenders/voter'
11
+ require 'acts_as_votable/vote'
12
+ ActiveRecord::Base.extend ActsAsVotable::Extenders::Votable
13
+ ActiveRecord::Base.extend ActsAsVotable::Extenders::Voter
14
+ end
15
+
16
+ end
@@ -0,0 +1,25 @@
1
+ module ActsAsVotable
2
+ module Extenders
3
+
4
+ module Votable
5
+
6
+ def votable?
7
+ false
8
+ end
9
+
10
+ def acts_as_votable
11
+ require 'acts_as_votable/votable'
12
+ include ActsAsVotable::Votable
13
+
14
+ class_eval do
15
+ def self.votable?
16
+ true
17
+ end
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,24 @@
1
+ module ActsAsVotable
2
+ module Extenders
3
+
4
+ module Voter
5
+
6
+ def voter?
7
+ false
8
+ end
9
+
10
+ def acts_as_voter(*args)
11
+ require 'acts_as_votable/voter'
12
+ include ActsAsVotable::Voter
13
+
14
+ class_eval do
15
+ def self.voter?
16
+ true
17
+ end
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+ end
24
+ end