has_ratings 0.3.0
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/CHANGELOG.rdoc +23 -0
- data/LICENSE +20 -0
- data/README.rdoc +60 -0
- data/Rakefile +89 -0
- data/app/models/rating.rb +15 -0
- data/app/models/rating_value.rb +31 -0
- data/assets/images/star.gif +0 -0
- data/assets/stylesheets/star.css +84 -0
- data/db/migrate/001_create_rating_values.rb +12 -0
- data/db/migrate/002_create_ratings.rb +13 -0
- data/init.rb +1 -0
- data/lib/has_ratings.rb +50 -0
- data/test/app_root/app/models/user.rb +2 -0
- data/test/app_root/app/models/video.rb +3 -0
- data/test/app_root/config/environment.rb +12 -0
- data/test/app_root/db/migrate/001_create_users.rb +11 -0
- data/test/app_root/db/migrate/002_create_videos.rb +11 -0
- data/test/app_root/db/migrate/003_migrate_has_ratings_to_version_2.rb +13 -0
- data/test/factory.rb +60 -0
- data/test/functional/has_ratings_test.rb +48 -0
- data/test/test_helper.rb +13 -0
- data/test/unit/rating_test.rb +82 -0
- data/test/unit/rating_value_test.rb +61 -0
- metadata +98 -0
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
== master
|
2
|
+
|
3
|
+
== 0.3.0 / 2009-04-30
|
4
|
+
|
5
|
+
* Replace acts_as_enumeration with enumerate_by
|
6
|
+
* Add dependency on Rails 2.3
|
7
|
+
|
8
|
+
== 0.2.0 / 2008-12-14
|
9
|
+
|
10
|
+
* Remove the PluginAWeek namespace
|
11
|
+
|
12
|
+
== 0.1.0 / 2008-10-26
|
13
|
+
|
14
|
+
* Change how the base module is included to prevent namespacing conflicts
|
15
|
+
* Round to two decimal places for rating averages
|
16
|
+
|
17
|
+
== 0.0.2 / 2008-06-22
|
18
|
+
|
19
|
+
* Remove log files from gems
|
20
|
+
|
21
|
+
== 0.0.1 / 2008-05-09
|
22
|
+
|
23
|
+
* Initial public release
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2006-2009 Aaron Pfeifer
|
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,60 @@
|
|
1
|
+
== has_ratings
|
2
|
+
|
3
|
+
+has_ratings+ demonstrates a reference implementation for handling ratings.
|
4
|
+
|
5
|
+
== Resources
|
6
|
+
|
7
|
+
API
|
8
|
+
|
9
|
+
* http://api.pluginaweek.org/has_ratings
|
10
|
+
|
11
|
+
Bugs
|
12
|
+
|
13
|
+
* http://pluginaweek.lighthouseapp.com/projects/13276-has_ratings
|
14
|
+
|
15
|
+
Development
|
16
|
+
|
17
|
+
* http://github.com/pluginaweek/has_ratings
|
18
|
+
|
19
|
+
Source
|
20
|
+
|
21
|
+
* git://github.com/pluginaweek/has_ratings.git
|
22
|
+
|
23
|
+
== Description
|
24
|
+
|
25
|
+
Storing ratings is a pretty common task when building web applications with a
|
26
|
+
community-based focus. Ratings can have names and values associated with them.
|
27
|
+
This plugin demonstrate a simple way to manage what ratings can be used and
|
28
|
+
how they are persisted.
|
29
|
+
|
30
|
+
== Usage
|
31
|
+
|
32
|
+
Note that this is a reference implementation and, most likely, should be
|
33
|
+
modified for your own usage.
|
34
|
+
|
35
|
+
=== Example
|
36
|
+
|
37
|
+
user = User.find(1)
|
38
|
+
video = Video.find(1)
|
39
|
+
|
40
|
+
video.ratings.create(:rater => user, :value => 'poor')
|
41
|
+
video.ratings.average # => 1.0
|
42
|
+
|
43
|
+
== Assets
|
44
|
+
|
45
|
+
Included with the plugin are image/stylesheet assets for creating raters using
|
46
|
+
css as described at http://www.komodomedia.com/blog/2007/01/css-star-rating-redux
|
47
|
+
|
48
|
+
== Testing
|
49
|
+
|
50
|
+
Before you can run any tests, the following gem must be installed:
|
51
|
+
* plugin_test_helper[http://github.com/pluginaweek/plugin_test_helper]
|
52
|
+
|
53
|
+
To run against a specific version of Rails:
|
54
|
+
|
55
|
+
rake test RAILS_FRAMEWORK_ROOT=/path/to/rails
|
56
|
+
|
57
|
+
== Dependencies
|
58
|
+
|
59
|
+
* Rails 2.3 or later
|
60
|
+
* enumerate_by[http://github.com/pluginaweek/enumerate_by]
|
data/Rakefile
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require 'rake/rdoctask'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'rake/contrib/sshpublisher'
|
5
|
+
|
6
|
+
spec = Gem::Specification.new do |s|
|
7
|
+
s.name = 'has_ratings'
|
8
|
+
s.version = '0.3.0'
|
9
|
+
s.platform = Gem::Platform::RUBY
|
10
|
+
s.summary = 'Demonstrates a reference implementation for handling ratings.'
|
11
|
+
|
12
|
+
s.files = FileList['{app,assets,db,lib,test}/**/*'] + %w(CHANGELOG.rdoc init.rb LICENSE Rakefile README.rdoc) - FileList['test/app_root/{log,log/*,script,script/*}']
|
13
|
+
s.require_path = 'lib'
|
14
|
+
s.has_rdoc = true
|
15
|
+
s.test_files = Dir['test/**/*_test.rb']
|
16
|
+
s.add_dependency 'enumerate_by', '>= 0.4.0'
|
17
|
+
|
18
|
+
s.author = 'Aaron Pfeifer'
|
19
|
+
s.email = 'aaron@pluginaweek.org'
|
20
|
+
s.homepage = 'http://www.pluginaweek.org'
|
21
|
+
s.rubyforge_project = 'pluginaweek'
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Default: run all tests.'
|
25
|
+
task :default => :test
|
26
|
+
|
27
|
+
desc "Test the #{spec.name} plugin."
|
28
|
+
Rake::TestTask.new(:test) do |t|
|
29
|
+
t.libs << 'lib'
|
30
|
+
t.test_files = spec.test_files
|
31
|
+
t.verbose = true
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
namespace :test do
|
37
|
+
desc "Test the #{spec.name} plugin with Rcov."
|
38
|
+
Rcov::RcovTask.new(:rcov) do |t|
|
39
|
+
t.libs << 'lib'
|
40
|
+
t.test_files = spec.test_files
|
41
|
+
t.rcov_opts << '--exclude="^(?!lib/|app/)"'
|
42
|
+
t.verbose = true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
rescue LoadError
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "Generate documentation for the #{spec.name} plugin."
|
49
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
50
|
+
rdoc.rdoc_dir = 'rdoc'
|
51
|
+
rdoc.title = spec.name
|
52
|
+
rdoc.template = '../rdoc_template.rb'
|
53
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
54
|
+
rdoc.rdoc_files.include('README.rdoc', 'CHANGELOG.rdoc', 'LICENSE', 'lib/**/*.rb', 'app/**/*.rb')
|
55
|
+
end
|
56
|
+
|
57
|
+
Rake::GemPackageTask.new(spec) do |p|
|
58
|
+
p.gem_spec = spec
|
59
|
+
p.need_tar = true
|
60
|
+
p.need_zip = true
|
61
|
+
end
|
62
|
+
|
63
|
+
desc 'Publish the beta gem.'
|
64
|
+
task :pgem => [:package] do
|
65
|
+
Rake::SshFilePublisher.new('aaron@pluginaweek.org', '/home/aaron/gems.pluginaweek.org/public/gems', 'pkg', "#{spec.name}-#{spec.version}.gem").upload
|
66
|
+
end
|
67
|
+
|
68
|
+
desc 'Publish the API documentation.'
|
69
|
+
task :pdoc => [:rdoc] do
|
70
|
+
Rake::SshDirPublisher.new('aaron@pluginaweek.org', "/home/aaron/api.pluginaweek.org/public/#{spec.name}", 'rdoc').upload
|
71
|
+
end
|
72
|
+
|
73
|
+
desc 'Publish the API docs and gem'
|
74
|
+
task :publish => [:pgem, :pdoc, :release]
|
75
|
+
|
76
|
+
desc 'Publish the release files to RubyForge.'
|
77
|
+
task :release => [:gem, :package] do
|
78
|
+
require 'rubyforge'
|
79
|
+
|
80
|
+
ruby_forge = RubyForge.new.configure
|
81
|
+
ruby_forge.login
|
82
|
+
|
83
|
+
%w(gem tgz zip).each do |ext|
|
84
|
+
file = "pkg/#{spec.name}-#{spec.version}.#{ext}"
|
85
|
+
puts "Releasing #{File.basename(file)}..."
|
86
|
+
|
87
|
+
ruby_forge.add_release(spec.rubyforge_project, spec.name, spec.version, file)
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# A rating of a particular record. Ratings consist of three components:
|
2
|
+
# * +rater+ - The person who is actually creating the rating
|
3
|
+
# * +ratable+ - The object which is being rated
|
4
|
+
# * +value+ - The value being assigned to the rating
|
5
|
+
#
|
6
|
+
# *Note* that the value does not represent the actual integer value, but rather
|
7
|
+
# the enumeration record in the RatingValue model.
|
8
|
+
class Rating < ActiveRecord::Base
|
9
|
+
belongs_to :rater, :polymorphic => true
|
10
|
+
belongs_to :ratable, :polymorphic => true
|
11
|
+
belongs_to :value, :class_name => 'RatingValue'
|
12
|
+
|
13
|
+
validates_presence_of :rater_id, :rater_type, :ratable_id, :ratable_type,
|
14
|
+
:value_id
|
15
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# The type of rating that can be assigned. This is an enumeration which
|
2
|
+
# consists of a pre-determined set of possible rating values. Each value has
|
3
|
+
# the following attributes:
|
4
|
+
# * +name+ - The actual name to refer to the value as
|
5
|
+
# * +value+ - The numeric value of the rating (higher is better)
|
6
|
+
#
|
7
|
+
# Values should normally be referred to by name. For example,
|
8
|
+
#
|
9
|
+
# RatingValue['poor'] # => #<RatingValue id: 1, name: "poor", value: 1>
|
10
|
+
# RatingValue['excellent'] # => #<RatingValue id: 5, name: "excellent", value: 5>
|
11
|
+
class RatingValue < ActiveRecord::Base
|
12
|
+
enumerate_by :name
|
13
|
+
|
14
|
+
has_many :ratings, :foreign_key => 'value_id'
|
15
|
+
|
16
|
+
validates_presence_of :value
|
17
|
+
|
18
|
+
# Returns the integer value of the rating
|
19
|
+
def to_i
|
20
|
+
value
|
21
|
+
end
|
22
|
+
|
23
|
+
# Represent the possible values for ratings
|
24
|
+
bootstrap(
|
25
|
+
{:id => 1, :name => 'poor', :value => 1},
|
26
|
+
{:id => 2, :name => 'below_average', :value => 2},
|
27
|
+
{:id => 3, :name => 'average', :value => 3},
|
28
|
+
{:id => 4, :name => 'above_average', :value => 4},
|
29
|
+
{:id => 5, :name => 'excellent', :value => 5}
|
30
|
+
)
|
31
|
+
end
|
Binary file
|
@@ -0,0 +1,84 @@
|
|
1
|
+
.star-rating {
|
2
|
+
position: relative;
|
3
|
+
float: left;
|
4
|
+
width: 150px;
|
5
|
+
height: 25px;
|
6
|
+
margin: 0px;
|
7
|
+
padding: 0px;
|
8
|
+
list-style:none;
|
9
|
+
background: url(../images/star.gif) top left repeat-x;
|
10
|
+
}
|
11
|
+
|
12
|
+
.star-rating li {
|
13
|
+
padding: 0px;
|
14
|
+
margin: 0px;
|
15
|
+
/*\*/
|
16
|
+
float: left;
|
17
|
+
/* */
|
18
|
+
}
|
19
|
+
|
20
|
+
.star-rating li a {
|
21
|
+
position: absolute;
|
22
|
+
display: block;
|
23
|
+
width: 30px;
|
24
|
+
height: 25px;
|
25
|
+
padding: 0px;
|
26
|
+
text-decoration: none;
|
27
|
+
text-indent: -9000px;
|
28
|
+
z-index: 20;
|
29
|
+
}
|
30
|
+
|
31
|
+
.star-rating li a:hover {
|
32
|
+
left: 0px;
|
33
|
+
background: url(../images/star.gif) left bottom;
|
34
|
+
z-index: 2;
|
35
|
+
}
|
36
|
+
|
37
|
+
.star-rating a.star1 {
|
38
|
+
left: 0px;
|
39
|
+
}
|
40
|
+
|
41
|
+
.star-rating a.star1:hover {
|
42
|
+
width: 30px;
|
43
|
+
}
|
44
|
+
|
45
|
+
.star-rating a.star2 {
|
46
|
+
left: 30px;
|
47
|
+
}
|
48
|
+
|
49
|
+
.star-rating a.star2:hover {
|
50
|
+
width: 60px;
|
51
|
+
}
|
52
|
+
|
53
|
+
.star-rating a.star3 {
|
54
|
+
left: 60px;
|
55
|
+
}
|
56
|
+
|
57
|
+
.star-rating a.star3:hover {
|
58
|
+
width: 90px;
|
59
|
+
}
|
60
|
+
|
61
|
+
.star-rating a.star4 {
|
62
|
+
left: 90px;
|
63
|
+
}
|
64
|
+
|
65
|
+
.star-rating a.star4:hover {
|
66
|
+
width: 120px;
|
67
|
+
}
|
68
|
+
|
69
|
+
.star-rating a.star5 {
|
70
|
+
left: 120px;
|
71
|
+
}
|
72
|
+
|
73
|
+
.star-rating a.star5:hover {
|
74
|
+
width: 150px;
|
75
|
+
}
|
76
|
+
|
77
|
+
.star-rating li.current-rating {
|
78
|
+
position: absolute;
|
79
|
+
display: block;
|
80
|
+
height: 25px;
|
81
|
+
background: url(../images/star.gif) left center;
|
82
|
+
text-indent: -9000px;
|
83
|
+
z-index: 1;
|
84
|
+
}
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class CreateRatings < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :ratings do |t|
|
4
|
+
t.references :ratable, :rater, :polymorphic => true, :null => false
|
5
|
+
t.references :value, :null => false
|
6
|
+
t.timestamps
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.down
|
11
|
+
drop_table :ratings
|
12
|
+
end
|
13
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'has_ratings'
|
data/lib/has_ratings.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# Adds a generic implementation for dealing with ratings
|
2
|
+
module HasRatings
|
3
|
+
module MacroMethods
|
4
|
+
# Creates the following association:
|
5
|
+
# * +ratings+ - All ratings associated with the current record
|
6
|
+
#
|
7
|
+
# This association assumes that it is being created on the +ratable+
|
8
|
+
# model. If you want to create an association on the +rater+ model,
|
9
|
+
# it will have to be created manually like so:
|
10
|
+
#
|
11
|
+
# has_many :ratings, :as => :rater
|
12
|
+
#
|
13
|
+
# == Creating new ratings
|
14
|
+
#
|
15
|
+
# Creating new ratings is very similar to creating other records within
|
16
|
+
# a has_many association:
|
17
|
+
#
|
18
|
+
# user = User.find(1)
|
19
|
+
#
|
20
|
+
# video = Video.find_by_name('The Shawshank Redemption')
|
21
|
+
# video.ratings.create(:rater => user, :value => 'excellent')
|
22
|
+
# video.ratings.average # => 5
|
23
|
+
def has_ratings
|
24
|
+
has_many :ratings, :as => :ratable, :extend => RatingExtension
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module RatingExtension
|
29
|
+
# Gets the average of all the ratings, up to a precision of 2 decimals.
|
30
|
+
# If no ratings have ever been made, then 0.0 is returned.
|
31
|
+
#
|
32
|
+
# For example,
|
33
|
+
#
|
34
|
+
# video = Video.find_by_name('The Shawshank Redemption')
|
35
|
+
# video.ratings.map {|rating| rating.value.to_i} # => [4, 5, 5]
|
36
|
+
# video.ratings.average # => 4.67
|
37
|
+
def average
|
38
|
+
if empty?
|
39
|
+
0.0
|
40
|
+
else
|
41
|
+
average = inject(0) {|total, rating| total += rating.value.to_i} / size.to_f
|
42
|
+
average.round(2)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
ActiveRecord::Base.class_eval do
|
49
|
+
extend HasRatings::MacroMethods
|
50
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'config/boot'
|
2
|
+
|
3
|
+
Rails::Initializer.run do |config|
|
4
|
+
config.plugin_paths << '..'
|
5
|
+
config.plugins = %w(enumerate_by has_ratings)
|
6
|
+
config.cache_classes = false
|
7
|
+
config.whiny_nils = true
|
8
|
+
config.action_controller.session = {:key => 'rails_session', :secret => 'd229e4d22437432705ab3985d4d246'}
|
9
|
+
config.after_initialize do
|
10
|
+
EnumerateBy.perform_caching = false
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class MigrateHasRatingsToVersion2 < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
ActiveRecord::Migrator.new(:up, "#{Rails.root}/../../db/migrate", 0).migrations.each do |migration|
|
4
|
+
migration.migrate(:up)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.down
|
9
|
+
ActiveRecord::Migrator.new(:up, "#{Rails.root}/../../db/migrate", 0).migrations.each do |migration|
|
10
|
+
migration.migrate(:down)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/test/factory.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
module Factory
|
2
|
+
# Build actions for the model
|
3
|
+
def self.build(model, &block)
|
4
|
+
name = model.to_s.underscore
|
5
|
+
|
6
|
+
define_method("#{name}_attributes", block)
|
7
|
+
define_method("valid_#{name}_attributes") {|*args| valid_attributes_for(model, *args)}
|
8
|
+
define_method("new_#{name}") {|*args| new_record(model, *args)}
|
9
|
+
define_method("create_#{name}") {|*args| create_record(model, *args)}
|
10
|
+
end
|
11
|
+
|
12
|
+
# Get valid attributes for the model
|
13
|
+
def valid_attributes_for(model, attributes = {})
|
14
|
+
name = model.to_s.underscore
|
15
|
+
send("#{name}_attributes", attributes)
|
16
|
+
attributes.stringify_keys!
|
17
|
+
attributes
|
18
|
+
end
|
19
|
+
|
20
|
+
# Build an unsaved record
|
21
|
+
def new_record(model, *args)
|
22
|
+
attributes = valid_attributes_for(model, *args)
|
23
|
+
record = model.new(attributes)
|
24
|
+
attributes.each {|attr, value| record.send("#{attr}=", value) if model.accessible_attributes && !model.accessible_attributes.include?(attr) || model.protected_attributes && model.protected_attributes.include?(attr)}
|
25
|
+
record
|
26
|
+
end
|
27
|
+
|
28
|
+
# Build and save/reload a record
|
29
|
+
def create_record(model, *args)
|
30
|
+
record = new_record(model, *args)
|
31
|
+
record.save!
|
32
|
+
record.reload
|
33
|
+
record
|
34
|
+
end
|
35
|
+
|
36
|
+
build Rating do |attributes|
|
37
|
+
attributes[:ratable] = create_video unless attributes.include?(:ratable)
|
38
|
+
attributes[:rater] = create_user unless attributes.include?(:rater)
|
39
|
+
attributes[:value] = create_rating_value unless attributes.include?(:value)
|
40
|
+
end
|
41
|
+
|
42
|
+
build RatingValue do |attributes|
|
43
|
+
attributes.reverse_merge!(
|
44
|
+
:name => 'awesome',
|
45
|
+
:value => 10
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
build User do |attributes|
|
50
|
+
attributes.reverse_merge!(
|
51
|
+
:login => 'admin'
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
build Video do |attributes|
|
56
|
+
attributes.reverse_merge!(
|
57
|
+
:name => 'Rick Roll'
|
58
|
+
)
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class VideoTest < ActiveRecord::TestCase
|
4
|
+
def setup
|
5
|
+
@video = create_video
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_should_not_have_any_ratings
|
9
|
+
assert @video.ratings.empty?
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_should_have_an_average_of_0
|
13
|
+
assert_equal 0.0, @video.ratings.average
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class VideoWithRatingsTest < ActiveRecord::TestCase
|
18
|
+
def setup
|
19
|
+
@video = create_video
|
20
|
+
|
21
|
+
rater = create_user
|
22
|
+
@poor_rating = create_rating(:rater => rater, :ratable => @video, :value => 'poor')
|
23
|
+
@average_rating = create_rating(:rater => rater, :ratable => @video, :value => 'average')
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_should_have_ratings
|
27
|
+
assert_equal [@poor_rating, @average_rating], @video.ratings
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_should_have_an_average
|
31
|
+
assert_equal 2.0, @video.ratings.average
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class VideoWithRoundedAverageTest < ActiveRecord::TestCase
|
36
|
+
def setup
|
37
|
+
@video = create_video
|
38
|
+
|
39
|
+
rater = create_user
|
40
|
+
create_rating(:rater => rater, :ratable => @video, :value => 'above_average')
|
41
|
+
create_rating(:rater => rater, :ratable => @video, :value => 'excellent')
|
42
|
+
create_rating(:rater => rater, :ratable => @video, :value => 'excellent')
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_should_round_to_two_decimal_places
|
46
|
+
assert_equal 4.67, @video.ratings.average
|
47
|
+
end
|
48
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Load the plugin testing framework
|
2
|
+
$:.unshift("#{File.dirname(__FILE__)}/../../plugin_test_helper/lib")
|
3
|
+
require 'rubygems'
|
4
|
+
require 'plugin_test_helper'
|
5
|
+
|
6
|
+
# Run the migrations
|
7
|
+
ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate")
|
8
|
+
|
9
|
+
# Mixin the factory helper
|
10
|
+
require File.expand_path("#{File.dirname(__FILE__)}/factory")
|
11
|
+
Test::Unit::TestCase.class_eval do
|
12
|
+
include Factory
|
13
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class RatingByDefaultTest < ActiveRecord::TestCase
|
4
|
+
def setup
|
5
|
+
@rating = Rating.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_should_not_have_a_ratable_association
|
9
|
+
assert_nil @rating.ratable_id
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_should_not_have_a_ratable_type
|
13
|
+
assert_nil @rating.ratable_type
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_should_not_have_a_rater
|
17
|
+
assert_nil @rating.rater_id
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_should_not_have_a_rater_type
|
21
|
+
assert_nil @rating.rater_type
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_should_not_have_a_value
|
25
|
+
assert_nil @rating.value_id
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class RatingTest < ActiveRecord::TestCase
|
30
|
+
def test_should_be_valid_with_a_valid_set_of_attributes
|
31
|
+
rating = new_rating
|
32
|
+
assert rating.valid?
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_should_require_a_ratable_association
|
36
|
+
rating = new_rating(:ratable => nil)
|
37
|
+
assert !rating.valid?
|
38
|
+
assert rating.errors.invalid?(:ratable_id)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_should_require_a_ratable_type
|
42
|
+
rating = new_rating(:ratable => nil)
|
43
|
+
assert !rating.valid?
|
44
|
+
assert rating.errors.invalid?(:ratable_type)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_should_require_a_rater
|
48
|
+
rating = new_rating(:rater => nil)
|
49
|
+
assert !rating.valid?
|
50
|
+
assert rating.errors.invalid?(:rater_id)
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_should_require_a_rater_type
|
54
|
+
rating = new_rating(:rater => nil)
|
55
|
+
assert !rating.valid?
|
56
|
+
assert rating.errors.invalid?(:rater_type)
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_should_require_a_value
|
60
|
+
rating = new_rating(:value => nil)
|
61
|
+
assert !rating.valid?
|
62
|
+
assert rating.errors.invalid?(:value_id)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class RatingAfterBeingCreatedTest < ActiveRecord::TestCase
|
67
|
+
def setup
|
68
|
+
@rating = create_rating
|
69
|
+
end
|
70
|
+
|
71
|
+
def test_should_have_a_value
|
72
|
+
assert_not_nil @rating.value
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_should_have_a_ratable_association
|
76
|
+
assert_not_nil @rating.ratable
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_should_have_a_rater
|
80
|
+
assert_not_nil @rating.rater
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class RatingValueByDefaultTest < ActiveRecord::TestCase
|
4
|
+
def setup
|
5
|
+
@rating_value = RatingValue.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_should_not_have_a_name
|
9
|
+
assert @rating_value.name.blank?
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_should_not_have_a_value
|
13
|
+
assert_nil @rating_value.value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class RatingValueTest < ActiveRecord::TestCase
|
18
|
+
def test_should_be_valid_with_a_valid_set_of_attributes
|
19
|
+
rating_value = new_rating_value
|
20
|
+
assert rating_value.valid?
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_should_require_a_name
|
24
|
+
rating_value = new_rating_value(:name => nil)
|
25
|
+
assert !rating_value.valid?
|
26
|
+
assert rating_value.errors.invalid?(:name)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_should_require_a_value
|
30
|
+
rating_value = new_rating_value(:value => nil)
|
31
|
+
assert !rating_value.valid?
|
32
|
+
assert rating_value.errors.invalid?(:value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_should_convert_to_an_integer
|
36
|
+
rating_value = new_rating_value(:value => 1)
|
37
|
+
assert_equal 1, rating_value.to_i
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class RatingValueAfterBeingCreatedTest < ActiveRecord::TestCase
|
42
|
+
def setup
|
43
|
+
@rating_value = create_rating_value
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_should_not_have_any_ratings
|
47
|
+
assert @rating_value.ratings.empty?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class RatingValueWithRatingsTest < ActiveRecord::TestCase
|
52
|
+
def setup
|
53
|
+
@rating_value = create_rating_value
|
54
|
+
@poor_rating = create_rating(:value => @rating_value)
|
55
|
+
@second_poor_rating = create_rating(:value => @rating_value)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_should_have_ratings
|
59
|
+
assert_equal [@poor_rating, @second_poor_rating], @rating_value.ratings
|
60
|
+
end
|
61
|
+
end
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: has_ratings
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aaron Pfeifer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-04-30 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: enumerate_by
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.4.0
|
24
|
+
version:
|
25
|
+
description:
|
26
|
+
email: aaron@pluginaweek.org
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files: []
|
32
|
+
|
33
|
+
files:
|
34
|
+
- app/models
|
35
|
+
- app/models/rating.rb
|
36
|
+
- app/models/rating_value.rb
|
37
|
+
- assets/images
|
38
|
+
- assets/images/star.gif
|
39
|
+
- assets/stylesheets
|
40
|
+
- assets/stylesheets/star.css
|
41
|
+
- db/migrate
|
42
|
+
- db/migrate/002_create_ratings.rb
|
43
|
+
- db/migrate/001_create_rating_values.rb
|
44
|
+
- lib/has_ratings.rb
|
45
|
+
- test/factory.rb
|
46
|
+
- test/test_helper.rb
|
47
|
+
- test/functional
|
48
|
+
- test/functional/has_ratings_test.rb
|
49
|
+
- test/unit
|
50
|
+
- test/unit/rating_value_test.rb
|
51
|
+
- test/unit/rating_test.rb
|
52
|
+
- test/app_root
|
53
|
+
- test/app_root/db
|
54
|
+
- test/app_root/db/migrate
|
55
|
+
- test/app_root/db/migrate/003_migrate_has_ratings_to_version_2.rb
|
56
|
+
- test/app_root/db/migrate/002_create_videos.rb
|
57
|
+
- test/app_root/db/migrate/001_create_users.rb
|
58
|
+
- test/app_root/config
|
59
|
+
- test/app_root/config/environment.rb
|
60
|
+
- test/app_root/app
|
61
|
+
- test/app_root/app/models
|
62
|
+
- test/app_root/app/models/user.rb
|
63
|
+
- test/app_root/app/models/video.rb
|
64
|
+
- CHANGELOG.rdoc
|
65
|
+
- init.rb
|
66
|
+
- LICENSE
|
67
|
+
- Rakefile
|
68
|
+
- README.rdoc
|
69
|
+
has_rdoc: true
|
70
|
+
homepage: http://www.pluginaweek.org
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: "0"
|
81
|
+
version:
|
82
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: "0"
|
87
|
+
version:
|
88
|
+
requirements: []
|
89
|
+
|
90
|
+
rubyforge_project: pluginaweek
|
91
|
+
rubygems_version: 1.3.1
|
92
|
+
signing_key:
|
93
|
+
specification_version: 2
|
94
|
+
summary: Demonstrates a reference implementation for handling ratings.
|
95
|
+
test_files:
|
96
|
+
- test/functional/has_ratings_test.rb
|
97
|
+
- test/unit/rating_value_test.rb
|
98
|
+
- test/unit/rating_test.rb
|