Module: AWSCronParser::Describer

Includes:
Helpers
Defined in:
lib/aws_cron_parser/describer.rb,
lib/aws_cron_parser/describer/template.rb,
lib/aws_cron_parser/describer/day_composer.rb,
lib/aws_cron_parser/describer/cron_composer.rb,
lib/aws_cron_parser/describer/time_composer.rb,
lib/aws_cron_parser/describer/month_composer.rb,
lib/aws_cron_parser/describer/field_describers/base.rb,
lib/aws_cron_parser/describer/field_describers/month.rb,
lib/aws_cron_parser/describer/field_describers/time_field.rb,
lib/aws_cron_parser/describer/field_describers/day_of_week.rb,
lib/aws_cron_parser/describer/field_describers/day_of_month.rb

Defined Under Namespace

Modules: FieldDescribers Classes: CronComposer, DayComposer, MonthComposer, Template, TimeComposer

Class Method Summary collapse

Methods included from Helpers

included

Class Method Details

.describe(expression) ⇒ Object

Main entry point: describe a CRON expression in human-readable form Returns string like "Every weekday at 9:00 AM"



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/aws_cron_parser/describer.rb', line 11

def describe(expression)
  return nil if expression.nil? || expression.to_s.strip.empty? || !expression.is_a?(String)

  begin
    AWSCronParser::Validator.validate(expression)
    config = parse_config(expression)
    return nil unless config

    case config[:type]
    when 'rate'
      describe_rate(config)
    when 'macro'
      describe_macro(config)
    when 'at'
      describe_at(config)
    when /^(aws-)?cron/
      describe_cron(config)
    end
  end
end

.describe_at(config) ⇒ Object

Describe at expression



100
101
102
103
104
105
# File 'lib/aws_cron_parser/describer.rb', line 100

def describe_at(config)
  date_time = Time.zone.parse(config[:dateTime])
  "At #{date_time.strftime('%A, %b %d, %Y %I:%M:%S %p')}"
rescue StandardError
  nil
end

.describe_cron(config) ⇒ Object

Describe CRON expression using composers



108
109
110
# File 'lib/aws_cron_parser/describer.rb', line 108

def describe_cron(config)
  CronComposer.new(config).compose
end

.describe_field(value, field_type, is_aws: false) ⇒ Object

Legacy method - kept for backward compatibility Delegates to appropriate field describer



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/aws_cron_parser/describer.rb', line 114

def describe_field(value, field_type, is_aws: false)
  return nil if value.blank? || ['*', '?'].include?(value)

  case field_type
  when 'minute', 'second', 'hour'
    FieldDescribers::TimeField.new(value, field_type.to_sym, is_aws: is_aws).describe
  when 'day-of-month'
    FieldDescribers::DayOfMonth.new(value, is_aws: is_aws).describe
  when 'day-of-week'
    FieldDescribers::DayOfWeek.new(value, is_aws: is_aws).describe
  when 'month'
    FieldDescribers::Month.new(value, is_aws: is_aws).describe
  else
    value
  end
end

.describe_macro(config) ⇒ Object

Describe macro expression



94
95
96
97
# File 'lib/aws_cron_parser/describer.rb', line 94

def describe_macro(config)
  macro = config[:macro]
  Template.interpolate("macro.#{macro}") || "Every #{macro}"
end

.describe_rate(config) ⇒ Object

Describe rate expression



86
87
88
89
90
91
# File 'lib/aws_cron_parser/describer.rb', line 86

def describe_rate(config)
  value = config[:value]
  unit = config[:unit]

  Template.interpolate(value == 1 ? 'rate.singular' : 'rate.plural', value: value, unit: unit)
end

.parse_config(expression) ⇒ Object

Parse parser into config hash for describing



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/aws_cron_parser/describer.rb', line 33

def parse_config(expression)
  trimmed = expression.strip

  # Rate expression: rate(value unit)
  if (rate_match = trimmed.match(RATE_REGEX))
    unit = rate_match[:unit].downcase.chomp('s').to_sym
    return { type: 'rate', value: rate_match[:value].to_i, unit: unit }
  end

  # Macro expressions: @yearly, @monthly, etc.
  if (macro_match = trimmed.match(MACRO_REGEX))
    macro = macro_match[:macro].downcase
    return { type: 'macro', macro: macro }
  end

  # At expression: at(iso8601)
  if (at_match = trimmed.match(AT_REGEX))
    return { type: 'at', dateTime: at_match[:datetime] }
  end

  # Detect AWS cron wrapper
  is_aws = false
  content = trimmed
  if (cron_match = content.match(AWS_CRON_REGEX))
    is_aws = true
    content = cron_match[:expression].strip
  end

  fields = content.split(/\s+/)
  case fields.length
  when 5
    # Standard CRON: MINUTE HOUR DAY MONTH DOW
    # OR AWS (no wrapper): not applicable, AWS needs cron() wrapper
    { type: is_aws ? 'aws-cron-5' : 'cron-5', second: nil, minute: fields[0], hour: fields[1], day: fields[2],
      month: fields[3], dow: fields[4], is_aws: is_aws }
  when 6
    if is_aws
      # AWS with wrapper: MINUTE HOUR DAY MONTH DOW YEAR
      { type: 'aws-cron-6', second: nil, minute: fields[0], hour: fields[1], day: fields[2], month: fields[3],
        dow: fields[4], year: fields[5], is_aws: is_aws }
    else
      # Unix CRON: SECOND MINUTE HOUR DAY MONTH DOW
      { type: 'cron-6', second: fields[0], minute: fields[1], hour: fields[2], day: fields[3], month: fields[4],
        dow: fields[5], is_aws: is_aws }
    end
  when 7
    # AWS with seconds: SECOND MINUTE HOUR DAY MONTH DOW YEAR
    { type: 'aws-cron-7', second: fields[0], minute: fields[1], hour: fields[2], day: fields[3], month: fields[4],
      dow: fields[5], year: fields[6], is_aws: is_aws }
  end
end