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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f0ec61a85ec090995b6030203a9b8808e85ff27e
4
- data.tar.gz: a21d6768ecb083c34b4b103d78100f2095d726dc
3
+ metadata.gz: d5343fe7238068fb78cb53e3fc86339774633348
4
+ data.tar.gz: 167c1f8ec30362080420cffde1c5b3025d98dde4
5
5
  SHA512:
6
- metadata.gz: ca8a6fdb9c2f2fd00d25ea31ca507fafa6cd69c0c9eb3bbe7d3509f368b67a35329012be76909f56a71defb91be16a3d35358eed729e8623a7d586466f810aa2
7
- data.tar.gz: b1734c47ace30591629843cc41dfda108c2671e13cf2c15831972659db6b55025a5c5f74b869e76dfd815f4438a539e250bf1cf7bc9d202799836d054d4595f1
6
+ metadata.gz: 6250ef18663aa9959dd415678b633cb2cac036c59c6d18048532b01deedebbcb4e7d68619f7d7b3768e95e2b85791e2f71fd69e819adcbffd50b5d76c3b4e1e1
7
+ data.tar.gz: 045e580ca96472802d7d4b1fee0059db2211a7a5a041cff4bbd630b37a07896a759a3eaf7bbbdc9c45fc5ad90ce600e3468c7076c22475bd12932a556cd2e7f3
@@ -1,4 +1,5 @@
1
1
  language: ruby
2
+ sudo: false
2
3
  rvm:
3
4
  - 2.0
4
5
  - 2.1
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 overriden and customised.
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/[USERNAME]/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.
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
@@ -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
- # object that has various attributes that you need rated.
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
- # rating can be calculated based on varying attributes of that model.
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
- # that is rateable. See FiveStar.rateable.
36
+ # that is rateable. See FiveStar.rateable.
34
37
  #
35
38
  # This implements the interface necessary to calculate a rating for the
36
- # rateable instance. At a minium this must be +build+, +rating+,
37
- # +description+ and +weighting+.
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
- # the instance being rated.
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
@@ -1,26 +1,24 @@
1
1
  module FiveStar
2
2
  # Base implementation of a class to give a rating, weighting and description
3
- # to a +rateable+ instance.
3
+ # to a +rateable+ instance.
4
4
  #
5
- # Default implementation is defined below, users should override methods
6
- # with their own implementation.
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 rate
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 can be any
22
- # valid floating point number at present, the weighting system is up to
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 ||= 1.0
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 `rateable`
62
- # object.
63
- # Override to customise this message.
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 `rateable` object.
84
- # Override this method to perform your own calculation for the rating based
85
- # on your own criteria. If this is an expensive operation then the result
86
- # should be cached as this method *can* be called more than once, for
87
- # example by the +description+ method.
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
- # @return [Float] the rating value
108
- # defaults to 0 unless overridden
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
- 0
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
- 10
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
- 0
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.name
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
@@ -0,0 +1,5 @@
1
+ module FiveStar
2
+ # Exception raised when error calculating occurs.
3
+ #
4
+ RatingError = Class.new(StandardError)
5
+ end
@@ -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] object
7
- # the object to mix in this +Rateable+ module
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
- # using this module.
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] *klasses
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.rateable
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
- # Define which rating classes will be used to rate the object
42
- # using this module.
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 `rateable` object by calculating based on
55
- # set raters and their configuration.
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 `rateable`
69
- # object.
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
- # defined in `rate_with`.
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
- # when generating descriptions.
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 name
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
- # Each instance must implement `rating` and `weighting`.
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
- def self.rate(raters)
7
- new(raters).calculate_rating
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 0 unless raters.any?
28
+ return min_rating unless raters.any?
21
29
 
22
- sum_total / weights_total.to_f
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| rater.rating * rater.weighting }.inject(&:+)
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).inject(&:+)
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
@@ -1,3 +1,3 @@
1
1
  module FiveStar
2
- VERSION = "0.1.1"
2
+ VERSION = "1.0.0"
3
3
  end
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.1.1
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: 2015-12-06 00:00:00.000000000 Z
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