config: build the OpenSkill model once
Axis#ranking, Axis#ratings, and the list view each built their own
model; they now read CONFIG.open_skill so the sort order and the
displayed ordinal cannot drift apart.
Assisted-by: Claude Sonnet 5.5 via Claude Code
diff --git a/lib/rank_king/config.rb b/lib/rank_king/config.rb
index efbcda8..07e3bf3 100644
--- a/lib/rank_king/config.rb
+++ b/lib/rank_king/config.rb
@@ -2,11 +2,14 @@
require "securerandom"
+require_relative "../open_skill"
+
module RankKing
# @rbs skip
Config = Data.define(
:database_url,
:session_secret,
+ :open_skill,
)
class Config
@@ -20,9 +23,10 @@ module RankKing
new(
database_url: env.fetch("DATABASE_URL", ":memory:"),
session_secret: env.fetch("SESSION_SECRET") { SecureRandom.hex(64) },
+ open_skill: OpenSkill::Model.new,
)
end
end
- CONFIG = Config.from_env
+ CONFIG = Config.from_env #: Config
end
diff --git a/lib/rank_king/models.rb b/lib/rank_king/models.rb
index 5f9e7b6..5f613b8 100644
--- a/lib/rank_king/models.rb
+++ b/lib/rank_king/models.rb
@@ -46,14 +46,14 @@ module RankKing
# the axis's `ratings` when the caller already has them.
def ranking(ratings = self.ratings)
ranked, unranked = list.items.partition { |item| ratings.key?(item.id) }
- model = OpenSkill::Model.new
+ model = CONFIG.open_skill
[ranked.sort_by { |item| [-model.ordinal(ratings.fetch(item.id)), item.id] }, unranked]
end
# Each compared item's rating, from replaying the axis's results in
# the order they were recorded.
def ratings
- model = OpenSkill::Model.new
+ model = CONFIG.open_skill
ratings = {} #: Hash[Integer, OpenSkill::Rating]
results_dataset.order(:id).each do |result|
winner = ratings.fetch(result.winner_id) { model.rating }
diff --git a/lib/rank_king/views/list/show.rb b/lib/rank_king/views/list/show.rb
index 56c1909..f8b8629 100644
--- a/lib/rank_king/views/list/show.rb
+++ b/lib/rank_king/views/list/show.rb
@@ -86,7 +86,7 @@ module RankKing
def render_ranking(axis)
ratings = axis.ratings
ranked, unranked = axis.ranking(ratings)
- model = OpenSkill::Model.new
+ model = CONFIG.open_skill
ol(class: "card") do
ranked.each.with_index(1) do |item, rank|
diff --git a/sig/rank_king/config.rbs b/sig/rank_king/config.rbs
index f359a38..0a5bcad 100644
--- a/sig/rank_king/config.rbs
+++ b/sig/rank_king/config.rbs
@@ -5,7 +5,8 @@ module RankKing
class Config
attr_reader database_url: String
attr_reader session_secret: String
+ attr_reader open_skill: OpenSkill::Model
- def self.new: (database_url: String, session_secret: String) -> instance
+ def self.new: (database_url: String, session_secret: String, open_skill: OpenSkill::Model) -> instance
end
end
diff --git a/test/test_web.rb b/test/test_web.rb
index e469bf8..0d38c8d 100644
--- a/test/test_web.rb
+++ b/test/test_web.rb
@@ -248,7 +248,7 @@ class TestWeb < Minitest::Test
get "/lists/#{list.id}"
body = last_response.body[/role="tabpanel".*/m]
assert_equal 2, body.scan(/<span[^>]*data-rating/).size
- model = OpenSkill::Model.new
+ model = RankKing::CONFIG.open_skill
winner, loser = [sushi, pizza].map { |i| axis.ratings.fetch(i.id) }
assert_operator model.ordinal(loser), :<, 0
shown = body.scan(%r{<span[^>]*data-rating[^>]*title="([^"]*)"[^>]*>(-?\d+\.\d)</span>})