Module: UsageCredits::PeriodParser

Defined in:
lib/usage_credits/helpers/period_parser.rb

Overview

Handles parsing and normalization of time periods throughout the gem. Converts strings like “1.month” or symbols like :monthly into ActiveSupport::Duration objects.

Constant Summary collapse

VALID_PERIODS =

Canonical periods and their aliases

{
  day: [:day, :daily],                # 1.day
  week: [:week, :weekly],             # 1.week
  month: [:month, :monthly],          # 1.month
  quarter: [:quarter, :quarterly],    # 3.months
  year: [:year, :yearly, :annually]   # 1.year
}.freeze
MIN_PERIOD =
1.day

Class Method Summary collapse

Class Method Details

.normalize_period(period) ⇒ Object

Turns things like ‘:monthly` into `1.month` to always store consistent time periods



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/usage_credits/helpers/period_parser.rb', line 22

def normalize_period(period)
  return nil unless period

  # Handle ActiveSupport::Duration objects directly
  if period.is_a?(ActiveSupport::Duration)
    raise ArgumentError, "Period must be at least #{MIN_PERIOD.inspect}" if period < MIN_PERIOD
    period
  else
    # Convert symbols to canonical durations
    case period
    when *VALID_PERIODS[:day] then 1.day
    when *VALID_PERIODS[:week] then 1.week
    when *VALID_PERIODS[:month] then 1.month
    when *VALID_PERIODS[:quarter] then 3.months
    when *VALID_PERIODS[:year] then 1.year
    else
      raise ArgumentError, "Unsupported period: #{period}. Supported periods: #{VALID_PERIODS.values.flatten.inspect}"
    end
  end
end

.parse_period(period_str) ⇒ ActiveSupport::Duration

Parse a period string into an ActiveSupport::Duration

Parameters:

  • period_str (String, ActiveSupport::Duration)

    A string like “1.month” or “1 month” or an existing duration

Returns:

  • (ActiveSupport::Duration)

    The parsed duration

Raises:

  • (ArgumentError)

    If the period string is invalid



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/usage_credits/helpers/period_parser.rb', line 47

def parse_period(period_str)
  return period_str if period_str.is_a?(ActiveSupport::Duration)

  if period_str.to_s =~ /\A(\d+)[.\s](\w+)\z/
    amount = $1.to_i
    unit = $2.singularize.to_sym

    # Validate the unit is supported
    valid_units = VALID_PERIODS.values.flatten
    unless valid_units.include?(unit)
      raise ArgumentError, "Unsupported period unit: #{unit}. Supported units: #{valid_units.inspect}"
    end

    duration = amount.send(unit)
    raise ArgumentError, "Period must be at least #{MIN_PERIOD.inspect}" if duration < MIN_PERIOD
    duration
  else
    raise ArgumentError, "Invalid period format: #{period_str}. Expected format: '1.month', '2 months', etc."
  end
end

.valid_period_format?(period_str) ⇒ Boolean

Validates that a period string matches the expected format and units

Returns:

  • (Boolean)


69
70
71
72
73
74
# File 'lib/usage_credits/helpers/period_parser.rb', line 69

def valid_period_format?(period_str)
  parse_period(period_str)
  true
rescue ArgumentError
  false
end