cron_calc 0.4.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29ac47b06a1dc188f3fb9ed5c10f9fa1a6ef748e8d15a6783eb7b8f99de85b38
4
- data.tar.gz: 8f136ff6c1010357acd75942e80bc7d4a2f4b0d1b8555041486f1cc9bdd97f00
3
+ metadata.gz: aebec718fd55bb74df49580abe4309a41ad0246b2c266a143f9dfac807cd436e
4
+ data.tar.gz: 1b47dea7541f369800f1f816fdf2160e0721de4a4f8bcdd9434c0b77fdf85876
5
5
  SHA512:
6
- metadata.gz: 38f8b7a5a0f80d10f6c4867a8a2e687b9ebb508c5e79031856cbb9bc81a9a97b6f399e0b37f332f5ec5aeb7d2839e29d11b6e76b0fdc5601b675a6a5ed82e806
7
- data.tar.gz: d1545c32cd0559370fc1778c3517567ee0be5f4fecf41ad32af0a2a3fd3202d52f0b9d5014f202ab736c8174675d2c7692610fa72968f247022082aa7a2b5567
6
+ metadata.gz: f6f3349709b4a5babb3d2267f7e8cf1a7e2e51d9a118044e67743cc02b31d34bf5d637b068e825afe9f10c24e34c97a906730363a2c1c309eb003408b2c48586
7
+ data.tar.gz: fd80e141fd67e56adb122b6acf2dbbeff5572e69868212c749d1f6d67c422d70790a9910cec991a2ef328841f8fea17e2214c6276761124f5e4630f04c613557
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## [1.0.0] - 2023-12-28
2
+
3
+ - Add support for predefined definitions
4
+ - Add support for joining ,-
5
+
1
6
  ## [0.4.0] - 2023-12-22
2
7
 
3
8
  - Added support for named months and wdays
@@ -5,7 +10,7 @@
5
10
 
6
11
  ## [0.3.0] - 2023-12-22
7
12
 
8
- - Added support for DOWs
13
+ - Added support for DOWs (wdays)
9
14
 
10
15
  ## [0.2.0] - 2023-12-19
11
16
 
data/README.md CHANGED
@@ -1,6 +1,11 @@
1
1
  # CronCalc
2
2
 
3
- CronCalc: A Ruby gem for calculating and analyzing scheduled CRON job occurrences and timings within specified intervals.
3
+ **CronCalc**: A Ruby gem for calculating CRON job occurrences. With this gem, you can easily determine when a cron job will occur by providing a cron expression. Key features include the ability to **calculate occurrences**:
4
+ - **Within a specified period**: Find out all the times your cron job will run during a particular timeframe.
5
+ - **After a given date**: Determine the next set of occurrences after a specific starting point.
6
+ - **Before a given date**: Discover when your cron job ran or would have run before a certain date.
7
+
8
+ This tool can be used for scheduling, forecasting, and analyzing tasks in systems that use cron for job scheduling.
4
9
 
5
10
  ## Installation
6
11
 
@@ -68,10 +73,21 @@ Calculates the last 'n' occurrences of the cron job until a given end time.\
68
73
  # => [2023-12-31 05:05:00 +0100, 2023-12-30 05:05:00 +0100, 2023-12-29 05:05:00 +0100, 2023-12-28 05:05:00 +0100]
69
74
  ```
70
75
 
71
- ## Unsupported features
76
+ ### Other examples
77
+
78
+ ```ruby
79
+ # You can omit the count parameter
80
+ CronCalc.new('5 5 */5 * SUN').last(before: Time.new(2020, 1, 1, 0, 0))
81
+ # => [2019-12-01 05:05:00 +0100]
72
82
 
