periodoxical 0.7.3 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 63ed27b7ac9376b1cd35d505dbcf13c6637e47a8bee5983aa8697a389c2423ee
4
- data.tar.gz: df71967f5be8771b0bda25c4b6352f922a82bac39a546f2f66e04247a41ea3cb
3
+ metadata.gz: 1028e4261c9759e49e7446a1ff506fcb4d3b789b4bdd1ef40dbec0bd8df18ae8
4
+ data.tar.gz: c7dece06fabe86ede77b98203bea7716d0d1e039393f1e6e693c8a232615ef01
5
5
  SHA512:
6
- metadata.gz: ce019309287e5c8d065e77ce9cdc31348c12d867ba9140a43cfb2da2a086a647dcfd0ef0e1a801c11b41f3794fb0b056d695a7f079ad87e5e77e75bae1646bc2
7
- data.tar.gz: f8ae7b9cdc4e395618665f5b625624418bdc8d343fdc4e4dccd7aa8af9672671d2d02230d344193ac016ab1ada3468f3e9089b7fcc3b41a110f974d04c5f1486
6
+ metadata.gz: '08dc98ece1a24ed33564c60f32c31fcf76defddbab51fbf2c0c3df04b296759767fc1dde8a4ed744a24b700fe812ce97bcdc06c052c382e61872c55426116258'
7
+ data.tar.gz: c8edb8ea410b88c5888edda103752c27c149e4e06421b74fb7c4a29ed0f09ae32726536ed495702156b8e6e054da0a5140e1a3487bbbac4468abb94ed7cfb79f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- periodoxical (0.7.3)
4
+ periodoxical (0.9.3)
5
5
  tzinfo (~> 2.0, >= 2.0.0)
6
6
  week_of_month (= 1.2.6)
7
7
 
