periodoxical 0.8.3 → 0.9.3

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: 78125f7c8e33a8588c933d7b0438daa5d0913394fe9c141e752dd73fc1968d88
4
- data.tar.gz: 60acbba0684d36991ac7bffcb21dc8a97e27bfb313d1ab9641668463e73c718c
3
+ metadata.gz: 1028e4261c9759e49e7446a1ff506fcb4d3b789b4bdd1ef40dbec0bd8df18ae8
4
+ data.tar.gz: c7dece06fabe86ede77b98203bea7716d0d1e039393f1e6e693c8a232615ef01
5
5
  SHA512:
6
- metadata.gz: df7a8cc7abe1139af195aebe455feb7c66b75e27e3a8d43e4c862ec362111756a461b7293efe3c3fdcca50eb1f70d5fdb5de04e740014a4fc33fe3f324e8d6ec
7
- data.tar.gz: '070876a087c2712b12f497054966f9cd98ac3d0e3eab1e4337e165e2ea42cef5ea4dd5b43b714393d92d14ddab2119b426128cf9d85f5de845b9e32959f72b1d'
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.8.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
@@ -291,7 +291,7 @@ Periodoxical.generate(
291
291
  ]
292
292
  ```
293
293
 
294
- ### Example 7 - Exclude time blocks using the `exclusion_dates` parameter
294
+ ### Example 7 - Exclude time blocks using the `exclusion_dates` and `exclusion_times` parameters
295
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
@@ -328,10 +328,68 @@ 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
+
331
380
  ### Example 8 - Every-other-nth day-of-week rules (ie. every other Tuesday, every 3rd Wednesday, every 10th Friday)
332
381
 
333
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.
334
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
+
335
393
  ```rb
336
394
  Periodoxical.generate(
337
395
  time_zone: 'America/Los_Angeles',
@@ -464,7 +522,8 @@ Periodoxical.generate(
464
522
  {
465
523
  start: #<DateTime: 2028-11-23T17:00:00-0800>,
466
524
  end: #<DateTime: 2028-11-23T18:00:00-0800>,
467
- }
525
+ },
526
+ ...
468
527
  ]
469
528
  ```
470
529
 
@@ -99,6 +99,14 @@ module Periodoxical
99
99
  unless( @limit || @end_date)
100
100
  raise "Either `limit` or `end_date` must be provided"
101
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
102
110
  end
103
111
  end
104
112
  end
@@ -1,3 +1,3 @@
1
1
  module Periodoxical
2
- VERSION = "0.8.3"
2
+ VERSION = "0.9.3"
3
3
  end
data/lib/periodoxical.rb CHANGED
@@ -44,6 +44,19 @@ module Periodoxical
44
44
  # @param [Aray<String>] exclusion_dates
45
45
  # Dates to be excluded when generating the time blocks
46
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
+ #
47
60
  # @param [Hash<Array<Hash>>] day_of_week_time_blocks
48
61
  # To be used when hours are different between days of the week
49
62
  # Ex: {
@@ -58,6 +71,7 @@ module Periodoxical
58
71
  day_of_week_time_blocks: nil,
59
72
  limit: nil,
60
73
  exclusion_dates: nil,
74
+ exclusion_times: nil,
61
75
  time_zone: 'Etc/UTC',
62
76
  days_of_week: nil,
63
77
  nth_day_of_week_in_month: nil,
@@ -84,6 +98,11 @@ module Periodoxical
84
98
  @exclusion_dates = if exclusion_dates && !exclusion_dates.empty?
85
99
  exclusion_dates.map { |ed| Date.parse(ed) }
86
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
87
106
  validate!
88
107
  end
89
108
 
@@ -184,6 +203,9 @@ module Periodoxical
184
203
  # }
185
204
  # Generates time block but also checks if we should stop generating
186
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
+
187
209
  @output << {
188
210
  start: time_str_to_object(@current_date, time_block[:start_time]),
189
211
  end: time_str_to_object(@current_date, time_block[:end_time])
@@ -350,5 +372,43 @@ module Periodoxical
350
372
  def update_days_of_week_running_tally!
351
373
  @days_of_week_running_tally[@current_day_of_week.to_sym] = @days_of_week_running_tally[@current_day_of_week.to_sym] + 1
352
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
353
413
  end
354
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.8.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-03 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