73
- - Joining characters , - /
74
- - Predefined definitions (@yearly, @monthly, @weekly, @daily, @midnight, @hourly)
83
+ # You can combine ',' and '-'
84
+ CronCalc.new('5 5 5-7,10 FEB *').next(5)
85
+ # => [2024-02-05 05:05:00 +0100, 2024-02-06 05:05:00 +0100, 2024-02-07 05:05:00 +0100, 2024-02-10 05:05:00 +0100, 2025-02-05 05:05:00 +0100]
86
+
87
+ # You can use predefined definitions like @daily, @monthly, etc.
88
+ CronCalc.new('@monthly').next(3, after: Time.new(2024, 1, 1, 0, 0))
89
+ # => [2024-01-01 00:00:00 +0100, 2024-02-01 00:00:00 +0100, 2024-03-01 00:00:00 +0100]
90
+ ```
75
91
 
76
92
  ## Contributing
77
93
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CronCalc
4
- VERSION = '0.4.0'
4
+ VERSION = '1.0.0'
5
5
  end
data/lib/cron_calc.rb CHANGED
@@ -7,6 +7,33 @@ require 'time'
7
7
  module CronCalc
8
8
  class Error < StandardError; end
9
9
 
10
+ RANGE = {
11
+ minutes: 0..59,
12
+ hours: 0..23,
13
+ days: 1..31,
14
+ months: 1..12,
15
+ wdays: 0..6
16
+ }.freeze
17
+
18
+ WDAYS = {
19
+ 'SUN' => '0', 'MON' => '1', 'TUE' => '2', 'WED' => '3',
20
+ 'THU' => '4', 'FRI' => '5', 'SAT' => '6'
21
+ }.freeze
22
+
23
+ MONTHS = {
24
+ 'JAN' => '1', 'FEB' => '2', 'MAR' => '3', 'APR' => '4',
25
+ 'MAY' => '5', 'JUN' => '6', 'JUL' => '7', 'AUG' => '8',
26
+ 'SEP' => '9', 'OCT' => '10', 'NOV' => '11', 'DEC' => '12'
27
+ }.freeze
28
+
29
+ PREDEFINED_DEFINITIONS = {
30
+ '@yearly' => '0 0 1 1 *', '@annually' => '0 0 1 1 *',
31
+ '@monthly' => '0 0 1 * *',
32
+ '@weekly' => '0 0 * * 0',
33
+ '@daily' => '0 0 * * *', '@midnight' => '0 0 * * *',
34
+ '@hourly' => '0 * * * *'
35
+ }.freeze
36
+
10
37
  def self.new(cron_string)
11
38
  Parser.new(cron_string)
12
39
  end
@@ -17,30 +44,12 @@ module CronCalc
17
44
  class Parser
18
45
  attr_reader :cron_string, :cron_parts
19
46
 
20
- RANGE = {
21
- minutes: 0..59,
22
- hours: 0..23,
23
- days: 1..31,
24
- months: 1..12,
25
- wdays: 0..6
26
- }.freeze
27
-
28
- WDAYS = {
29
- 'SUN' => '0', 'MON' => '1', 'TUE' => '2', 'WED' => '3',
30
- 'THU' => '4', 'FRI' => '5', 'SAT' => '6'
31
- }.freeze
32
-
33
- MONTHS = {
34
- 'JAN' => '1', 'FEB' => '2', 'MAR' => '3', 'APR' => '4',
35
- 'MAY' => '5', 'JUN' => '6', 'JUL' => '7', 'AUG' => '8',
36
- 'SEP' => '9', 'OCT' => '10', 'NOV' => '11', 'DEC' => '12'
37
- }.freeze
38
-
39
47
  def initialize(cron_string)
40
48
  @cron_string = cron_string
41
49
 
42
50
  raise 'Cron expression is not supported or invalid' unless cron_string_valid?
43
51
 
52
+ @cron_string = normalize_with(cron_string, PREDEFINED_DEFINITIONS) if @cron_string.start_with? '@'
44
53
  @cron_parts = split_cron_string
45
54
  end
46
55
 
@@ -114,35 +123,40 @@ module CronCalc
114
123
  %i[minutes hours days months].map { |unit| parse_cron_part(unit) }
115
124
  end
116
125
 
117
- # rubocop:disable Metrics
118
126
  def parse_cron_part(time_unit)
119
127
  range = RANGE[time_unit]
120
128
  part = cron_parts[time_unit]
121
129
 
122
- case part
130
+ if part.include?(',')
131
+ part.split(',').flat_map { |e| parse_single_element(e, range) }.uniq.sort
132
+ else
133
+ parse_single_element(part, range)
134
+ end
135
+ end
136
+
137
+ def parse_single_element(element, range)
138
+ case element
123
139
  when '*'
124
140
  range.to_a
125
- when /,/
126
- part.split(',').map(&:to_i)
127
141
  when /-/
128
- (part.split('-').first.to_i..part.split('-').last.to_i).to_a
142
+ (element.split('-').first.to_i..element.split('-').last.to_i).to_a
129
143
  when %r{/}
130
- range.step(part.split('/').last.to_i).to_a
144
+ range.step(element.split('/').last.to_i).to_a
131
145
  else
132
- [part.to_i]
146
+ [element.to_i]
133
147
  end
134
148
  end
135
- # rubocop:enable Metrics
136
149
 
137
150
  def normalize_with(string, mapping)
138
151
  mapping.inject(string) { |str, (k, v)| str.gsub(k, v) }
139
152
  end
140
153
 
141
154
  def cron_string_valid?
155
+ predefined = /\A@(yearly|annually|monthly|weekly|daily|midnight|hourly)\z/
142
156
  # rubocop:disable Layout/LineLength
143
- regex = %r{\A(\*|([0-5]?\d)(,([0-5]?\d))*|(\*/\d+)|(\d+-\d+)) (\*|([01]?\d|2[0-3])(,([01]?\d|2[0-3]))*|(\*/\d+)|(\d+-\d+)) (\*|([12]?\d|3[01])(,([12]?\d|3[01]))*|(\*/\d+)|(\d+-\d+)) (\*|(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC|[1-9]|1[0-2])(,(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC|[1-9]|1[0-2])|-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))*|(\*/\d+)|(\d+-\d+)) (\*|(SUN|MON|TUE|WED|THU|FRI|SAT|[0-6])(,(SUN|MON|TUE|WED|THU|FRI|SAT|[0-6])|-(SUN|MON|TUE|WED|THU|FRI|SAT))*|(\*/[0-6]+)|([0-6]-[0-6]))\z}
157
+ standard = %r{\A(\*|(\*/[0-5]?\d)|([0-5]?\d)(-(?:[0-5]?\d))?(,([0-5]?\d)(-(?:[0-5]?\d))?)*) (\*|(\*/[01]?\d|2[0-3])|([01]?\d|2[0-3])(-(?:[01]?\d|2[0-3]))?(,([01]?\d|2[0-3])(-(?:[01]?\d|2[0-3]))?)*|(\*/\d+)) (\*|(\*/[12]?\d|3[01])|([12]?\d|3[01])(-(?:[12]?\d|3[01]))?(,([12]?\d|3[01])(-(?:[12]?\d|3[01]))?)*|(\*/\d+)) (\*|(\*/[1-9]|1[0-2])|(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC|[1-9]|1[0-2])(-(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC|[1-9]|1[0-2]))?(,(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC|[1-9]|1[0-2])(-(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC|[1-9]|1[0-2]))?)*|(\*/\d+)) (\*|(\*/[0-6])|(SUN|MON|TUE|WED|THU|FRI|SAT|[0-6])(-(?:SUN|MON|TUE|WED|THU|FRI|SAT|[0-6]))?(,(SUN|MON|TUE|WED|THU|FRI|SAT|[0-6])(-(?:SUN|MON|TUE|WED|THU|FRI|SAT|[0-6]))?)*|(\*/[0-6]+))\z}
144
158
  # rubocop:enable Layout/LineLength
145
- cron_string.match?(regex)
159
+ cron_string.match?(predefined) || cron_string.match?(standard)
146
160
  end
147
161
  end
148
162
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cron_calc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakub Miziński
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-12-22 00:00:00.000000000 Z
11
+ date: 2023-12-28 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |-
14
14
  Calculates cron job occurrences within a specified period