weighted_list_rank 0.3.1 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bf34a6c62fda7d3038b31da0d7c8d9ec0b9a86a1b0204308e44d950e599f95b7
4
- data.tar.gz: 3ed6316fa225185f79afa58899f2b0d29c0abb072c7835492be8dc14b1151b39
3
+ metadata.gz: f9afa895dc286e9cc5dd2370376b965eda825669debad06e21c232b996e2cab6
4
+ data.tar.gz: 6116b3e97dc978a0ca8021f683ff7d5b31b1ebd1e0e3f07fc10c7a266b34659e
5
5
  SHA512:
6
- metadata.gz: ff08f7f218c00bd592e6c54a8862df527fb8c75cbfdf28ec4ccad44221c73b3fb699f590b0e8cb82c7b9e023e42f0fd285dab907a766864b88360cfb622dcdc2
7
- data.tar.gz: 760b3d89d47fce1c4fa48899bdd9f58ee925bbe90937988028b1162f19b6afb4f157b37a7ff68b4964d6581f288834e9a065c372f68ca22bf0d31f572cda9806
6
+ metadata.gz: 71656bad8660b6ae1455afc06a406dddf69f688feb22b690b6dcef57b39aa2ba60df1fe14be91aa22af957b71960b7fe856a980b1769090ea039149fcb005abe
7
+ data.tar.gz: cb30e3d19ed531e74ff7d665c92029a105c83a6d18e3ce98671c3471218c1c5fa6fc39672394161444b38cc2a97d0dfc2aeab60cfaedefde2664f246cd9ac5c6
data/CHANGELOG.md CHANGED
@@ -1,12 +1,16 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.4.0] - 2024-06-26
4
+ - Added score_penalty feature to allow percentage-based penalties on item scores.
5
+ - Updated all dependencies to their latest versions.
6
+
3
7
  ## [0.3.1] - 2024-05-026
4
8
 
5
9
  - Fixed issue with lists with only a single item getting bonus points
6
10
 
7
11
  ## [0.3.0] - 2024-02-03
8
12
 
9
- - added bonus_pool_percentage feature to expoential
13
+ - added bonus_pool_percentage feature to exponential
10
14
 
11
15
  ## [0.2.0] - 2024-02-03
