From 0e31d5105bd9787ad0e7c2496bd95f39a11f5076 Mon Sep 17 00:00:00 2001 From: Valentine Frolov Date: Tue, 29 Sep 2026 10:25:46 +0300 Subject: [PATCH] fix(#1219): print a float in the bill text with two decimals instead of a whole number --- lib/fbe/award.rb | 11 ++++++++++- test/fbe/test_award.rb | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/lib/fbe/award.rb b/lib/fbe/award.rb index ae6eeb43..246c9d38 100644 --- a/lib/fbe/award.rb +++ b/lib/fbe/award.rb @@ -370,7 +370,7 @@ def line(value, text) text.gsub(/\$\{([^}]*)\}/) do |_x| k = Regexp.last_match[1].to_sym raise(Fbe::Error, "Undefined variable '#{k}' used in award text: #{text}") unless @vars.key?(k) - @vars[k].is_a?(Float) ? whole(@vars[k]) : @vars[k] + @vars[k].is_a?(Float) ? short(@vars[k]) : @vars[k] end return if value.zero? @lines << { v: value, t: text } @@ -416,6 +416,15 @@ def greeting def whole(value) Integer(Float(value).round) end + + # Rounds a Float to two decimals, dropping the fraction when it is zero. + # + # @param [Float] value The value to print in the text of a line + # @return [Float, Integer] The value as short as it can be printed + def short(value) + r = value.round(2) + r == r.round ? r.round : r + end end # A class for generating human-readable bylaws. diff --git a/test/fbe/test_award.rb b/test/fbe/test_award.rb index b13c5c3d..db2b7811 100644 --- a/test/fbe/test_award.rb +++ b/test/fbe/test_award.rb @@ -240,4 +240,39 @@ def test_rounds_float_variable_in_award_text def test_div_does_not_truncate_integers assert_equal(3, Fbe::Award.new('(award (give (times (div 3 2) 2) "x"))').bill.points) end + + def test_prints_float_rate_in_award_text + seed = Random.new_seed + k = Random.new(seed).rand(1..99) / 100.0 + g = Fbe::Award.new( + "(award (give 1 \"base\") (in hoc \"hits\") (let k #{k}) (set b (times hoc k)) (give b \"at ${k} each\"))" + ).bill(hoc: 1000).greeting + assert_includes(g, "at #{k} each", "rate is not printed as is, seed #{seed}") + end + + def test_rounds_float_in_award_text_to_two_decimals + g = Fbe::Award.new('(award (give 1 "base") (set r (div 1 3)) (give 5 "at ${r} each"))').bill.greeting + assert_includes(g, 'at 0.33 each', 'float is not rounded to two decimals') + end + + def test_prints_whole_float_in_award_text_without_fraction + seed = Random.new_seed + n = Random.new(seed).rand(1..1000) + g = Fbe::Award.new( + "(award (give 1 \"base\") (set d (times 0.5 #{n * 2})) (give 5 \"for ${d} days\"))" + ).bill.greeting + assert_includes(g, "for #{n} days", "whole float is printed with a fraction, seed #{seed}") + end + + def test_prints_tiny_negative_float_in_award_text_as_zero + g = Fbe::Award.new('(award (give 1 "base") (set d (times -0.001 1)) (give 5 "for ${d} days"))').bill.greeting + assert_includes(g, 'for 0 days', 'tiny negative float is not printed as zero') + end + + def test_prints_negative_float_rate_in_award_text + seed = Random.new_seed + k = -Random.new(seed).rand(1..99) / 100.0 + g = Fbe::Award.new("(award (give 1 \"base\") (let k #{k}) (give 5 \"at ${k} each\"))").bill.greeting + assert_includes(g, "at #{k} each", "negative rate is not printed as is, seed #{seed}") + end end