has_ratings 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|