12
16
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- weighted_list_rank (0.3.1)
4
+ weighted_list_rank (0.4.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -10,18 +10,18 @@ GEM
10
10
  json (2.7.2)
11
11
  language_server-protocol (3.17.0.3)
12
12
  lint_roller (1.1.0)
13
- minitest (5.23.1)
14
- parallel (1.24.0)
15
- parser (3.3.1.0)
13
+ minitest (5.24.0)
14
+ parallel (1.25.1)
15
+ parser (3.3.3.0)
16
16
  ast (~> 2.4.1)
17
17
  racc
18
18
  racc (1.8.0)
19
19
  rainbow (3.1.1)
20
20
  rake (13.2.1)
21
21
  regexp_parser (2.9.2)
22
- rexml (3.2.8)
23
- strscan (>= 3.0.9)
24
- rubocop (1.63.5)
22
+ rexml (3.3.1)
23
+ strscan
24
+ rubocop (1.64.1)
25
25
  json (~> 2.3)
26
26
  language_server-protocol (>= 3.17.0)
27
27
  parallel (~> 1.10)
@@ -37,16 +37,16 @@ GEM
37
37
  rubocop-minitest (0.35.0)
38
38
  rubocop (>= 1.61, < 2.0)
39
39
  rubocop-ast (>= 1.31.1, < 2.0)
40
- rubocop-performance (1.21.0)
40
+ rubocop-performance (1.21.1)
41
41
  rubocop (>= 1.48.1, < 2.0)
42
42
  rubocop-ast (>= 1.31.1, < 2.0)
43
43
  rubocop-rake (0.6.0)
44
44
  rubocop (~> 1.0)
45
45
  ruby-progressbar (1.13.0)
46
- standard (1.36.0)
46
+ standard (1.39.0)
47
47
  language_server-protocol (~> 3.17.0.2)
48
48
  lint_roller (~> 1.0)
49
- rubocop (~> 1.63.0)
49
+ rubocop (~> 1.64.0)
50
50
  standard-custom (~> 1.0.0)
51
51
  standard-performance (~> 1.4)
52
52
  standard-custom (1.0.2)
data/README.md CHANGED
@@ -92,6 +92,78 @@ custom_ranked_items.each do |item|
92
92
  end
93
93
  ```
94
94
 
95
+ ### Using Item Penalties
96
+ The WeightedListRank system also supports applying penalties to individual items. A penalty is defined as a percentage reduction in the item's score. This feature can be used to de-emphasize certain items based on specific criteria.
97
+
98
+ To use the penalty feature, include the score_penalty attribute when defining your items:
99
+
100
+ ```ruby
101
+ class MyItem
102
+ include WeightedListRank::Item
103
+ attr_reader :id, :position, :score_penalty
104
+
105
+ def initialize(id, position, score_penalty = nil)
106
+ @id = id
107
+ @position = position
108
+ @score_penalty = score_penalty
109
+ end
110
+ end
111
+ ```
112
+
113
+ You can then apply the penalties when calculating the scores:
114
+
115
+ ```ruby
116
+ require 'weighted_list_rank'
117
+
118
+ # Initialize items and list with text identifiers and penalties
119
+ items = [
120
+ MyItem.new("Item 1", 1, 0.20), # 20% penalty
121
+ MyItem.new("Item 2", 2, 0.10), # 10% penalty
122
+ MyItem.new("Item 3", 3, nil) # No penalty
123
+ ]
124
+ list = MyList.new("List 1", 10, items)
125
+
126
+ # Initialize the Exponential strategy with an optional exponent
127
+ exponential_strategy = WeightedListRank::Strategies::Exponential.new(exponent: 1.5)
128
+
129
+ # Create a RankingContext using the Exponential strategy
130
+ ranking_context = WeightedListRank::RankingContext.new(exponential_strategy)
131
+
132
+ # Rank the items
133
+ ranked_items = ranking_context.rank([list])
134
+
135
+ # Display the ranked items
136
+ ranked_items.each do |item|
137
+ puts "Item: #{item[:id]}, Total Score: #{item[:total_score]}"
138
+ end
139
+ ```
140
+
141
+ ### Customizing Penalties Example
142
+ You can customize the penalty values to see how they affect the final scores of the items.
143
+
144
+ ```ruby
145
+ # Customizing penalties for different items
146
+ items = [
147
+ MyItem.new("Item 1", 1, 0.30), # 30% penalty
148
+ MyItem.new("Item 2", 2, 0.15), # 15% penalty
149
+ MyItem.new("Item 3", 3, nil) # No penalty
150
+ ]
151
+ list = MyList.new("List 1", 10, items)
152
+
153
+ # Initialize the Exponential strategy with an optional exponent
154
+ exponential_strategy = WeightedListRank::Strategies::Exponential.new(exponent: 2.0)
155
+
156
+ # Create a RankingContext using the Exponential strategy
157
+ ranking_context = WeightedListRank::RankingContext.new(exponential_strategy)
158
+
159
+ # Rank the items
160
+ ranked_items = ranking_context.rank([list])
161
+
162
+ # Output the results
163
+ ranked_items.each do |item|
164
+ puts "Item: #{item[:id]}, Total Score: #{item[:total_score]}"
165
+ end
166
+ ```
95
167
 
96
168
  ## Development
97
169
 
data/Rakefile CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "bundler/gem_tasks"
4
4
  require "rake/testtask"
5
+ require "standard/rake"
5
6
 
6
7
  Rake::TestTask.new(:test) do |t|
7
8
  t.libs << "test"
@@ -11,5 +11,11 @@ module WeightedListRank
11
11
  def id
12
12
  raise NotImplementedError, "Implement this method to return the item's unique identifier"
13
13
  end
14
+
15
+ # Returns the score penalty of the item. Can be overridden by the including class.
16
+ # @return [Float, NilClass] the score penalty of the item as a percentage (e.g., 0.20 for 20%) or nil if no penalty
17
+ def score_penalty
18
+ nil
19
+ end
14
20
  end
15
21
  end
@@ -42,21 +42,38 @@ module WeightedListRank
42
42
  # @return [Float] the calculated score for the item, adjusted by the list's weight, the specified exponent,
43
43
  # and the bonus pool percentage.
44
44
  def calculate_score(list, item)
45
- # Return the list weight if there are no positions
46
- return list.weight if item.position.nil? || list.items.count == 1
45
+ # Default score to the list's weight
46
+ score = list.weight
47
47
 
48
- num_items = list.items.count
49
- total_bonus_pool = list.weight * bonus_pool_percentage
48
+ unless item.position.nil? || list.items.count == 1
49
+ num_items = list.items.count
50
+ total_bonus_pool = list.weight * bonus_pool_percentage
50
51
 
51
- # Calculate the exponential factor for the item's rank position
52
- exponential_factor = (num_items + 1 - item.position)**exponent
53
- total_exponential_factor = (1..num_items).sum { |pos| (num_items + 1 - pos)**exponent }
52
+ # Calculate the exponential factor for the item's rank position
53
+ exponential_factor = (num_items + 1 - item.position)**exponent
54
+ total_exponential_factor = (1..num_items).sum { |pos| (num_items + 1 - pos)**exponent }
54
55
 
55
- # Allocate a portion of the total bonus pool based on the item's exponential factor
56
- item_bonus = (exponential_factor / total_exponential_factor) * total_bonus_pool
56
+ # Allocate a portion of the total bonus pool based on the item's exponential factor
57
+ item_bonus = (exponential_factor / total_exponential_factor) * total_bonus_pool
57
58
 
58
- # The final score is the list's weight plus the item's allocated bonus
59
- list.weight + item_bonus
59
+ # Add the item's allocated bonus to the default score
60
+ score += item_bonus
61
+ end
62
+
63
+ # Apply score penalty if it exists
64
+ apply_penalty(score, item.score_penalty)
65
+ end
66
+
67
+ private
68
+
69
+ # Applies the score penalty if it exists
70
+ #
71
+ # @param score [Float] the original score of the item
72
+ # @param penalty [Float, NilClass] the score penalty of the item as a percentage (e.g., 0.20 for 20%) or nil if no penalty
73
+ #
74
+ # @return [Float] the score after applying the penalty
75
+ def apply_penalty(score, penalty)
76
+ penalty ? score * (1 - penalty) : score
60
77
  end
61
78
  end
62
79
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WeightedListRank
4
- VERSION = "0.3.1"
4
+ VERSION = "0.4.0"
5
5
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/weighted_list_rank/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "weighted_list_rank"
7
+ spec.version = WeightedListRank::VERSION
8
+ spec.authors = ["Shane Sherman"]
9
+ spec.email = ["shane.sherman@gmail.com"]
10
+
11
+ spec.summary = "generate ranks of items from weighted lists"
12
+ spec.description = "generate ranks of items from weighted lists"
13
+ spec.homepage = "https://github.com/ssherman/weighted_list_rank"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = ">= 2.6.0"
16
+
17
+ # spec.metadata["allowed_push_host"] = "TODO: Set to your gem server 'https://example.com'"
18
+
19
+ spec.metadata["homepage_uri"] = spec.homepage
20
+ spec.metadata["source_code_uri"] = "https://github.com/ssherman/weighted_list_rank"
21
+ spec.metadata["changelog_uri"] = "https://github.com/ssherman/weighted_list_rank/CHANGELOG.md"
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(__dir__) do
26
+ `git ls-files -z`.split("\x0").reject do |f|
27
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
28
+ end
29
+ end
30
+ spec.bindir = "exe"
31
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ # Uncomment to register a new dependency of your gem
35
+ # spec.add_dependency "example-gem", "~> 1.0"
36
+ spec.add_development_dependency "rubocop", "~> 1.0"
37
+ spec.add_development_dependency "standard", "~> 1.0"
38
+ spec.add_development_dependency "rubocop-minitest", "~> 0.3"
39
+ spec.add_development_dependency "rubocop-rake", "~> 0.6"
40
+ # For more information and examples about making a new gem, check out our
41
+ # guide at: https://bundler.io/guides/creating_gem.html
42
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: weighted_list_rank
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shane Sherman
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-05-26 00:00:00.000000000 Z
11
+ date: 2024-06-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -89,6 +89,7 @@ files:
89
89
  - lib/weighted_list_rank/strategy.rb
90
90
  - lib/weighted_list_rank/version.rb
91
91
  - sig/weighted_list_rank.rbs
92
+ - weighted_list_rank.gemspec
92
93
  homepage: https://github.com/ssherman/weighted_list_rank
93
94
  licenses:
94
95
  - MIT
@@ -111,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
111
112
  - !ruby/object:Gem::Version
112
113
  version: '0'
113
114
  requirements: []
114
- rubygems_version: 3.3.7
115
+ rubygems_version: 3.5.11
115
116
  signing_key:
116
117
  specification_version: 4
117
118
  summary: generate ranks of items from weighted lists