data/README.md CHANGED
@@ -186,7 +186,7 @@ Periodoxical.generate(
186
186
 
187
187
  ### Example 5 - when specifying time blocks using day-of-month and/or week-of-month and/or month.
188
188
 
189
- As a Ruby dev, I want to generate the next 3 slots for **8AM - 9AM** for the **5th** and **10th** day of every month starting from **June**
189
+ As a Ruby dev, I want to generate the next 3 timeblocks for **8AM - 9AM** for the **5th** and **10th** day of every month starting from **June**
190
190
 
191
191
  ```rb
192
192
  Periodoxical.generate(
@@ -215,7 +215,7 @@ Periodoxical.generate(
215
215
  ]
216
216
  ```
217
217
 
218
- As a Ruby dev, I want to generate **4** slots for **8AM - 9AM** on **Mondays** but only in the **first two weeks** in the months of **April, May, and June**
218
+ As a Ruby dev, I want to generate **4** timeblocks for **8AM - 9AM** on **Mondays** but only in the **first two weeks** in the months of **April, May, and June**
219
219
 
220
220
  ```
221
221
  Periodoxical.generate(
@@ -251,7 +251,7 @@ Periodoxical.generate(
251
251
  ```
252
252
 
253
253
  ### Example 6 - Specify nth day-of-week in month (ie. first Monday of the Month, second Tuesday of the Month, last Friday of Month)
254
- As a Ruby dev, I want to generate slots for **8AM - 9AM** on the **first and second Mondays** and **last Fridays** of every month starting in June 2024. I can do this with the `nth_day_of_week_in_month` param.
254
+ As a Ruby dev, I want to generate timeblocks for **8AM - 9AM** on the **first and second Mondays** and **last Fridays** of every month starting in June 2024. I can do this with the `nth_day_of_week_in_month` param.
255
255
 
256
256
  ```rb
257
257
  Periodoxical.generate(
@@ -291,8 +291,8 @@ Periodoxical.generate(
291
291
  ]
292
292
  ```
293
293
 
294
- ### Example 7 - Exclude time blocks using the `exclusion_dates` parameter
295
- As a Ruby dev, I want to generate slots for **8AM - 9AM** on **Mondays**, except for the **Monday of June 10, 2024**.
294
+ ### Example 7 - Exclude time blocks using the `exclusion_dates` and `exclusion_times` parameters
295
+ As a Ruby dev, I want to generate timeblocks for **8AM - 9AM** on **Mondays**, except for the **Monday of June 10, 2024**.
296
296
 
297
297
  ```rb
298
298
  Periodoxical.generate(
@@ -328,6 +328,127 @@ Periodoxical.generate(
328
328
  ]
329
329
  ```
330
330
 
331
+ As a Ruby dev, I want to generate timeblocks for **8AM - 9AM**, and **10AM - 11AM** on **Mondays**, except for those that conflict (meaning overlap) with the time block of **10:30AM - 11:30AM** on the **Monday of June 10, 2024**. I can skip the conflicting time blocks by using the `exclusion_times` parameter.
332
+
333
+ ```rb
334
+ Periodoxical.generate(
335
+ time_zone: 'America/Los_Angeles',
336
+ start_date: '2024-06-3',
337
+ limit: 4,
338
+ days_of_week: %(mon),
339
+ time_blocks: [
340
+ { start_time: '8:00AM', end_time: '9:00AM' },
341
+ { start_time: '10:00AM', end_time: '11:00AM' },
342
+ ],
343
+ exclusion_times: [
344
+ {
345
+ start: '2024-06-10T10:30:00-07:00',
346
+ end: '2024-06-10T11:30:00-07:00',
347
+ }
348
+ ],
349
+ )
350
+ # =>
351
+ [
352
+ {
353
+ start: #<DateTime 2024-06-03T08:00:00-0700>,
354
+ end: #<DateTime 2024-06-03T09:00:00-0700>,
355
+ },
356
+ {
357
+ start: #<DateTime 2024-06-03T10:00:00-0700>,
358
+ end: #<DateTime 2024-06-03T11:00:00-0700>,
359
+ },
360
+ {
361
+ start: #<DateTime 2024-06-10T08:00:00-0700>,
362
+ end: #<DateTime 2024-06-10T09:00:00-0700>,
363
+ },
364
+ # The June 10 10AM - 11AM was skipped because it overlapped with the June 10 10:30AM - 11:30AM exclusion time.
365
+ {
366
+ start: #<DateTime 2024-06-17T08:00:00-0700>,
367
+ end: #<DateTime 2024-06-17T09:00:00-0700>,
368
+ },
369
+ {
370
+ start: #<DateTime 2024-06-17T10:00:00-0700>,
371
+ end: #<DateTime 2024-06-17T11:00:00-0700>,
372
+ },
373
+ {
374
+ start: #<DateTime 2024-06-24T08:00:00-0700>,
375
+ end: #<DateTime 2024-06-24T09:00:00-0700>,
376
+ },
377
+ ]
378
+ ```
379
+
380
+ ### Example 8 - Every-other-nth day-of-week rules (ie. every other Tuesday, every 3rd Wednesday, every 10th Friday)
381
+
382
+ As a Ruby dev, I want to generate timeblocks for **9AM- 10AM** on **every Monday**, but **every other Tuesday**, and **every other 3rd Wednesday**. I can do this using the `days_of_week` parameter, but also using the `every` and `every_other_nth` keys to specify the every-other-nth-rules.
383
+
384
+ This can be visualized as:
385
+
386
+ <div align="center">
387
+ <img width="600" alt="alt_google_cal_image" src="https://github.com/StevenJL/periodoxical/assets/2191808/d663da17-a94a-4715-886a-8223b129dd60">
388
+ <p><i>(image courtesy of calendar.google.com)</i></p>
389
+ </div>
390
+
391
+ <br>
392
+
393
+ ```rb
394
+ Periodoxical.generate(
395
+ time_zone: 'America/Los_Angeles',
396
+ start_date: '2024-12-30',
397
+ days_of_week: {
398
+ mon: { every: true }, # every Monday (no skipping)
399
+ tue: { every_other_nth: 2 }, # every other Tuesday starting at first Tuesday from start date
400
+ wed: { every_other_nth: 3 }, # every 3rd Wednesday starting at first Wednesday from start date
401
+ },
402
+ limit: 10,
403
+ time_blocks: [
404
+ { start_time: '9:00AM', end_time: '10:00AM' },
405
+ ],
406
+ )
407
+ #=>
408
+ [
409
+ {
410
+ start: #<DateTime: 2024-12-30T09:00:00-0800>,
411
+ end: #<DateTime: 2024-12-30T10:00:00-0800>,
412
+ },
413
+ {
414
+ start: #<DateTime: 2024-12-31T09:00:00-0800>,
415
+ end: #<DateTime: 2024-12-31T10:00:00-0800>,
416
+ },
417
+ {
418
+ start: #<DateTime: 2025-01-01T09:00:00-0800>,
419
+ end: #<DateTime: 2025-01-01T10:00:00-0800>,
420
+ },
421
+ {
422
+ start: #<DateTime: 2025-01-06T09:00:00-0800>,
423
+ end: #<DateTime: 2025-01-06T10:00:00-0800>,
424
+ },
425
+ {
426
+ start: #<DateTime: 2025-01-13T09:00:00-0800>,
427
+ end: #<DateTime: 2025-01-13T10:00:00-0800>,
428
+ },
429
+ {
430
+ start: #<DateTime: 2025-01-14T09:00:00-0800>,
431
+ end: #<DateTime: 2025-01-14T10:00:00-0800>,
432
+ },
433
+ {
434
+ start: #<DateTime: 2025-01-20T09:00:00-0800>,
435
+ end: #<DateTime: 2025-01-20T10:00:00-0800>,
436
+ },
437
+ {
438
+ start: #<DateTime: 2025-01-22T09:00:00-0800>,
439
+ end: #<DateTime: 2025-01-22T10:00:00-0800>,
440
+ },
441
+ {
442
+ start: #<DateTime: 2025-01-27T09:00:00-0800>,
443
+ end: #<DateTime: 2025-01-27T10:00:00-0800>,
444
+ },
445
+ {
446
+ start: #<DateTime: 2025-01-28T09:00:00-0800>,
447
+ end: #<DateTime: 2025-01-28T10:00:00-0800>,
448
+ }
449
+ ]
450
+ ```
451
+
331
452
  ### Having Some Fun
332
453
 
333
454
  Generate all the Friday the 13ths ever since May 1980 (when the first Friday the 13th film was released).
@@ -401,7 +522,8 @@ Periodoxical.generate(
401
522
  {
402
523
  start: #<DateTime: 2028-11-23T17:00:00-0800>,
403
524
  end: #<DateTime: 2028-11-23T18:00:00-0800>,
404
- }
525
+ },
526
+ ...
405
527
  ]
