philiprehberger-cron_parser 0.3.0 → 0.5.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: d11c034aa656522a0e2ca5e145ca68f974b1b0eb9aeafad15797ee5a53d859f1
4
- data.tar.gz: 874e7abb865fa66511d7a407e7e0cc4ea0dfd8e8a637ff75225cffc9db5f0206
3
+ metadata.gz: 2d7e8b08d65ab34dacc640a348cd965a7a604840a0a5c10ad13327740ddb323e
4
+ data.tar.gz: 353889bda7ae0edd7074fc0a3a84056dff6ca731ab5daa65fa4c4ace54cedacf
5
5
  SHA512:
6
- metadata.gz: c8053224dd61f4defd352fbdf106351f995de7b16b6f10b610a40e99c47f577c0b27d241587aa74cd4299da2d7a4601c6879844eb63d68ce47dfcaa383ce5847
7
- data.tar.gz: f830772d6a686fec8dcf8f857a68b4be1f162bf70f0ebde4146f7228b44f5aadc18dbe567ce8570fcd4d5c5fa3125ab2ef56313978cec0320caa5b7796d458b5
6
+ metadata.gz: b3a8cef0c91c1f4056005b846d1b1d9960abca68cb1821c1fe602b9d4f8e9b73e4d70df8b11fd4971b46e0f4c65fbd9bfa6c466713f3a664037f1b373de93821
7
+ data.tar.gz: a89b2d2bef776c9f2ff5f0edba5fd163db301e0566ed0a9a6062b5af2633ec45731f90fae38e46ef4a4cf7f376804b7a21f6bff9f42b334527214cd540e4ceb8
data/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.5.0] - 2026-05-12
11
+
12
+ ### Added
13
+ - `Expression#each_in(from:, to:, &block)` iterator over every matching occurrence in an inclusive window; returns an Enumerator when no block is given so callers can chain `Enumerable` methods like `first`, `take`, and `lazy`
14
+
15
+ ## [0.4.0] - 2026-04-30
16
+
17
+ ### Added
18
+ - `Expression#count_in(from:, to:)` returns the number of times the expression matches within an inclusive time window — useful for capacity planning and alert tuning
19
+
10
20
  ## [0.3.0] - 2026-04-09
11
21
 
12
22
  ### Added
data/README.md CHANGED
@@ -49,6 +49,29 @@ cron.matches?(Time.new(2026, 3, 22, 9, 0, 0)) # => true
49
49
  cron.matches?(Time.new(2026, 3, 22, 10, 0, 0)) # => false
50
50
  ```
51
51
 
52
+ ### Counting Occurrences in a Window
53
+
54
+ ```ruby
55
+ cron = Philiprehberger::CronParser.new('*/15 * * * *')
56
+ from = Time.new(2026, 4, 30, 9, 0, 0)
57
+ to = Time.new(2026, 4, 30, 10, 0, 0)
58
+ cron.count_in(from: from, to: to) # => 5
59
+ ```
60
+
61
+ ### Iterating Occurrences in a Window
62
+
63
+ ```ruby
64
+ cron = Philiprehberger::CronParser.new('*/15 * * * *')
65
+ from = Time.new(2026, 4, 30, 9, 0, 0)
66
+ to = Time.new(2026, 4, 30, 10, 0, 0)
67
+
68
+ cron.each_in(from: from, to: to) { |t| puts t }
69
+
70
+ # Without a block, returns an Enumerator
71
+ cron.each_in(from: from, to: to).first(2)
72
+ # => [2026-04-30 09:00:00, 2026-04-30 09:15:00]
73
+ ```
74
+
52
75
  ### Human-Readable Description
53
76
 
54
77
  ```ruby
@@ -118,6 +141,8 @@ Philiprehberger::CronParser.new('0 9 * * MON-FRI') # named weekdays
118
141
  | `Expression#next(from:)` | Calculate the next matching time |
119
142
  | `Expression#prev(from:)` | Calculate the previous matching time |
120
143
  | `Expression#next_n(n, from:)` | Calculate the next N matching times |
144
+ | `Expression#count_in(from:, to:)` | Count occurrences within an inclusive `[from, to]` window |
145
+ | `Expression#each_in(from:, to:, &block)` | Yield each matching occurrence in `[from, to]`; returns an Enumerator without a block |
121
146
  | `Expression#matches?(time)` | Check if a time matches the expression |
122
147
  | `Expression#human_readable` | Human-readable description of the expression |
123
148
  | `Expression#description` | Alias for `human_readable` |
@@ -106,6 +106,56 @@ module Philiprehberger
106
106
  results
107
107
  end
108
108
 
109
+ # Count occurrences within a time window [from, to].
110
+ #
111
+ # The window is inclusive on both ends; `from` is treated as the cursor's
112
+ # starting point so an exact match at `from` counts only if it lies on a
113
+ # minute boundary that the schedule fires on.
114
+ #
115
+ # @param from [Time] start of the window
116
+ # @param to [Time] end of the window
117
+ # @return [Integer] the count of occurrences in the window
118
+ # @raise [Error] if `to` is earlier than `from`
119
+ def count_in(from:, to:)
120
+ raise Error, '`to` must be greater than or equal to `from`' if to < from
121
+
122
+ count = 0
123
+ cursor = round_to_minute(from) - 60
124
+ loop do
125
+ cursor = self.next(from: cursor)
126
+ break if cursor > to
127
+
128
+ count += 1
129
+ end
130
+ count
131
+ end
132
+
133
+ # Iterate every matching time within an inclusive `[from, to]` window.
134
+ #
135
+ # When called with a block, yields each occurrence and returns `self`.
136
+ # Without a block, returns an `Enumerator` so callers can chain `Enumerable`
137
+ # methods (`take`, `lazy`, `to_a`, ...).
138
+ #
139
+ # @param from [Time] start of the window
140
+ # @param to [Time] end of the window
141
+ # @yieldparam time [Time] a matching occurrence
142
+ # @return [self, Enumerator] self when a block is given, otherwise an Enumerator
143
+ # @raise [Error] if `to` is earlier than `from`
144
+ def each_in(from:, to:, &block)
145
+ raise Error, '`to` must be greater than or equal to `from`' if to < from
146
+
147
+ return enum_for(:each_in, from: from, to: to) unless block
148
+
149
+ cursor = round_to_minute(from) - 60
150
+ loop do
151
+ cursor = self.next(from: cursor)
152
+ break if cursor > to
153
+
154
+ block.call(cursor)
155
+ end
156
+ self
157
+ end
158
+
109
159
  # Return a human-readable description of the expression
110
160
  #
111
161
  # @return [String]
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Philiprehberger
4
4
  module CronParser
5
- VERSION = '0.3.0'
5
+ VERSION = '0.5.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: philiprehberger-cron_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philip Rehberger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-04-09 00:00:00.000000000 Z
11
+ date: 2026-05-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Parse standard 5-field cron expressions and calculate next/previous occurrences,
14
14
  match times against patterns, and generate human-readable descriptions.