# frozen_string_literal: true module Expire # Base class for rules with an adjective in their name class KeepAdjectiveRuleBase < RuleBase using RefineAllAndNone NOUN_FOR = { 'hourly' => 'hour', 'daily' => 'day', 'weekly' => 'week', 'monthly' => 'month', 'yearly' => 'year' }.freeze PRIMARY_RANK = 20 SECONDARY_RANK_FOR = { 'hourly' => 1, 'daily' => 2, 'weekly' => 3, 'monthly' => 4, 'yearly' => 5 }.freeze def self.from_value(value) value = -1 if value.all? value = 0 if value.none? integer_value = Integer(value) raise ArgumentError, 'must be at least -1' if integer_value < -1 new(amount: integer_value) end def self.primary_rank PRIMARY_RANK end def self.rank primary_rank + secondary_rank end def self.secondary_rank match = name.downcase.match(/(hourly|daily|weekly|monthly|yearly)/) return unless match SECONDARY_RANK_FOR[match[1]] end def adjective @adjective ||= infer_adjective end def apply(backups, _) per_spacing = backups.one_per(spacing) kept = amount == -1 ? per_spacing : per_spacing.most_recent(amount) kept.each { |backup| backup.add_reason_to_keep(reason_to_keep) } end def rank @rank ||= primary_rank + secondary_rank end def primary_rank self.class.primary_rank end def secondary_rank self.class.secondary_rank end def spacing NOUN_FOR[adjective] end private def class_name self.class.to_s end def infer_adjective match = class_name.downcase.match(/(hourly|daily|weekly|monthly|yearly)/) return unless match match[1] end def reason_to_keep "keep #{pretty_amount} #{adjective} #{numerus_backup}" end def pretty_amount amount == -1 ? 'all' : amount.to_s end end end