aws-cron-parser 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +32 -0
- data/LICENSE.txt +21 -0
- data/README.md +117 -0
- data/lib/aws_cron_parser/describer/cron_composer.rb +198 -0
- data/lib/aws_cron_parser/describer/day_composer.rb +74 -0
- data/lib/aws_cron_parser/describer/field_describers/base.rb +108 -0
- data/lib/aws_cron_parser/describer/field_describers/day_of_month.rb +88 -0
- data/lib/aws_cron_parser/describer/field_describers/day_of_week.rb +143 -0
- data/lib/aws_cron_parser/describer/field_describers/month.rb +92 -0
- data/lib/aws_cron_parser/describer/field_describers/time_field.rb +101 -0
- data/lib/aws_cron_parser/describer/month_composer.rb +29 -0
- data/lib/aws_cron_parser/describer/template.en.yml +183 -0
- data/lib/aws_cron_parser/describer/template.rb +87 -0
- data/lib/aws_cron_parser/describer/time_composer.rb +255 -0
- data/lib/aws_cron_parser/describer.rb +131 -0
- data/lib/aws_cron_parser/fugit_adapter.rb +64 -0
- data/lib/aws_cron_parser/helpers/calendar.rb +115 -0
- data/lib/aws_cron_parser/helpers/clock.rb +50 -0
- data/lib/aws_cron_parser/helpers/cron_expression.rb +277 -0
- data/lib/aws_cron_parser/helpers/numbers.rb +32 -0
- data/lib/aws_cron_parser/helpers.rb +17 -0
- data/lib/aws_cron_parser/parser.rb +152 -0
- data/lib/aws_cron_parser/parsers/aws_at.rb +32 -0
- data/lib/aws_cron_parser/parsers/aws_cron.rb +413 -0
- data/lib/aws_cron_parser/parsers/aws_rate.rb +33 -0
- data/lib/aws_cron_parser/parsers/base.rb +21 -0
- data/lib/aws_cron_parser/parsers/quartz_cron.rb +21 -0
- data/lib/aws_cron_parser/validator.rb +31 -0
- data/lib/aws_cron_parser/validators/aws_at_validator.rb +28 -0
- data/lib/aws_cron_parser/validators/aws_cron_validator.rb +212 -0
- data/lib/aws_cron_parser/validators/aws_macro_validator.rb +13 -0
- data/lib/aws_cron_parser/validators/aws_rate_validator.rb +17 -0
- data/lib/aws_cron_parser/validators/base.rb +23 -0
- data/lib/aws_cron_parser/validators/quartz_cron_validator.rb +132 -0
- data/lib/aws_cron_parser/version.rb +5 -0
- data/lib/aws_cron_parser.rb +48 -0
- metadata +127 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AWSCronParser
|
|
4
|
+
module Validators
|
|
5
|
+
class AWSCronValidator < Base
|
|
6
|
+
def validate
|
|
7
|
+
validate_aws_cron
|
|
8
|
+
|
|
9
|
+
true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
# Override method inherited from Helpers::CronExpression
|
|
15
|
+
def normalize_source(source)
|
|
16
|
+
normalized = super(source)
|
|
17
|
+
|
|
18
|
+
# Handle 6-field standard with seconds by dropping seconds, to make range validation easier
|
|
19
|
+
tokens = normalized.split(/\s+/)
|
|
20
|
+
if tokens.length == 6 && tokens.none? { |t| t.include?('?') }
|
|
21
|
+
normalized = tokens[1..5].join(' ')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
normalized
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def validate_aws_cron
|
|
28
|
+
fields = validate_cron_wrapper_format(source)
|
|
29
|
+
|
|
30
|
+
# Pull out fields (with/without seconds)
|
|
31
|
+
if fields.length == 6
|
|
32
|
+
minute, hour, dom, month, dow, _year = fields
|
|
33
|
+
else
|
|
34
|
+
_second, minute, hour, dom, month, dow, _year = fields
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Check for invalid modifiers in day-of-month field
|
|
38
|
+
if dom&.include?('#')
|
|
39
|
+
raise ArgumentError, 'day-of-month field cannot contain # (only day-of-week can)'
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Validate ranges for minute, hour, month
|
|
43
|
+
validate_range(minute, 0..59, 'minute')
|
|
44
|
+
validate_range(hour, 0..23, 'hour')
|
|
45
|
+
validate_range(normalize_month_field(month), 1..12, 'month')
|
|
46
|
+
|
|
47
|
+
# Special patterns: nth weekday (#) and last weekday (L)
|
|
48
|
+
if dow&.include?('#')
|
|
49
|
+
validate_special_cron(source, 'nth')
|
|
50
|
+
elsif dow&.include?('L')
|
|
51
|
+
validate_special_cron(source, 'last')
|
|
52
|
+
else
|
|
53
|
+
# Validate weekday_only/day_only constraints
|
|
54
|
+
validate_special_cron(source, 'pattern')
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def validate_cron_wrapper_format(source)
|
|
59
|
+
return nil unless (cron_match = source.match(AWS_CRON_REGEX))
|
|
60
|
+
|
|
61
|
+
content = cron_match[:expression].strip
|
|
62
|
+
fields = content.split(/\s+/)
|
|
63
|
+
|
|
64
|
+
raise ArgumentError, "cron() requires 6 or 7 fields, got #{fields.length}" unless [6, 7].include?(fields.length)
|
|
65
|
+
|
|
66
|
+
# AWS rule: ? cannot be used in both day-of-month and day-of-week
|
|
67
|
+
# Fields order within cron(): [second] minute hour day-of-month month day-of-week year
|
|
68
|
+
# For 6 fields: minute hour day-of-month month day-of-week year (no seconds)
|
|
69
|
+
day_of_month = fields.length == 6 ? fields[2] : fields[3]
|
|
70
|
+
day_of_week = fields.length == 6 ? fields[4] : fields[5]
|
|
71
|
+
if day_of_month == '?' && day_of_week == '?'
|
|
72
|
+
raise ArgumentError, '? can only be used in one of day-of-month or day-of-week fields'
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
year_field = fields[-1]
|
|
76
|
+
raise ArgumentError, 'Year cannot have L, #, or W' if /[L#W]/.match?(year_field)
|
|
77
|
+
|
|
78
|
+
unless /^\*$|^\d+$|^\d+-\d+$|^\d+,\d+$/.match?(year_field)
|
|
79
|
+
raise ArgumentError, 'Year must be *, number, range, or list'
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
fields
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def validate_special_cron(source, type)
|
|
86
|
+
tokens = normalize_source(source).split(/\s+/)
|
|
87
|
+
raise ArgumentError, 'Invalid CRON expression' unless (5..6).cover?(tokens.length)
|
|
88
|
+
|
|
89
|
+
minute, hour, dom, month, dow = tokens.length == 5 ? tokens[0..4] : tokens[1..5]
|
|
90
|
+
|
|
91
|
+
# For non-AWS expressions with special chars, validate ? usage
|
|
92
|
+
unless source.start_with?('cron(')
|
|
93
|
+
invalid_q_mark = false
|
|
94
|
+
[minute, hour, month].each do |field|
|
|
95
|
+
invalid_q_mark = true if field.include?('?')
|
|
96
|
+
end
|
|
97
|
+
if dom.include?('?') && !dow.match?(/[L#]/)
|
|
98
|
+
invalid_q_mark = true
|
|
99
|
+
end
|
|
100
|
+
invalid_q_mark = true if dow.include?('?')
|
|
101
|
+
|
|
102
|
+
raise ArgumentError, '? is not valid in standard CRON expressions' if invalid_q_mark
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
if source.start_with?('cron(') && dom == '?' && dow == '?'
|
|
106
|
+
raise ArgumentError, '? can only be used in one of day-of-month or day-of-week fields'
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
case type
|
|
110
|
+
when 'nth'
|
|
111
|
+
raise ArgumentError, 'day-of-month must be ? or *' unless ['?', '*'].include?(dom)
|
|
112
|
+
|
|
113
|
+
normalized = normalize_weekday_in_nth_spec(dow, is_aws: true)
|
|
114
|
+
match = normalized.match(NTH_WEEKDAY_REGEX)
|
|
115
|
+
raise ArgumentError, "Invalid nth weekday: #{dow}" unless match
|
|
116
|
+
|
|
117
|
+
weekday_num = match[:weekday].to_i
|
|
118
|
+
occurrence_num = match[:occurrence].to_i
|
|
119
|
+
# Allow 0..7 to be tolerant with sources that use 0 for Sunday; AWS uses 1..7, standard may use 0 or 7.
|
|
120
|
+
raise ArgumentError, "weekday must be 0-7, got #{weekday_num}" unless (0..7).cover?(weekday_num)
|
|
121
|
+
raise ArgumentError, "occurrence must be 1-5, got #{occurrence_num}" unless (1..5).cover?(occurrence_num)
|
|
122
|
+
when 'last'
|
|
123
|
+
raise ArgumentError, 'day-of-month must be ? or *' unless ['?', '*'].include?(dom)
|
|
124
|
+
|
|
125
|
+
normalized = normalize_weekday_in_last_spec(dow)
|
|
126
|
+
match = normalized.match(LAST_WEEKDAY_REGEX)
|
|
127
|
+
raise ArgumentError, "Invalid last weekday: #{dow}" unless match
|
|
128
|
+
|
|
129
|
+
weekday_num = match[:weekday].to_i
|
|
130
|
+
raise ArgumentError, "weekday must be 0-7, got #{weekday_num}" unless (0..7).cover?(weekday_num)
|
|
131
|
+
when 'pattern'
|
|
132
|
+
raise ArgumentError, 'day-of-month must be ?' if weekday_only?(source) && dom != '?'
|
|
133
|
+
raise ArgumentError, 'day-of-week must be ?' if day_only?(source) && dow != '?'
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
validate_range(minute, 0..59, 'minute')
|
|
137
|
+
validate_range(hour, 0..23, 'hour')
|
|
138
|
+
validate_range(normalize_month_field(month), 1..12, 'month')
|
|
139
|
+
|
|
140
|
+
# Validate weekday range based on CRON format (skip validation for special patterns)
|
|
141
|
+
# Skip if the dow field contains special modifiers (L, #, W) as they're already validated above
|
|
142
|
+
unless dow.match?(/[L#W]/)
|
|
143
|
+
weekday_range = source.start_with?('cron(') ? 1..7 : 0..6
|
|
144
|
+
validate_range(normalize_weekday_field(dow, is_aws: true), weekday_range, 'day-of-week')
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
true
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def validate_range(field, range, name)
|
|
151
|
+
return if ['*', '?'].include?(field)
|
|
152
|
+
|
|
153
|
+
# Handle step syntax like "*/5" or "0/5"
|
|
154
|
+
if field.include?('/')
|
|
155
|
+
start, step = field.split('/', 2)
|
|
156
|
+
raise ArgumentError, "Invalid step syntax: #{field}" unless start && step
|
|
157
|
+
|
|
158
|
+
# Validate start value if it's not '*' or a range
|
|
159
|
+
unless start == '*' || start.include?('-') || start.include?(',')
|
|
160
|
+
raise ArgumentError, "Invalid start value in step: #{start}" unless start.match?(/^\d+$/)
|
|
161
|
+
|
|
162
|
+
start_val = start.to_i
|
|
163
|
+
raise ArgumentError, "#{name} start value #{start_val} out of range" unless range.include?(start_val)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Validate step value
|
|
167
|
+
raise ArgumentError, "Invalid step value: #{step}" unless step.match?(/^\d+$/)
|
|
168
|
+
|
|
169
|
+
step_val = step.to_i
|
|
170
|
+
raise ArgumentError, "Step value must be positive, got #{step_val}" unless step_val.positive?
|
|
171
|
+
|
|
172
|
+
return
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Handle ranges like "1-5"
|
|
176
|
+
if field.include?('-')
|
|
177
|
+
start_str, end_str = field.split('-', 2)
|
|
178
|
+
raise ArgumentError, "Invalid range syntax: #{field}" unless start_str && end_str
|
|
179
|
+
|
|
180
|
+
start_val = start_str.to_i
|
|
181
|
+
end_val = end_str.to_i
|
|
182
|
+
raise ArgumentError, "#{name} range start #{start_val} out of range" unless range.include?(start_val)
|
|
183
|
+
raise ArgumentError, "#{name} range end #{end_val} out of range" unless range.include?(end_val)
|
|
184
|
+
|
|
185
|
+
# Allow reverse ranges for permissiveness
|
|
186
|
+
|
|
187
|
+
return
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Handle lists like "1,3,5"
|
|
191
|
+
if field.include?(',')
|
|
192
|
+
values = field.split(',')
|
|
193
|
+
values.each do |value_str|
|
|
194
|
+
next if value_str.strip.empty?
|
|
195
|
+
raise ArgumentError, "Invalid list value: #{value_str}" unless value_str.match?(/^\d+$/)
|
|
196
|
+
|
|
197
|
+
value = value_str.to_i
|
|
198
|
+
raise ArgumentError, "#{name} #{value} out of range" unless range.include?(value)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
return
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Handle simple numeric values
|
|
205
|
+
return unless field.match?(/^\d+$/)
|
|
206
|
+
|
|
207
|
+
value = field.to_i
|
|
208
|
+
raise ArgumentError, "#{name} #{value} out of range" unless range.include?(value)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AWSCronParser
|
|
4
|
+
module Validators
|
|
5
|
+
class AWSRateValidator < Base
|
|
6
|
+
def validate
|
|
7
|
+
match = source.match(RATE_REGEX)
|
|
8
|
+
raise ArgumentError, 'Invalid rate expression' unless match
|
|
9
|
+
|
|
10
|
+
value = match[1].to_i
|
|
11
|
+
raise ArgumentError, 'Rate value must be positive' if value <= 0
|
|
12
|
+
|
|
13
|
+
true
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AWSCronParser
|
|
4
|
+
module Validators
|
|
5
|
+
class Base
|
|
6
|
+
include AWSCronParser::Helpers
|
|
7
|
+
|
|
8
|
+
attr_reader :source
|
|
9
|
+
|
|
10
|
+
def initialize(source)
|
|
11
|
+
@source = source
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.validate(source)
|
|
15
|
+
new(source).validate
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def validate
|
|
19
|
+
raise NotImplementedError, 'This method should be implemented in a subclass'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module AWSCronParser
|
|
4
|
+
module Validators
|
|
5
|
+
class QuartzCronValidator < Base
|
|
6
|
+
def validate
|
|
7
|
+
parts = @source.split
|
|
8
|
+
|
|
9
|
+
# Validate field count (5 or 6 fields)
|
|
10
|
+
unless (5..6).cover?(parts.length)
|
|
11
|
+
raise ArgumentError, "Invalid CRON format: expected 5 or 6 fields, got #{parts.length}"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Define field ranges and names
|
|
15
|
+
field_ranges = if parts.length == 6
|
|
16
|
+
[{ min: 0, max: 59, name: 'second' },
|
|
17
|
+
{ min: 0, max: 59, name: 'minute' },
|
|
18
|
+
{ min: 0, max: 23, name: 'hour' },
|
|
19
|
+
{ min: 1, max: 31, name: 'day-of-month' },
|
|
20
|
+
{ min: 1, max: 12, name: 'month' },
|
|
21
|
+
{ min: 0, max: 7, name: 'day-of-week' }]
|
|
22
|
+
else
|
|
23
|
+
[{ min: 0, max: 59, name: 'minute' },
|
|
24
|
+
{ min: 0, max: 23, name: 'hour' },
|
|
25
|
+
{ min: 1, max: 31, name: 'day-of-month' },
|
|
26
|
+
{ min: 1, max: 12, name: 'month' },
|
|
27
|
+
{ min: 0, max: 7, name: 'day-of-week' }]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Check for AWS-specific characters and validate ranges
|
|
31
|
+
aws_chars = %w[L W # ?]
|
|
32
|
+
parts.each_with_index do |field, index|
|
|
33
|
+
range_info = field_ranges[index]
|
|
34
|
+
field_name = range_info[:name]
|
|
35
|
+
|
|
36
|
+
# Normalize month and weekday fields before validation
|
|
37
|
+
normalized_field = if field_name == 'month'
|
|
38
|
+
normalize_month_field(field)
|
|
39
|
+
elsif field_name == 'day-of-week'
|
|
40
|
+
normalize_weekday_field(field, is_aws: false)
|
|
41
|
+
else
|
|
42
|
+
field
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Check for AWS-specific characters
|
|
46
|
+
aws_chars.each do |char|
|
|
47
|
+
next unless field.include?(char)
|
|
48
|
+
|
|
49
|
+
msg = "#{field_name} field cannot contain '#{char}'. " \
|
|
50
|
+
'Use cron() wrapper for AWS expressions.'
|
|
51
|
+
raise ArgumentError, msg
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Validate numeric values in ranges (simple check for obvious errors)
|
|
55
|
+
validate_field_values(normalized_field, range_info)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Use FugitAdapter for comprehensive validation
|
|
59
|
+
AWSCronParser::FugitAdapter.new(@source)
|
|
60
|
+
true
|
|
61
|
+
rescue ArgumentError => e
|
|
62
|
+
raise ArgumentError, e.message
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
# Validate individual numeric values in a field
|
|
68
|
+
def validate_field_values(field, range_info)
|
|
69
|
+
return if ['*', '?'].include?(field) # Wildcard/question mark is always valid
|
|
70
|
+
|
|
71
|
+
min_val = range_info[:min]
|
|
72
|
+
max_val = range_info[:max]
|
|
73
|
+
field_name = range_info[:name]
|
|
74
|
+
|
|
75
|
+
# Parse and validate each value (simple approach, let fugit handle complex cases)
|
|
76
|
+
field.split(',').each do |part|
|
|
77
|
+
part = part.strip
|
|
78
|
+
next if part.empty?
|
|
79
|
+
|
|
80
|
+
# Check for step of 0 (will cause ZeroDivisionError in fugit)
|
|
81
|
+
if part.include?('/')
|
|
82
|
+
step_parts = part.split('/')
|
|
83
|
+
step_val = step_parts[-1].to_i
|
|
84
|
+
|
|
85
|
+
raise ArgumentError, "Step value must be positive, got #{step_val}" if step_val.zero?
|
|
86
|
+
|
|
87
|
+
# For ranges like "1-30/0", also check if start is in range
|
|
88
|
+
if step_parts[0].include?('-')
|
|
89
|
+
range_start, range_end = step_parts[0].split('-').map(&:to_i)
|
|
90
|
+
unless (min_val..max_val).cover?(range_start)
|
|
91
|
+
raise ArgumentError, "#{field_name} #{range_start} out of range"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
unless (min_val..max_val).cover?(range_end)
|
|
95
|
+
raise ArgumentError, "#{field_name} #{range_end} out of range"
|
|
96
|
+
end
|
|
97
|
+
elsif step_parts[0] != '*' && step_parts[0] != '?'
|
|
98
|
+
start_val = step_parts[0].to_i
|
|
99
|
+
unless (min_val..max_val).cover?(start_val)
|
|
100
|
+
raise ArgumentError, "#{field_name} #{start_val} out of range"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
next
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Handle ranges like "1-5"
|
|
108
|
+
if part.include?('-')
|
|
109
|
+
range_start, range_end = part.split('-').map(&:to_i)
|
|
110
|
+
unless (min_val..max_val).cover?(range_start)
|
|
111
|
+
raise ArgumentError, "#{field_name} #{range_start} out of range"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
unless (min_val..max_val).cover?(range_end)
|
|
115
|
+
raise ArgumentError, "#{field_name} #{range_end} out of range"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
next
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Single numeric value
|
|
122
|
+
val = part.to_i
|
|
123
|
+
next if val.zero? && part != '0' # Not a number, fugit will catch it
|
|
124
|
+
|
|
125
|
+
unless (min_val..max_val).cover?(val)
|
|
126
|
+
raise ArgumentError, "#{field_name} #{val} out of range"
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'date'
|
|
4
|
+
require 'set'
|
|
5
|
+
require 'yaml'
|
|
6
|
+
require 'fugit'
|
|
7
|
+
require 'zeitwerk'
|
|
8
|
+
# The whole core_ext set, not a hand-picked subset: this code was extracted from
|
|
9
|
+
# a Rails app and leans on blank?/present?/exclude?/delegate/durations/Time.zone
|
|
10
|
+
# across paths the suite does not all cover. The AS framework itself stays out.
|
|
11
|
+
require 'active_support'
|
|
12
|
+
require 'active_support/core_ext'
|
|
13
|
+
|
|
14
|
+
loader = Zeitwerk::Loader.for_gem
|
|
15
|
+
loader.inflector.inflect(
|
|
16
|
+
'aws_cron_parser' => 'AWSCronParser',
|
|
17
|
+
'aws_at' => 'AWSAt',
|
|
18
|
+
'aws_cron' => 'AWSCron',
|
|
19
|
+
'aws_rate' => 'AWSRate',
|
|
20
|
+
'aws_at_validator' => 'AWSAtValidator',
|
|
21
|
+
'aws_cron_validator' => 'AWSCronValidator',
|
|
22
|
+
'aws_macro_validator' => 'AWSMacroValidator',
|
|
23
|
+
'aws_rate_validator' => 'AWSRateValidator'
|
|
24
|
+
)
|
|
25
|
+
loader.ignore("#{__dir__}/aws_cron_parser/version.rb")
|
|
26
|
+
loader.setup
|
|
27
|
+
|
|
28
|
+
require_relative 'aws_cron_parser/version'
|
|
29
|
+
|
|
30
|
+
# ActiveSupport leaves Time.zone nil until a host application sets it, and the
|
|
31
|
+
# parsers build zone-aware times. Default it to UTC so the gem works outside
|
|
32
|
+
# Rails; Rails' own time zone initializer runs later and overrides this.
|
|
33
|
+
Time.zone_default ||= ActiveSupport::TimeZone['UTC']
|
|
34
|
+
|
|
35
|
+
module AWSCronParser
|
|
36
|
+
def self.new(expression, time_source = Time)
|
|
37
|
+
Parser.new(expression, time_source)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.parse(...)
|
|
41
|
+
new(...)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Exposed so hosts that boot eagerly (or the test suite) can force every
|
|
46
|
+
# constant to resolve instead of discovering a bad autoload path at runtime.
|
|
47
|
+
AWSCronParser::LOADER = loader
|
|
48
|
+
|
metadata
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: aws-cron-parser
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Washington Silva
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: activesupport
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '7.1'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '7.1'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: fugit
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '1.11'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '1.11'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: zeitwerk
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '2.6'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '2.6'
|
|
54
|
+
description: |-
|
|
55
|
+
AWSCronParser parses the scheduling expressions accepted by AWS EventBridge and
|
|
56
|
+
Systems Manager - cron(...) with 6 fields, rate(...), @macros and at(...) - as well
|
|
57
|
+
as Quartz and standard 5-field CRON. It computes next/previous occurrences, validates
|
|
58
|
+
expressions with actionable error messages, and renders them as English descriptions
|
|
59
|
+
such as "Every weekday at 9:00 AM".
|
|
60
|
+
email:
|
|
61
|
+
- washington.silva@skie.io
|
|
62
|
+
executables: []
|
|
63
|
+
extensions: []
|
|
64
|
+
extra_rdoc_files: []
|
|
65
|
+
files:
|
|
66
|
+
- CHANGELOG.md
|
|
67
|
+
- LICENSE.txt
|
|
68
|
+
- README.md
|
|
69
|
+
- lib/aws_cron_parser.rb
|
|
70
|
+
- lib/aws_cron_parser/describer.rb
|
|
71
|
+
- lib/aws_cron_parser/describer/cron_composer.rb
|
|
72
|
+
- lib/aws_cron_parser/describer/day_composer.rb
|
|
73
|
+
- lib/aws_cron_parser/describer/field_describers/base.rb
|
|
74
|
+
- lib/aws_cron_parser/describer/field_describers/day_of_month.rb
|
|
75
|
+
- lib/aws_cron_parser/describer/field_describers/day_of_week.rb
|
|
76
|
+
- lib/aws_cron_parser/describer/field_describers/month.rb
|
|
77
|
+
- lib/aws_cron_parser/describer/field_describers/time_field.rb
|
|
78
|
+
- lib/aws_cron_parser/describer/month_composer.rb
|
|
79
|
+
- lib/aws_cron_parser/describer/template.en.yml
|
|
80
|
+
- lib/aws_cron_parser/describer/template.rb
|
|
81
|
+
- lib/aws_cron_parser/describer/time_composer.rb
|
|
82
|
+
- lib/aws_cron_parser/fugit_adapter.rb
|
|
83
|
+
- lib/aws_cron_parser/helpers.rb
|
|
84
|
+
- lib/aws_cron_parser/helpers/calendar.rb
|
|
85
|
+
- lib/aws_cron_parser/helpers/clock.rb
|
|
86
|
+
- lib/aws_cron_parser/helpers/cron_expression.rb
|
|
87
|
+
- lib/aws_cron_parser/helpers/numbers.rb
|
|
88
|
+
- lib/aws_cron_parser/parser.rb
|
|
89
|
+
- lib/aws_cron_parser/parsers/aws_at.rb
|
|
90
|
+
- lib/aws_cron_parser/parsers/aws_cron.rb
|
|
91
|
+
- lib/aws_cron_parser/parsers/aws_rate.rb
|
|
92
|
+
- lib/aws_cron_parser/parsers/base.rb
|
|
93
|
+
- lib/aws_cron_parser/parsers/quartz_cron.rb
|
|
94
|
+
- lib/aws_cron_parser/validator.rb
|
|
95
|
+
- lib/aws_cron_parser/validators/aws_at_validator.rb
|
|
96
|
+
- lib/aws_cron_parser/validators/aws_cron_validator.rb
|
|
97
|
+
- lib/aws_cron_parser/validators/aws_macro_validator.rb
|
|
98
|
+
- lib/aws_cron_parser/validators/aws_rate_validator.rb
|
|
99
|
+
- lib/aws_cron_parser/validators/base.rb
|
|
100
|
+
- lib/aws_cron_parser/validators/quartz_cron_validator.rb
|
|
101
|
+
- lib/aws_cron_parser/version.rb
|
|
102
|
+
homepage: https://github.com/w-osilva/aws-cron-parser
|
|
103
|
+
licenses:
|
|
104
|
+
- MIT
|
|
105
|
+
metadata:
|
|
106
|
+
source_code_uri: https://github.com/w-osilva/aws-cron-parser
|
|
107
|
+
changelog_uri: https://github.com/w-osilva/aws-cron-parser/blob/main/CHANGELOG.md
|
|
108
|
+
rubygems_mfa_required: 'true'
|
|
109
|
+
rdoc_options: []
|
|
110
|
+
require_paths:
|
|
111
|
+
- lib
|
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - ">="
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: 3.2.0
|
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
|
+
requirements:
|
|
119
|
+
- - ">="
|
|
120
|
+
- !ruby/object:Gem::Version
|
|
121
|
+
version: '0'
|
|
122
|
+
requirements: []
|
|
123
|
+
rubygems_version: 3.6.9
|
|
124
|
+
specification_version: 4
|
|
125
|
+
summary: Parser, validator and human-readable describer for AWS, Quartz and standard
|
|
126
|
+
CRON expressions
|
|
127
|
+
test_files: []
|