406
528
  ```
407
529
 
@@ -0,0 +1,112 @@
1
+ module Periodoxical
2
+ module Validation
3
+ VALID_DAYS_OF_WEEK = %w[mon tue wed thu fri sat sun].freeze
4
+ def validate!
5
+ unless @day_of_week_time_blocks || @time_blocks
6
+ raise "`day_of_week_time_blocks` or `time_blocks` need to be provided"
7
+ end
8
+
9
+ if (@days_of_week || @days_of_week_with_alternations) && @day_of_week_time_blocks
10
+ raise "`days_of_week` and `day_of_week_time_blocks` are both provided, which leads to ambiguity. Please use only one of these parameters."
11
+ end
12
+
13
+ if @weeks_of_month
14
+ @weeks_of_month.each do |wom|
15
+ unless wom.is_a?(Integer) && wom.between?(1, 5)
16
+ raise "weeks_of_month must be an array of integers between 1 and 5"
17
+ end
18
+ end
19
+ end
20
+
21
+ # days of week are valid
22
+ if @days_of_week
23
+ @days_of_week.each do |day|
24
+ unless VALID_DAYS_OF_WEEK.include?(day.to_s)
25
+ raise "#{day} is not valid day of week format. Must be: #{VALID_DAYS_OF_WEEK}"
26
+ end
27
+ end
28
+ end
29
+
30
+ if @days_of_week_with_alternations
31
+ @days_of_week_with_alternations.each do |dow, every_other|
32
+ unless VALID_DAYS_OF_WEEK.include?(dow.to_s)
33
+ raise "#{dow} is not valid day of week format. Must be: #{VALID_DAYS_OF_WEEK}"
34
+ end
35
+ unless every_other.is_a?(Hash)
36
+ raise "days_of_week parameter is not used correctly. Please look at examples in README."
37
+ end
38
+ unless every_other[:every] || every_other[:every_other_nth]
39
+ raise "days_of_week parameter is not used correctly. Please look at examples in README."
40
+ end
41
+ if every_other[:every_other_nth]
42
+ unless every_other[:every_other_nth].is_a?(Integer)
43
+ raise "days_of_week parameter is not used correctly. Please look at examples in README."
44
+ end
45
+
46
+ unless every_other[:every_other_nth] > 1
47
+ raise "days_of_week parameter is not used correctly. Please look at examples in README."
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ if @nth_day_of_week_in_month
54
+ @nth_day_of_week_in_month.keys.each do |day|
55
+ unless VALID_DAYS_OF_WEEK.include?(day.to_s)
56
+ raise "#{day} is not valid day of week format. Must be: #{VALID_DAYS_OF_WEEK}"
57
+ end
58
+ end
59
+ @nth_day_of_week_in_month.each do |k,v|
60
+ unless v.is_a?(Array)
61
+ raise "nth_day_of_week_in_month parameter is invalid. Please look at the README for examples."
62
+ end
63
+ v.each do |num|
64
+ unless [-1,1,2,3,4,5].include?(num)
65
+ raise "nth_day_of_week_in_month parameter is invalid. Please look at the README for examples. "
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ if @nth_day_of_week_in_month && (@days_of_week || @days_of_week_with_alternations || @day_of_week_time_blocks)
72
+ raise "nth_day_of_week_in_month parameter cannot be used in combination with `days_of_week` or `day_of_week_time_blocks`. Please look at the README for examples."
73
+ end
74
+
75
+ if @day_of_week_time_blocks
76
+ @day_of_week_time_blocks.keys.each do |d|
77
+ unless VALID_DAYS_OF_WEEK.include?(d.to_s)
78
+ raise "#{d} is not a valid day of week format. Must be #{VALID_DAYS_OF_WEEK}"
79
+ end
80
+ end
81
+ end
82
+
83
+ if @days_of_month
84
+ @days_of_month.each do |dom|
85
+ unless dom.is_a?(Integer) && dom.between?(1,31)
86
+ raise 'days_of_months must be array of integers between 1 and 31'
87
+ end
88
+ end
89
+ end
90
+
91
+ if @months
92
+ @months.each do |mon|
93
+ unless mon.is_a?(Integer) && mon.between?(1, 12)
94
+ raise 'months must be array of integers between 1 and 12'
95
+ end
96
+ end
97
+ end
98
+
99
+ unless( @limit || @end_date)
100
+ raise "Either `limit` or `end_date` must be provided"
101
+ end
102
+
103
+ if @exclusion_times
104
+ @exclusion_times.each do |tb|
105
+ unless tb[:start] < tb[:end]
106
+ raise "Exclusion times must have `start` before `end`. #{tb[:start]} not before #{tb[:end]}"
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -1,3 +1,3 @@
1
1
  module Periodoxical
2
- VERSION = "0.7.3"
2
+ VERSION = "0.9.3"
3
3
  end
data/lib/periodoxical.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "periodoxical/version"
2
+ require "periodoxical/validation"
2
3
  require "date"
3
4
  require "time"
4
5
  require "tzinfo"
@@ -12,7 +13,7 @@ module Periodoxical
12
13
  end
13
14
 
14
15
  class Core
15
- VALID_DAYS_OF_WEEK = %w[mon tue wed thu fri sat sun].freeze
16
+ include Periodoxical::Validation
16
17
  # @param [String] time_zone
17
18
  # Ex: 'America/Los_Angeles', 'America/Chicago',
18
19
  # TZInfo::DataTimezone#name from the tzinfo gem (https://github.com/tzinfo/tzinfo)
@@ -43,6 +44,19 @@ module Periodoxical
43
44
  # @param [Aray<String>] exclusion_dates
44
45
  # Dates to be excluded when generating the time blocks
45
46
  # Ex: ['2024-06-10', '2024-06-14']
47
+ # @param [Aray<Hash>] exclusion_times
48
+ # Timeblocks to be excluded when generating the time blocks if there is conflict (ie. overlap)
49
+ # Ex: [
50
+ # {
51
+ # start: '2024-06-10T10:30:00-07:00',
52
+ # end: '2024-06-10T11:30:00-07:00'
53
+ # },
54
+ # {
55
+ # start: '2024-06-10T14:30:00-07:00',
56
+ # end: '2024-06-10T15:30:00-07:00'
57
+ # },
58
+ # ]
59
+ #
46
60
  # @param [Hash<Array<Hash>>] day_of_week_time_blocks
47
61
  # To be used when hours are different between days of the week
48
62
  # Ex: {
@@ -57,6 +71,7 @@ module Periodoxical
57
71
  day_of_week_time_blocks: nil,
58
72
  limit: nil,
59
73
  exclusion_dates: nil,
74
+ exclusion_times: nil,
60
75
  time_zone: 'Etc/UTC',
61
76
  days_of_week: nil,
62
77
  nth_day_of_week_in_month: nil,
@@ -66,7 +81,11 @@ module Periodoxical
66
81
  )
67
82
 
68
83
  @time_zone = TZInfo::Timezone.get(time_zone)
69
- @days_of_week = days_of_week
84
+ if days_of_week.is_a?(Array)
85
+ @days_of_week = days_of_week
86
+ elsif days_of_week.is_a?(Hash)
87
+ @days_of_week_with_alternations = days_of_week
88
+ end
70
89
  @nth_day_of_week_in_month = nth_day_of_week_in_month
71
90
  @days_of_month = days_of_month
72
91
  @weeks_of_month = weeks_of_month
@@ -79,6 +98,11 @@ module Periodoxical
79
98
  @exclusion_dates = if exclusion_dates && !exclusion_dates.empty?
80
99
  exclusion_dates.map { |ed| Date.parse(ed) }
81
100
  end
101
+ @exclusion_times = if exclusion_times
102
+ exclusion_times.map do |et|
103
+ { start: DateTime.parse(et[:start]), end: DateTime.parse(et[:end]) }
104
+ end
105
+ end
82
106
  validate!
83
107
  end
84
108
 
@@ -106,83 +130,6 @@ module Periodoxical
106
130
 
107
131
  private
108
132
 
109
- def validate!
110
- unless @day_of_week_time_blocks || @time_blocks
111
- raise "`day_of_week_time_blocks` or `time_blocks` need to be provided"
112
- end
113
-
114
- if @days_of_week && @day_of_week_time_blocks
115
- raise "`days_of_week` and `day_of_week_time_blocks` are both provided, which leads to ambiguity. Please use only one of these parameters."
116
- end
117
-
118
- if @weeks_of_month
119
- @weeks_of_month.each do |wom|
120
- unless wom.is_a?(Integer) && wom.between?(1, 5)
121
- raise "weeks_of_month must be an array of integers between 1 and 5"
122
- end
123
- end
124
- end
125
-
126
- # days of week are valid
127
- if @days_of_week
128
- @days_of_week.each do |day|
129
- unless VALID_DAYS_OF_WEEK.include?(day.to_s)
130
- raise "#{day} is not valid day of week format. Must be: #{VALID_DAYS_OF_WEEK}"
131
- end
132
- end
133
- end
134
-
135
- if @nth_day_of_week_in_month
136
- @nth_day_of_week_in_month.keys.each do |day|
137
- unless VALID_DAYS_OF_WEEK.include?(day.to_s)
138
- raise "#{day} is not valid day of week format. Must be: #{VALID_DAYS_OF_WEEK}"
139
- end
140
- end
141
- @nth_day_of_week_in_month.each do |k,v|
142
- unless v.is_a?(Array)
143
- raise "nth_day_of_week_in_month parameter is invalid. Please look at the README for examples."
144
- end
145
- v.each do |num|
146
- unless [-1,1,2,3,4,5].include?(num)
147
- raise "nth_day_of_week_in_month parameter is invalid. Please look at the README for examples. "
148
- end
149
- end
150
- end
151
- end
152
-
153
- if @nth_day_of_week_in_month && (@days_of_week || @day_of_week_time_blocks)
154
- raise "nth_day_of_week_in_month parameter cannot be used in combination with `days_of_week` or `day_of_week_time_blocks`. Please look at the README for examples."
155
- end
156
-
157
- if @day_of_week_time_blocks
158
- @day_of_week_time_blocks.keys.each do |d|
159
- unless VALID_DAYS_OF_WEEK.include?(d.to_s)
160
- raise "#{d} is not a valid day of week format. Must be #{VALID_DAYS_OF_WEEK}"
161
- end
162
- end
163
- end
164
-
165
- if @days_of_month
166
- @days_of_month.each do |dom|
167
- unless dom.is_a?(Integer) && dom.between?(1,31)
168
- raise 'days_of_months must be array of integers between 1 and 31'
169
- end
170
- end
171
- end
172
-
173
- if @months
174
- @months.each do |mon|
175
- unless mon.is_a?(Integer) && mon.between?(1, 12)
176
- raise 'months must be array of integers between 1 and 12'
177
- end
178
- end
179
- end
180
-
181
- unless( @limit || @end_date)
182
- raise "Either `limit` or `end_date` must be provided"
183
- end
184
- end
185
-
186
133
  def day_of_week_long_to_short(dow)
187
134
  {
188
135
  "Monday" => "mon",
@@ -231,6 +178,21 @@ module Periodoxical
231
178
  @current_day_of_week = day_of_week_long_to_short(@current_date.strftime("%A"))
232
179
  @current_count = 0
233
180
  @keep_generating = true
181
+ # When there are alternations in days of week
182
+ # (ie. every other Monday, every 3rd Thursday, etc).
183
+ # We keep running tally of day_of_week counts and use modulo-math to pick out
184
+ # every n-th one.
185
+ if @days_of_week_with_alternations
186
+ @days_of_week_running_tally = {
187
+ mon: 0,
188
+ tue: 0,
189
+ wed: 0,
190
+ thu: 0,
191
+ fri: 0,
192
+ sat: 0,
193
+ sun: 0,
194
+ }
195
+ end
234
196
  end
235
197
 
236
198
  # @param [Hash] time_block
@@ -241,6 +203,9 @@ module Periodoxical
241
203
  # }
242
204
  # Generates time block but also checks if we should stop generating
243
205
  def append_to_output_and_check_limit(time_block)
206
+ # Check if this particular time is conflicts with any times from `exclusion_times`.
207
+ return if overlaps_with_an_excluded_time?(time_block)
208
+
244
209
  @output << {
245
210
  start: time_str_to_object(@current_date, time_block[:start_time]),
246
211
  end: time_str_to_object(@current_date, time_block[:end_time])
@@ -256,6 +221,7 @@ module Periodoxical
256
221
 
257
222
  def advance_current_date_and_check_if_reached_end_date
258
223
  @current_date = @current_date + 1
224
+
259
225
  @current_day_of_week = day_of_week_long_to_short(@current_date.strftime("%A"))
260
226
 
261
227
  if @end_date && (@current_date > @end_date)
@@ -302,6 +268,28 @@ module Periodoxical
302
268
  return false unless @days_of_week.include?(@current_day_of_week)
303
269
  end
304
270
 
271
+ if @days_of_week_with_alternations
272
+ # current_date is not specified in days_of_week, so skip it
273
+ return false if @days_of_week_with_alternations[@current_day_of_week.to_sym].nil?
274
+
275
+ alternating_spec = @days_of_week_with_alternations[@current_day_of_week.to_sym]
276
+
277
+ # In the { every: true } case, we don't check the alternations logic, we just add it.
278
+ unless alternating_spec[:every]
279
+ # We are now specifying every other nth occurrence (ie. every 2nd Tuesday, every 3rd Wednesday)
280
+ alternating_frequency = alternating_spec[:every_other_nth]
281
+
282
+ unless (@days_of_week_running_tally[@current_day_of_week.to_sym] % alternating_frequency) == 0
283
+ # If day-of-week alternations are present, we need to keep track of day-of-weeks
284
+ # we have encountered and added or would have added so far.
285
+ update_days_of_week_running_tally!
286
+
287
+ return false
288
+ end
289
+ update_days_of_week_running_tally!
290
+ end
291
+ end
292
+
305
293
  if @day_of_week_time_blocks
306
294
  dowtb = @day_of_week_time_blocks[@current_day_of_week.to_sym]
307
295
  return false if dowtb.nil?
@@ -327,7 +315,20 @@ module Periodoxical
327
315
  end
328
316
  end
329
317
 
330
- # Otherwise, return true
318
+ # The default return true is really only needed to support this use-case:
319
+ # Periodoxical.generate(
320
+ # time_zone: 'America/Los_Angeles',
321
+ # time_blocks: [
322
+ # {
323
+ # start_time: '9:00AM',
324
+ # end_time: '10:30AM'
325
+ # },
326
+ # ],
327
+ # start_date: '2024-05-23',
328
+ # end_date: '2024-05-27',
329
+ # )
330
+ # where if we don't specify any date-of-week/month constraints, we return all consecutive dates.
331
+ # In the future, if we don't support this case, we can use `false` as the return value.
331
332
  true
332
333
  end
333
334
 
@@ -367,5 +368,47 @@ module Periodoxical
367
368
 
368
369
  ((last_date.day - 1) / 7) + 1
369
370
  end
371
+
372
+ def update_days_of_week_running_tally!
373
+ @days_of_week_running_tally[@current_day_of_week.to_sym] = @days_of_week_running_tally[@current_day_of_week.to_sym] + 1
374
+ end
375
+
376
+ # @return [Boolean]
377
+ # Whether or not the given `time_block` in the @current_date and
378
+ # @time_zone overlaps with the times in `exclusion_times`.
379
+ def overlaps_with_an_excluded_time?(time_block)
380
+ return false unless @exclusion_times
381
+
382
+ @exclusion_times.each do |exclusion_timeblock|
383
+ return true if overlap?(
384
+ exclusion_timeblock,
385
+ {
386
+ start: time_str_to_object(@current_date, time_block[:start_time]),
387
+ end: time_str_to_object(@current_date, time_block[:end_time]),
388
+ }
389
+ )
390
+ end
391
+
392
+ false
393
+ end
394
+
395
+ # @param [Hash] time_block_1, time_block_2
396
+ # Ex: {
397
+ # start: #<DateTime>,
398
+ # end: #<DateTime>,
399
+ # }
400
+ def overlap?(time_block_1, time_block_2)
401
+ tb_1_start = time_block_1[:start]
402
+ tb_1_end = time_block_1[:end]
403
+ tb_2_start = time_block_2[:start]
404
+ tb_2_end = time_block_2[:end]
405
+
406
+ # Basicall overlap is when one starts before the other has ended
407
+ return true if tb_1_end > tb_2_start && tb_1_end < tb_2_end
408
+ # By symmetry
409
+ return true if tb_2_end > tb_1_start && tb_2_end < tb_1_end
410
+
411
+ false
412
+ end
370
413
  end
371
414
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: periodoxical
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Li
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-02 00:00:00.000000000 Z
11
+ date: 2024-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tzinfo
@@ -135,6 +135,7 @@ files:
135
135
  - bin/console
136
136
  - bin/setup
137
137
  - lib/periodoxical.rb
138
+ - lib/periodoxical/validation.rb
138
139
  - lib/periodoxical/version.rb
139
140
  - periodoxical.gemspec
140
141
  homepage: https://github.com/StevenJL/periodoxical