five-star 0.1.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/README.md +5 -5
- data/lib/five-star.rb +12 -8
- data/lib/five-star/base_rater.rb +40 -27
- data/lib/five-star/configuration.rb +14 -0
- data/lib/five-star/errors.rb +5 -0
- data/lib/five-star/rateable.rb +42 -20
- data/lib/five-star/rating_calculator.rb +55 -9
- data/lib/five-star/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d5343fe7238068fb78cb53e3fc86339774633348
|
4
|
+
data.tar.gz: 167c1f8ec30362080420cffde1c5b3025d98dde4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6250ef18663aa9959dd415678b633cb2cac036c59c6d18048532b01deedebbcb4e7d68619f7d7b3768e95e2b85791e2f71fd69e819adcbffd50b5d76c3b4e1e1
|
7
|
+
data.tar.gz: 045e580ca96472802d7d4b1fee0059db2211a7a5a041cff4bbd630b37a07896a759a3eaf7bbbdc9c45fc5ad90ce600e3468c7076c22475bd12932a556cd2e7f3
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
|
9
9
|
:star: **FiveStar** :star: is a library to build a rating system - it allows you to rate *something* in your domain by various classification or criteria you define. This library gives you the structure to rate your object with as many of these different classifications as you like with the overall rating calculated from the weighted average.
|
10
10
|
|
11
|
-
This uses *Plain Old Ruby Objects* so can be used in any project.
|
11
|
+
This gem uses *Plain Old Ruby Objects* so it can be used in any project.
|
12
12
|
|
13
13
|
|
14
14
|
## Example
|
@@ -70,7 +70,7 @@ class SwearingRater < FiveStar.base_rater
|
|
70
70
|
end
|
71
71
|
|
72
72
|
film = Film.new
|
73
|
-
film.rating # => 6
|
73
|
+
film.rating # => 6.0
|
74
74
|
film.rating_descriptions # => ["The film Alien was rated 8 for gore", ...]
|
75
75
|
|
76
76
|
```
|
@@ -123,7 +123,7 @@ class Film
|
|
123
123
|
end
|
124
124
|
|
125
125
|
film = Film.new
|
126
|
-
film.rating # => 6
|
126
|
+
film.rating # => 6.0
|
127
127
|
film.rating_descriptions # => ["The film Alien was rated 8 for gore", ...]
|
128
128
|
```
|
129
129
|
|
@@ -165,7 +165,7 @@ end
|
|
165
165
|
|
166
166
|
The calculation used will be a weighted average based on each rating and the weighting defined in that class. If weighting is not required then all will be use the default value (of 1.0) and therefore be weighted the same, this being just a normal mean average calculation.
|
167
167
|
|
168
|
-
The default rating scale used is 0 - 10 as floating point numbers although this can be
|
168
|
+
The default rating scale used is 0 - 10 as floating point numbers although this can be customised.
|
169
169
|
|
170
170
|
|
171
171
|
## Development
|
@@ -176,7 +176,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
176
176
|
|
177
177
|
## Contributing
|
178
178
|
|
179
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
179
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/rob-murray/five-star. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
180
180
|
|
181
181
|
|
182
182
|
## License
|
data/lib/five-star.rb
CHANGED
@@ -1,18 +1,19 @@
|
|
1
1
|
require "five-star/version"
|
2
2
|
require "five-star/base_rater"
|
3
|
+
require "five-star/configuration"
|
3
4
|
require "five-star/rateable"
|
5
|
+
require "five-star/errors"
|
4
6
|
require "five-star/rating_calculator"
|
5
7
|
|
6
8
|
# Base module for library interface
|
7
9
|
module FiveStar
|
8
10
|
class << self
|
9
11
|
# Include this in your class that can be rated - this is your domain model
|
10
|
-
#
|
12
|
+
# object that has various attributes that you need rated.
|
11
13
|
# Being +rateable+ is defined as an object that has attributes on which a
|
12
|
-
#
|
14
|
+
# rating can be calculated based on varying attributes of that model.
|
13
15
|
#
|
14
16
|
# This adds the public class and instance methods from the Rateable module.
|
15
|
-
# See FiveStar::Rateable
|
16
17
|
#
|
17
18
|
# @example
|
18
19
|
# class Film
|
@@ -22,6 +23,8 @@ module FiveStar
|
|
22
23
|
# # ...
|
23
24
|
# end
|
24
25
|
#
|
26
|
+
# @see FiveStar::Rateable
|
27
|
+
#
|
25
28
|
# @return [Class]
|
26
29
|
#
|
27
30
|
# @api public
|
@@ -30,15 +33,14 @@ module FiveStar
|
|
30
33
|
end
|
31
34
|
|
32
35
|
# The base class of a class that gives a rating and weighting to something
|
33
|
-
#
|
36
|
+
# that is rateable. See FiveStar.rateable.
|
34
37
|
#
|
35
38
|
# This implements the interface necessary to calculate a rating for the
|
36
|
-
#
|
37
|
-
#
|
39
|
+
# rateable instance. At a minimum this must be +build+, +rating+,
|
40
|
+
# +description+ and +weighting+.
|
38
41
|
#
|
39
42
|
# The method +build+ *will* be called on each class with the argument of
|
40
|
-
#
|
41
|
-
# See FiveStar::BaseRater
|
43
|
+
# the instance being rated.
|
42
44
|
#
|
43
45
|
# @example
|
44
46
|
# class GoreRater < FiveStar.base_rater
|
@@ -53,6 +55,8 @@ module FiveStar
|
|
53
55
|
# end
|
54
56
|
# end
|
55
57
|
#
|
58
|
+
# @see FiveStar::BaseRater
|
59
|
+
#
|
56
60
|
# @return [Class]
|
57
61
|
#
|
58
62
|
# @api public
|
data/lib/five-star/base_rater.rb
CHANGED
@@ -1,26 +1,24 @@
|
|
1
1
|
module FiveStar
|
2
2
|
# Base implementation of a class to give a rating, weighting and description
|
3
|
-
#
|
3
|
+
# to a +rateable+ instance.
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
5
|
+
# You are *expected* to subclass this class and override the default
|
6
|
+
# implementation with your own implementation.
|
7
7
|
class BaseRater
|
8
|
-
# Called to build a new instance of the rater with the given object
|
9
|
-
# being rated.
|
8
|
+
# Called to build a new instance of the rater with the given object being rated.
|
10
9
|
#
|
11
10
|
# @param [Object] rateable
|
12
11
|
# the instance of the Object being rated
|
13
12
|
#
|
14
|
-
# @return [Object] the instance created ready to
|
13
|
+
# @return [Object] the instance of Rating class created ready to be used
|
15
14
|
#
|
16
15
|
# @api public
|
17
16
|
def self.build(rateable)
|
18
17
|
new(rateable)
|
19
18
|
end
|
20
19
|
|
21
|
-
# Set the weighting for this rating classifcation class. This
|
22
|
-
#
|
23
|
-
# the user to ensure correct.
|
20
|
+
# Set the weighting for this rating classifcation class. This should
|
21
|
+
# a valid floating point within the scale configured.
|
24
22
|
#
|
25
23
|
# @example
|
26
24
|
# class GoreRater < FiveStar.base_rater
|
@@ -41,11 +39,11 @@ module FiveStar
|
|
41
39
|
# Return the weighting value for this rating classifcation class.
|
42
40
|
#
|
43
41
|
# @return [Float]
|
44
|
-
# the weighting value
|
42
|
+
# the weighting value. Defaults to 1.0
|
45
43
|
#
|
46
44
|
# @api public
|
47
45
|
def self.weighting
|
48
|
-
@weighting ||=
|
46
|
+
@weighting ||= Configuration::DEFAULT_WEIGHTING
|
49
47
|
end
|
50
48
|
|
51
49
|
# Create a new instance of rater
|
@@ -58,9 +56,9 @@ module FiveStar
|
|
58
56
|
@rateable = rateable
|
59
57
|
end
|
60
58
|
|
61
|
-
# Return the rating description for the rater given to the
|
62
|
-
#
|
63
|
-
# Override to customise
|
59
|
+
# Return the rating description for the rater given to the +rateable+
|
60
|
+
# object.
|
61
|
+
# Override this method to customise the message.
|
64
62
|
#
|
65
63
|
# @example
|
66
64
|
# class GoreRater < FiveStar.base_rater
|
@@ -80,11 +78,11 @@ module FiveStar
|
|
80
78
|
"#{self.class} rated #{rateable_name} at #{rating} with weighting of #{weighting}"
|
81
79
|
end
|
82
80
|
|
83
|
-
# Return the rating for the rater given to the
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
81
|
+
# Return the rating for the rater given to the +rateable+ object.
|
82
|
+
# You are *expected* to override this method to perform your own calculation
|
83
|
+
# for the rating based on your own criteria. If this is an expensive
|
84
|
+
# operation then the result should be cached as this method *can* be
|
85
|
+
# called more than once, for example by the +description+ method.
|
88
86
|
#
|
89
87
|
# @example
|
90
88
|
# class GoreRater < FiveStar.base_rater
|
@@ -104,12 +102,15 @@ module FiveStar
|
|
104
102
|
#
|
105
103
|
# rater.rating # => 6
|
106
104
|
#
|
107
|
-
# @
|
108
|
-
#
|
105
|
+
# @raise [FiveStar::RatingError] raises error if any raters return either
|
106
|
+
# +rating+ or +weighting+ that is outside of configuration bounds.
|
107
|
+
#
|
108
|
+
# @return [Float] the rating value calculated.
|
109
|
+
# Defaults to minimum rating value unless overridden
|
109
110
|
#
|
110
111
|
# @api public
|
111
112
|
def rating
|
112
|
-
|
113
|
+
configuration.min_rating
|
113
114
|
end
|
114
115
|
|
115
116
|
# Return the weighting value for this rating classifcation class.
|
@@ -127,27 +128,29 @@ module FiveStar
|
|
127
128
|
attr_reader :rateable
|
128
129
|
|
129
130
|
# Return the maximum weighting value for this rating classifcation class.
|
131
|
+
# By default this comes from the instance of FiveStar::Configuration used.
|
130
132
|
#
|
131
133
|
# Override if required - this should be the same for each rater class.
|
132
134
|
#
|
133
135
|
# @return [Fixnum]
|
134
|
-
# the maximum rating value.
|
136
|
+
# the maximum rating value from configuration.
|
135
137
|
#
|
136
138
|
# @api protected
|
137
139
|
def max_rating
|
138
|
-
|
140
|
+
configuration.max_rating
|
139
141
|
end
|
140
142
|
|
141
143
|
# Return the minimum weighting value for this rating classifcation class.
|
144
|
+
# By default this comes from the instance of FiveStar::Configuration used.
|
142
145
|
#
|
143
146
|
# Override if required - this should be the same for each rater class.
|
144
147
|
#
|
145
148
|
# @return [Fixnum]
|
146
|
-
# the minimum rating value.
|
149
|
+
# the minimum rating value from configuration.
|
147
150
|
#
|
148
151
|
# @api protected
|
149
152
|
def min_rating
|
150
|
-
|
153
|
+
configuration.min_rating
|
151
154
|
end
|
152
155
|
|
153
156
|
# Return the name of the given rateable instance.
|
@@ -157,7 +160,17 @@ module FiveStar
|
|
157
160
|
#
|
158
161
|
# @api protected
|
159
162
|
def rateable_name
|
160
|
-
rateable.
|
163
|
+
rateable.rateable_name
|
164
|
+
end
|
165
|
+
|
166
|
+
# The current configuration instance for the given +rateable+ object.
|
167
|
+
#
|
168
|
+
# @return [FiveStar::Configuration]
|
169
|
+
# the instance of configuration described by the +rateable+ class.
|
170
|
+
#
|
171
|
+
# @api protected
|
172
|
+
def configuration
|
173
|
+
rateable.configuration
|
161
174
|
end
|
162
175
|
end
|
163
176
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module FiveStar
|
2
|
+
# Default configuration of rating values and weighting.
|
3
|
+
#
|
4
|
+
# @api private
|
5
|
+
class Configuration
|
6
|
+
DEFAULT_WEIGHTING = 1.0.freeze
|
7
|
+
|
8
|
+
def min_rating; 0.0; end
|
9
|
+
def max_rating; 10.0; end
|
10
|
+
|
11
|
+
def min_weighting; 0.0; end
|
12
|
+
def max_weighting; 1.0; end
|
13
|
+
end
|
14
|
+
end
|
data/lib/five-star/rateable.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module FiveStar
|
2
|
-
# A module to be included to enhance an object with the interface below
|
2
|
+
# A module to be included to enhance an object with the interface below.
|
3
3
|
module Rateable
|
4
4
|
# Extends base class or a module with Rateable methods
|
5
5
|
#
|
6
|
-
# @param [Object]
|
7
|
-
# the object to mix in this
|
6
|
+
# @param base [Object]
|
7
|
+
# the object to mix in this *Rateable* module
|
8
8
|
#
|
9
9
|
# @return [undefined]
|
10
10
|
#
|
@@ -15,7 +15,7 @@ module FiveStar
|
|
15
15
|
|
16
16
|
module ClassMethods
|
17
17
|
# Set which rating classes will be used to rate the object
|
18
|
-
#
|
18
|
+
# using this module.
|
19
19
|
# Each class must implement the rater methods, see FiveStar::BaseRater
|
20
20
|
#
|
21
21
|
# @example
|
@@ -26,20 +26,20 @@ module FiveStar
|
|
26
26
|
# # ...
|
27
27
|
# end
|
28
28
|
#
|
29
|
-
# @param [Class]
|
29
|
+
# @param klasses [Class]
|
30
30
|
# constants referencing classes to rate object included with
|
31
31
|
#
|
32
32
|
# @return [undefined]
|
33
33
|
#
|
34
|
-
# @see FiveStar
|
34
|
+
# @see FiveStar::BaseRater
|
35
35
|
#
|
36
36
|
# @api public
|
37
37
|
def rate_with(*klasses)
|
38
38
|
@rating_klasses = Array(klasses)
|
39
39
|
end
|
40
40
|
|
41
|
-
#
|
42
|
-
#
|
41
|
+
# Return which rating classes will be used to rate the object
|
42
|
+
# using this module.
|
43
43
|
#
|
44
44
|
# @return [Array] list of classes to rate with
|
45
45
|
#
|
@@ -49,26 +49,40 @@ module FiveStar
|
|
49
49
|
def rating_klasses
|
50
50
|
@rating_klasses ||= []
|
51
51
|
end
|
52
|
+
|
53
|
+
# Reference to Configuration used for this +rateable+ instance.
|
54
|
+
#
|
55
|
+
# @return [FiveStar::Configuration] Configuration instance in use
|
56
|
+
#
|
57
|
+
# @see FiveStar::Configuration
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
def configuration
|
61
|
+
@configuration ||= Configuration.new
|
62
|
+
end
|
52
63
|
end
|
53
64
|
|
54
|
-
# Return the rating given to the
|
55
|
-
#
|
65
|
+
# Return the rating given to the +rateable+ object by calculating based on
|
66
|
+
# set raters and their configuration.
|
56
67
|
#
|
57
68
|
# @example
|
58
69
|
# film = Film.new
|
59
|
-
# film.rating # => 6
|
70
|
+
# film.rating # => 6.0
|
60
71
|
#
|
61
72
|
# @return [Float] rating calculated by set raters for the object
|
62
73
|
#
|
74
|
+
# @raise [FiveStar::RatingError] raises error if any raters return either
|
75
|
+
# +rating+ or +weighting+ that is outside of configuration bounds.
|
76
|
+
#
|
63
77
|
# @api public
|
64
78
|
def rating
|
65
|
-
rating_calculator.rate(raters)
|
79
|
+
rating_calculator.rate(self.class.configuration, raters)
|
66
80
|
end
|
67
81
|
|
68
|
-
# Return the rating description for each rater given to the
|
69
|
-
#
|
82
|
+
# Return the rating description for each rater given to the +rateable+
|
83
|
+
# object.
|
70
84
|
# These are returned in the order in which the rating classes were
|
71
|
-
#
|
85
|
+
# defined in +rate_with+.
|
72
86
|
#
|
73
87
|
# @example
|
74
88
|
# film = Film.new
|
@@ -81,18 +95,26 @@ module FiveStar
|
|
81
95
|
raters.map { |rater| rater.description }
|
82
96
|
end
|
83
97
|
|
84
|
-
# The name of the object that is rateable. This may be used by raters
|
85
|
-
#
|
86
|
-
# This can be overridden to provide a better response, otherwise is the class
|
87
|
-
# name.
|
98
|
+
# The name of the object that is rateable. This may be used by raters when
|
99
|
+
# generating descriptions.
|
100
|
+
# This can be overridden to provide a better response, otherwise is the class name.
|
88
101
|
#
|
89
102
|
# @return [String] name of the class
|
90
103
|
#
|
91
104
|
# @api public
|
92
|
-
def
|
105
|
+
def rateable_name
|
93
106
|
self.class.name
|
94
107
|
end
|
95
108
|
|
109
|
+
# Reference to Configuration used for this +rateable+ instance. Delegates to class.
|
110
|
+
#
|
111
|
+
# @return [FiveStar::Configuration] Configuration instance in use
|
112
|
+
#
|
113
|
+
# @api private
|
114
|
+
def configuration
|
115
|
+
self.class.configuration
|
116
|
+
end
|
117
|
+
|
96
118
|
protected
|
97
119
|
|
98
120
|
# The instance that included this module
|
@@ -1,37 +1,83 @@
|
|
1
1
|
module FiveStar
|
2
2
|
# Calculate overall rating for the rateable object from each rater.
|
3
|
-
#
|
3
|
+
# Each instance must implement +rating+ and +weighting+.
|
4
|
+
# The configuration instance provides min and max rating and weighting values.
|
5
|
+
#
|
4
6
|
# @api private
|
5
7
|
class RatingCalculator
|
6
|
-
|
7
|
-
|
8
|
+
# @see calculate_rating
|
9
|
+
def self.rate(configuration, raters)
|
10
|
+
new(configuration, raters).calculate_rating
|
8
11
|
end
|
9
12
|
|
10
|
-
def initialize(raters)
|
13
|
+
def initialize(configuration, raters)
|
14
|
+
@configuration = configuration
|
11
15
|
@raters = raters
|
12
16
|
end
|
13
17
|
|
14
18
|
# Calculate the overall weighting from each rating class
|
15
19
|
#
|
16
20
|
# @return [Float] the calculated rating
|
21
|
+
# The min rating will be returned if there are no raters.
|
22
|
+
#
|
23
|
+
# @raise [FiveStar::RatingError] raises error if any raters return either
|
24
|
+
# +rating+ or +weighting+ that is outside of configuration bounds.
|
17
25
|
#
|
18
26
|
# @api private
|
19
27
|
def calculate_rating
|
20
|
-
return
|
28
|
+
return min_rating unless raters.any?
|
21
29
|
|
22
|
-
sum_total / weights_total
|
30
|
+
sum_total / weights_total
|
23
31
|
end
|
24
32
|
|
25
33
|
private
|
26
34
|
|
27
|
-
attr_reader :raters
|
35
|
+
attr_reader :raters, :configuration
|
28
36
|
|
29
37
|
def sum_total
|
30
|
-
raters.map { |rater|
|
38
|
+
raters.map { |rater|
|
39
|
+
validate_rating!(rater.rating, rater) * validate_weighting!(rater.weighting, rater)
|
40
|
+
}.reduce(&:+)
|
31
41
|
end
|
32
42
|
|
33
43
|
def weights_total
|
34
|
-
raters.map(&:weighting).
|
44
|
+
raters.map(&:weighting).reduce(&:+)
|
45
|
+
end
|
46
|
+
|
47
|
+
def validate_rating!(rating, rater)
|
48
|
+
rating = rating.to_f
|
49
|
+
|
50
|
+
if rating < min_rating || rating > max_rating
|
51
|
+
raise RatingError, "Rating #{rating} is invalid from #{rater.class}"
|
52
|
+
else
|
53
|
+
rating
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def validate_weighting!(weighting, rater)
|
58
|
+
weighting = weighting.to_f
|
59
|
+
|
60
|
+
if weighting < min_weighting || weighting > max_weighting
|
61
|
+
raise RatingError, "Weighting #{weighting} is invalid from #{rater.class}"
|
62
|
+
else
|
63
|
+
weighting
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def min_rating
|
68
|
+
configuration.min_rating
|
69
|
+
end
|
70
|
+
|
71
|
+
def max_rating
|
72
|
+
configuration.max_rating
|
73
|
+
end
|
74
|
+
|
75
|
+
def min_weighting
|
76
|
+
configuration.min_weighting
|
77
|
+
end
|
78
|
+
|
79
|
+
def max_weighting
|
80
|
+
configuration.max_weighting
|
35
81
|
end
|
36
82
|
end
|
37
83
|
end
|
data/lib/five-star/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: five-star
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob Murray
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -129,6 +129,8 @@ files:
|
|
129
129
|
- five-star.gemspec
|
130
130
|
- lib/five-star.rb
|
131
131
|
- lib/five-star/base_rater.rb
|
132
|
+
- lib/five-star/configuration.rb
|
133
|
+
- lib/five-star/errors.rb
|
132
134
|
- lib/five-star/rateable.rb
|
133
135
|
- lib/five-star/rating_calculator.rb
|
134
136
|
- lib/five-star/version.rb
|