elo_rankable 0.2.0 → 0.2.2

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/lib/elo_rankable.rb CHANGED
@@ -1,96 +1,96 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_record'
4
- require 'active_support'
5
-
6
- require_relative 'elo_rankable/version'
7
- require_relative 'elo_rankable/configuration'
8
- require_relative 'elo_rankable/elo_ranking'
9
- require_relative 'elo_rankable/calculator'
10
- require_relative 'elo_rankable/has_elo_ranking'
11
-
12
- # EloRankable provides methods for recording Elo-based ranking results for multiplayer matches,
13
- # winner-vs-all matches, and draws between players. It expects player objects to respond to
14
- # `elo_ranking` and `beat!` methods, and includes configuration support.
15
- #
16
- # Example usage:
17
- # EloRankable.record_multiplayer_match([player1, player2, player3])
18
- # EloRankable.record_winner_vs_all(winner, [loser1, loser2])
19
- # EloRankable.record_draw(player1, player2)
20
- #
21
- # Configuration can be customized via EloRankable.configure.
22
- #
23
- # Errors:
24
- # EloRankable::InvalidMatchError - Raised for invalid match scenarios.
25
- # ArgumentError - Raised for invalid arguments or player objects.
26
- module EloRankable
27
- class Error < StandardError; end
28
- class InvalidMatchError < Error; end
29
-
30
- class << self
31
- def config
32
- @config ||= Configuration.new
33
- end
34
-
35
- def configure
36
- yield(config) if block_given?
37
- end
38
-
39
- # Record a multiplayer match where players are ranked by their position in the array
40
- # Higher-indexed players are treated as having lost to lower-indexed ones
41
- def record_multiplayer_match(players)
42
- raise InvalidMatchError, 'Need at least 2 players for a match' if players.length < 2
43
-
44
- # Validate input array
45
- raise ArgumentError, 'Players array cannot contain nil values' if players.any?(&:nil?)
46
-
47
- # Check for duplicates
48
- raise ArgumentError, 'Players array cannot contain duplicate players' if players.uniq.length != players.length
49
-
50
- # Validate all players respond to elo_ranking
51
- invalid_players = players.reject { |p| p.respond_to?(:elo_ranking) }
52
- raise ArgumentError, 'All players must respond to elo_ranking' unless invalid_players.empty?
53
-
54
- # Process all pairwise combinations
55
- players.each_with_index do |player1, i|
56
- players[(i + 1)..].each do |player2|
57
- player1.beat!(player2)
58
- end
59
- end
60
- end
61
-
62
- # Record a single winner vs all others match
63
- def record_winner_vs_all(winner, losers)
64
- # Validate winner
65
- raise ArgumentError, 'Winner cannot be nil' if winner.nil?
66
- raise ArgumentError, 'Winner must respond to elo_ranking' unless winner.respond_to?(:elo_ranking)
67
-
68
- # Validate losers array
69
- raise InvalidMatchError, 'Need at least 1 loser' if losers.empty?
70
- raise ArgumentError, 'Losers array cannot contain nil values' if losers.any?(&:nil?)
71
- raise InvalidMatchError, 'Winner cannot be in losers list' if losers.include?(winner)
72
-
73
- # Validate all losers respond to elo_ranking
74
- invalid_losers = losers.reject { |p| p.respond_to?(:elo_ranking) }
75
- raise ArgumentError, 'All losers must respond to elo_ranking' unless invalid_losers.empty?
76
-
77
- losers.each do |loser|
78
- winner.beat!(loser)
79
- end
80
- end
81
-
82
- # Record a draw between two players
83
- def record_draw(player1, player2)
84
- raise ArgumentError, 'Player1 cannot be nil' if player1.nil?
85
- raise ArgumentError, 'Player2 cannot be nil' if player2.nil?
86
- raise ArgumentError, 'Cannot record draw with same player' if player1 == player2
87
- raise ArgumentError, 'Player1 must respond to elo_ranking' unless player1.respond_to?(:elo_ranking)
88
- raise ArgumentError, 'Player2 must respond to elo_ranking' unless player2.respond_to?(:elo_ranking)
89
-
90
- Calculator.update_ratings_for_draw(player1, player2)
91
- end
92
- end
93
- end
94
-
95
- # Hook into ActiveRecord
96
- ActiveRecord::Base.extend(EloRankable::HasEloRanking) if defined?(ActiveRecord::Base)
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_record'
4
+ require 'active_support'
5
+
6
+ require_relative 'elo_rankable/version'
7
+ require_relative 'elo_rankable/configuration'
8
+ require_relative 'elo_rankable/elo_ranking'
9
+ require_relative 'elo_rankable/calculator'
10
+ require_relative 'elo_rankable/has_elo_ranking'
11
+
12
+ # EloRankable provides methods for recording Elo-based ranking results for multiplayer matches,
13
+ # winner-vs-all matches, and draws between players. It expects player objects to respond to
14
+ # `elo_ranking` and `beat!` methods, and includes configuration support.
15
+ #
16
+ # Example usage:
17
+ # EloRankable.record_multiplayer_match([player1, player2, player3])
18
+ # EloRankable.record_winner_vs_all(winner, [loser1, loser2])
19
+ # EloRankable.record_draw(player1, player2)
20
+ #
21
+ # Configuration can be customized via EloRankable.configure.
22
+ #
23
+ # Errors:
24
+ # EloRankable::InvalidMatchError - Raised for invalid match scenarios.
25
+ # ArgumentError - Raised for invalid arguments or player objects.
26
+ module EloRankable
27
+ class Error < StandardError; end
28
+ class InvalidMatchError < Error; end
29
+
30
+ class << self
31
+ def config
32
+ @config ||= Configuration.new
33
+ end
34
+
35
+ def configure
36
+ yield(config) if block_given?
37
+ end
38
+
39
+ # Record a multiplayer match where players are ranked by their position in the array
40
+ # Higher-indexed players are treated as having lost to lower-indexed ones
41
+ def record_multiplayer_match(players)
42
+ raise InvalidMatchError, 'Need at least 2 players for a match' if players.length < 2
43
+
44
+ # Validate input array
45
+ raise ArgumentError, 'Players array cannot contain nil values' if players.any?(&:nil?)
46
+
47
+ # Check for duplicates
48
+ raise ArgumentError, 'Players array cannot contain duplicate players' if players.uniq.length != players.length
49
+
50
+ # Validate all players respond to elo_ranking
51
+ invalid_players = players.reject { |p| p.respond_to?(:elo_ranking) }
52
+ raise ArgumentError, 'All players must respond to elo_ranking' unless invalid_players.empty?
53
+
54
+ # Process all pairwise combinations
55
+ players.each_with_index do |player1, i|
56
+ players[(i + 1)..].each do |player2|
57
+ player1.beat!(player2)
58
+ end
59
+ end
60
+ end
61
+
62
+ # Record a single winner vs all others match
63
+ def record_winner_vs_all(winner, losers)
64
+ # Validate winner
65
+ raise ArgumentError, 'Winner cannot be nil' if winner.nil?
66
+ raise ArgumentError, 'Winner must respond to elo_ranking' unless winner.respond_to?(:elo_ranking)
67
+
68
+ # Validate losers array
69
+ raise InvalidMatchError, 'Need at least 1 loser' if losers.empty?
70
+ raise ArgumentError, 'Losers array cannot contain nil values' if losers.any?(&:nil?)
71
+ raise InvalidMatchError, 'Winner cannot be in losers list' if losers.include?(winner)
72
+
73
+ # Validate all losers respond to elo_ranking
74
+ invalid_losers = losers.reject { |p| p.respond_to?(:elo_ranking) }
75
+ raise ArgumentError, 'All losers must respond to elo_ranking' unless invalid_losers.empty?
76
+
77
+ losers.each do |loser|
78
+ winner.beat!(loser)
79
+ end
80
+ end
81
+
82
+ # Record a draw between two players
83
+ def record_draw(player1, player2)
84
+ raise ArgumentError, 'Player1 cannot be nil' if player1.nil?
85
+ raise ArgumentError, 'Player2 cannot be nil' if player2.nil?
86
+ raise ArgumentError, 'Cannot record draw with same player' if player1 == player2
87
+ raise ArgumentError, 'Player1 must respond to elo_ranking' unless player1.respond_to?(:elo_ranking)
88
+ raise ArgumentError, 'Player2 must respond to elo_ranking' unless player2.respond_to?(:elo_ranking)
89
+
90
+ Calculator.update_ratings_for_draw(player1, player2)
91
+ end
92
+ end
93
+ end
94
+
95
+ # Hook into ActiveRecord
96
+ ActiveRecord::Base.extend(EloRankable::HasEloRanking) if defined?(ActiveRecord::Base)
@@ -1,21 +1,29 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rails/generators/active_record'
4
-
5
- module EloRankable
6
- module Generators
7
- class InstallGenerator < ActiveRecord::Generators::Base
8
- desc 'Create migration for EloRankable'
9
-
10
- source_root File.expand_path('templates', __dir__)
11
-
12
- def self.default_generator_root
13
- File.dirname(__FILE__)
14
- end
15
-
16
- def create_migration_file
17
- migration_template 'create_elo_rankings.rb', 'db/migrate/create_elo_rankings.rb'
18
- end
19
- end
20
- end
21
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails/generators'
4
+ require 'rails/generators/migration'
5
+
6
+ module EloRankable
7
+ module Generators
8
+ class InstallGenerator < Rails::Generators::Base
9
+ include Rails::Generators::Migration
10
+
11
+ desc 'Create migration for EloRankable'
12
+
13
+ source_root File.expand_path('templates', __dir__)
14
+
15
+ def self.next_migration_number(dirname)
16
+ next_migration_number = current_migration_number(dirname) + 1
17
+ ActiveRecord::Migration.next_migration_number(next_migration_number)
18
+ end
19
+
20
+ def self.default_generator_root
21
+ File.dirname(__FILE__)
22
+ end
23
+
24
+ def create_migration_file
25
+ migration_template 'create_elo_rankings.rb', 'db/migrate/create_elo_rankings.rb'
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,16 +1,16 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateEloRankings < ActiveRecord::Migration[6.0]
4
- def change
5
- create_table :elo_rankings do |t|
6
- t.references :rankable, polymorphic: true, null: false, index: true
7
- t.integer :rating, null: false, default: 1200
8
- t.integer :games_played, null: false, default: 0
9
-
10
- t.timestamps
11
- end
12
-
13
- add_index :elo_rankings, :rating
14
- add_index :elo_rankings, %i[rankable_type rankable_id], unique: true
15
- end
16
- end
1
+ # frozen_string_literal: true
2
+
3
+ class CreateEloRankings < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
4
+ def change
5
+ create_table :elo_rankings do |t|
6
+ t.references :rankable, polymorphic: true, null: false, index: true
7
+ t.integer :rating, null: false, default: 1200
8
+ t.integer :games_played, null: false, default: 0
9
+
10
+ t.timestamps
11
+ end
12
+
13
+ add_index :elo_rankings, :rating
14
+ add_index :elo_rankings, %i[rankable_type rankable_id], unique: true
15
+ end
16
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elo_rankable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aberen
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '6.0'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '8.0'
22
+ version: '9.0'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '6.0'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '8.0'
32
+ version: '9.0'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: activesupport
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -39,7 +39,7 @@ dependencies:
39
39
  version: '6.0'
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
- version: '8.0'
42
+ version: '9.0'
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -49,8 +49,8 @@ dependencies:
49
49
  version: '6.0'
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
- version: '8.0'
53
- description: Adds ELO rating to any ActiveRecord model via has_elo_ranking. It stores
52
+ version: '9.0'
53
+ description: Adds Elo rating to any ActiveRecord model via has_elo_ranking. It stores
54
54
  ratings in a separate EloRanking model to keep your host model clean, and provides
55
55
  domain-style methods for updating rankings after matches.
56
56
  email:
@@ -100,5 +100,5 @@ requirements: []
100
100
  rubygems_version: 3.5.11
101
101
  signing_key:
102
102
  specification_version: 4
103
- summary: Add ELO rating capabilities to any ActiveRecord model
103
+ summary: Add Elo rating capabilities to any ActiveRecord model
104
104
  test_files: []