From aa752d4839375f313f0d3e0070e85fbbac13ced9 Mon Sep 17 00:00:00 2001 From: erdgeist Date: Thu, 16 Jul 2026 16:49:25 +0200 Subject: Aggregate selected weeks in a more human friendly form Weekdays appearing on a subset of the weeks of the month are now aggregated into a simpler form. --- app/models/concerns/rrule_humanizer.rb | 23 +++++++++++++++++++---- test/models/concerns/rrule_humanizer_test.rb | 8 ++++---- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/app/models/concerns/rrule_humanizer.rb b/app/models/concerns/rrule_humanizer.rb index ca29648..07141c1 100644 --- a/app/models/concerns/rrule_humanizer.rb +++ b/app/models/concerns/rrule_humanizer.rb @@ -46,19 +46,30 @@ module RruleHumanizer excluded_monthly_ordinal = nil excluded_monthly_weekday = nil + selected_monthly_ordinals = nil + selected_monthly_weekday = nil if freq == "MONTHLY" && byday_values.present? ordinal_days = byday_values.map { |d| d.match(/^([1-5])([A-Z]{2})$/) } if ordinal_days.all? positions = ordinal_days.map { |match| match[1].to_i }.uniq.sort weekdays_in_rule = ordinal_days.map { |match| match[2] }.uniq - missing_positions = (1..5).to_a - positions - if positions.size == 4 && weekdays_in_rule.size == 1 && missing_positions.size == 1 - excluded_monthly_ordinal = missing_positions.first - excluded_monthly_weekday = weekdays_in_rule.first + if weekdays_in_rule.size == 1 + selected_monthly_ordinals = positions + selected_monthly_weekday = weekdays_in_rule.first + missing_positions = (1..5).to_a - positions + if positions.size == 4 && missing_positions.size == 1 + excluded_monthly_ordinal = missing_positions.first + excluded_monthly_weekday = selected_monthly_weekday + end end end end + join_ordinals = lambda do |ordinal_values, conjunction| + names = ordinal_values.map { |ordinal| ordinals[ordinal] } + names.size > 1 ? "#{names[0..-2].join(', ')} #{conjunction} #{names.last}" : names.first + end + base = case loc when :de @@ -77,6 +88,8 @@ module RruleHumanizer when "MONTHLY" if excluded_monthly_ordinal "Jeden #{weekdays[excluded_monthly_weekday]} im Monat, außer dem #{ordinals[excluded_monthly_ordinal]} #{weekdays[excluded_monthly_weekday]}" + elsif selected_monthly_ordinals + "Jeden #{join_ordinals.call(selected_monthly_ordinals, 'und')} #{weekdays[selected_monthly_weekday]} im Monat" else days ? "Jeden #{days.join(' und ')} im Monat" : "Monatlich" end @@ -88,6 +101,8 @@ module RruleHumanizer when "MONTHLY" if excluded_monthly_ordinal "Every #{weekdays[excluded_monthly_weekday]} of the month, except the #{ordinals[excluded_monthly_ordinal]} #{weekdays[excluded_monthly_weekday]}" + elsif selected_monthly_ordinals + "Every #{join_ordinals.call(selected_monthly_ordinals, 'and')} #{weekdays[selected_monthly_weekday]} of the month" else days ? "Every #{days.join(' and ')} of the month" : "Monthly" end diff --git a/test/models/concerns/rrule_humanizer_test.rb b/test/models/concerns/rrule_humanizer_test.rb index c4e78d4..54c4c22 100644 --- a/test/models/concerns/rrule_humanizer_test.rb +++ b/test/models/concerns/rrule_humanizer_test.rb @@ -48,10 +48,10 @@ class RruleHumanizerTest < ActiveSupport::TestCase end test "monthly selected weeks" do - assert_equal "Jeden ersten Dienstag und dritten Dienstag im Monat", - humanize("FREQ=MONTHLY;BYDAY=1TU,3TU") - assert_equal "Every first Tuesday and third Tuesday of the month", - humanize("FREQ=MONTHLY;BYDAY=1TU,3TU", :en) + assert_equal "Jeden ersten, zweiten und fünften Dienstag im Monat", + humanize("FREQ=MONTHLY;BYDAY=1TU,2TU,5TU") + assert_equal "Every first, second and fifth Tuesday of the month", + humanize("FREQ=MONTHLY;BYDAY=1TU,2TU,5TU", :en) end test "monthly fifth weekday" do -- cgit v1.3