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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +61 -2
- data/lib/periodoxical/validation.rb +8 -0
- data/lib/periodoxical/version.rb +1 -1
- data/lib/periodoxical.rb +60 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1028e4261c9759e49e7446a1ff506fcb4d3b789b4bdd1ef40dbec0bd8df18ae8
|
|
4
|
+
data.tar.gz: c7dece06fabe86ede77b98203bea7716d0d1e039393f1e6e693c8a232615ef01
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '08dc98ece1a24ed33564c60f32c31fcf76defddbab51fbf2c0c3df04b296759767fc1dde8a4ed744a24b700fe812ce97bcdc06c052c382e61872c55426116258'
|
|
7
|
+
data.tar.gz: c8edb8ea410b88c5888edda103752c27c149e4e06421b74fb7c4a29ed0f09ae32726536ed495702156b8e6e054da0a5140e1a3487bbbac4468abb94ed7cfb79f
|
data/Gemfile.lock
CHANGED
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`
|
|
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
|
data/lib/periodoxical/version.rb
CHANGED
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.
|
|
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-
|
|
11
|
+
date: 2024-06-04 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: tzinfo
|