periodoxical 1.0.0 → 1.1.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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +16 -15
- data/lib/periodoxical/helpers.rb +70 -0
- data/lib/periodoxical/version.rb +1 -1
- data/lib/periodoxical.rb +8 -57
- metadata +3 -3
- data/.travis.yml +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b67da50d1bba17e1d25babaa937440ccad41bf152d1df8d3adb50ff8c9199b3
|
4
|
+
data.tar.gz: 954c91d5da06a9d4955fdb35576b11f1e209a8ab152825c3f09657e891787a5d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab9f0eb8538ea18407171b2d9dc435935821370f3f3d229f59d718e3e11f3eba6b6f926129274f33c5100b22a70d937ba6f9693d714f52abaf0f2a7be4965d28
|
7
|
+
data.tar.gz: 64503a74a1879ae8d0cda934ad511530ff6c22e5f1aeb9fe331f0dda99ccf8d7b81c735e2d10a9c6ce468010ea64674c1d8bc86a24fa8f18aa5382cfd29facdd
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -29,7 +29,7 @@ Or install it yourself as:
|
|
29
29
|
|
30
30
|
## Usage
|
31
31
|
|
32
|
-
### Example
|
32
|
+
### Basic Example
|
33
33
|
As a Ruby dev, I want to generate all the datetime blocks of **9:00AM - 10:30AM** for all days from **May 23, 2024** to **May 26, 2024** inclusive.
|
34
34
|
|
35
35
|
```rb
|
@@ -65,7 +65,7 @@ Periodoxical.generate(
|
|
65
65
|
]
|
66
66
|
```
|
67
67
|
|
68
|
-
The `starting_from` and `ending_at` params can also accept datetimes in ISO 8601 format
|
68
|
+
The `starting_from` and `ending_at` params can also accept datetimes in ISO 8601 format. This example generate all the datetime blocks of **9:00AM - 10:30AM** but starting from **May 23, 2024 at 9:30AM**.
|
69
69
|
|
70
70
|
```rb
|
71
71
|
Periodoxical.generate(
|
@@ -80,7 +80,8 @@ Periodoxical.generate(
|
|
80
80
|
ending_at: DateTime.parse('2024-05-26T17:00:00-07:00'), # or an instance of DateTime
|
81
81
|
)
|
82
82
|
#=> [
|
83
|
-
# 2024-05-23 was skipped because the 9AM
|
83
|
+
# 2024-05-23 was skipped because the 9AM time block was before
|
84
|
+
# the `starting_from` of '2024-05-23T09:30:00-07:00'
|
84
85
|
{
|
85
86
|
start_time: #<DateTime: 2024-05-24T09:00:00-0700>,
|
86
87
|
end_time: #<DateTime: 2024-05-24T10:30:00-0700>,
|
@@ -89,8 +90,8 @@ Periodoxical.generate(
|
|
89
90
|
]
|
90
91
|
```
|
91
92
|
|
92
|
-
###
|
93
|
-
As a Ruby dev, I want to generate all the datetime blocks of **9:00AM - 10:30AM** and **2:00PM - 2:30PM**, on **Mondays**, **Wednesdays**, and **Thursdays**, between the dates of **May 23, 2024** and **June 12, 2024**, inclusive. This can be represented visually as:
|
93
|
+
### Specify days of the week
|
94
|
+
As a Ruby dev, I want to generate all the datetime blocks of **9:00AM - 10:30AM** and **2:00PM - 2:30PM**, on **Mondays**, **Wednesdays**, and **Thursdays**, between the dates of **May 23, 2024** and **June 12, 2024**, inclusive. I can do this using the `days_of_week` parameter. This can be represented visually as:
|
94
95
|
|
95
96
|
<div align="center">
|
96
97
|
<img width="558" alt="calendar_image_1" src="https://github.com/StevenJL/periodoxical/assets/2191808/e92fc6ff-03fd-44ed-a955-d3a0dd0f5d0a">
|
@@ -139,9 +140,9 @@ Periodoxical.generate(
|
|
139
140
|
]
|
140
141
|
```
|
141
142
|
|
142
|
-
### Example
|
143
|
+
### Example using the `limit` parameter.
|
143
144
|
|
144
|
-
As a ruby dev, I want to generate the next **3** datetime blocks of **9:00AM - 10:30AM** and **2:00PM - 2:30PM** on **Sundays**, after **May 23, 2024
|
145
|
+
As a ruby dev, I want to generate the next **3** datetime blocks of **9:00AM - 10:30AM** and **2:00PM - 2:30PM** on **Sundays**, after **May 23, 2024**. I can do this using the `limit` parameter, instead of `ending_at`.
|
145
146
|
|
146
147
|
```rb
|
147
148
|
Periodoxical.generate(
|
@@ -177,9 +178,9 @@ Periodoxical.generate(
|
|
177
178
|
]
|
178
179
|
```
|
179
180
|
|
180
|
-
###
|
181
|
+
### Time blocks that vary between days-of-the-week
|
181
182
|
|
182
|
-
As a ruby dev, I want to generate all the timeblocks between **May 23, 2024** and **June 12, 2024** where the time should be **8AM-9AM** on **Mondays**, but **10:45AM-12:00PM** and **2:00PM-4:00PM** on **Wednesdays**, and **2:30PM-4:15PM** on **Thursdays**.
|
183
|
+
As a ruby dev, I want to generate all the timeblocks between **May 23, 2024** and **June 12, 2024** where the time should be **8AM-9AM** on **Mondays**, but **10:45AM-12:00PM** and **2:00PM-4:00PM** on **Wednesdays**, and **2:30PM-4:15PM** on **Thursdays**. I can do this using the `day_of_week_time_blocks` parameter.
|
183
184
|
|
184
185
|
<div align="center">
|
185
186
|
<img width="628" alt="calendar_image_2" src="https://github.com/StevenJL/periodoxical/assets/2191808/26d14824-08ff-481a-97e2-9b6b11beea29">
|
@@ -208,9 +209,9 @@ Periodoxical.generate(
|
|
208
209
|
)
|
209
210
|
```
|
210
211
|
|
211
|
-
###
|
212
|
+
### Specifying time blocks using rules for day-of-month and/or week-of-month and/or month.
|
212
213
|
|
213
|
-
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
|
214
|
+
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**. I can do this using the `days_of_month` parameter.
|
214
215
|
|
215
216
|
```rb
|
216
217
|
Periodoxical.generate(
|
@@ -239,7 +240,7 @@ Periodoxical.generate(
|
|
239
240
|
]
|
240
241
|
```
|
241
242
|
|
242
|
-
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
|
243
|
+
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**. I can do this using the `months` parameter.
|
243
244
|
|
244
245
|
```
|
245
246
|
Periodoxical.generate(
|
@@ -284,7 +285,7 @@ Periodoxical.generate(
|
|
284
285
|
limit: 5,
|
285
286
|
nth_day_of_week_in_month: {
|
286
287
|
mon: [1, 2], # valid values: -1,1,2,3,4,5
|
287
|
-
fri: [-1], # Use -1 to specify
|
288
|
+
fri: [-1], # Use -1 to specify the last Friday of the month.
|
288
289
|
},
|
289
290
|
time_blocks: [
|
290
291
|
{ start_time: '8:00AM', end_time: '9:00AM' },
|
@@ -316,7 +317,7 @@ Periodoxical.generate(
|
|
316
317
|
```
|
317
318
|
|
318
319
|
### Example 7 - Exclude time blocks using the `exclusion_dates` and `exclusion_times` parameters
|
319
|
-
As a Ruby dev, I want to generate timeblocks for **8AM - 9AM** on **Mondays**, except for the **Monday of June 10, 2024**.
|
320
|
+
As a Ruby dev, I want to generate timeblocks for **8AM - 9AM** on **Mondays**, except for the **Monday of June 10, 2024**. I can do this using the `exlcusion_dates` parameter.
|
320
321
|
|
321
322
|
```rb
|
322
323
|
Periodoxical.generate(
|
@@ -403,7 +404,7 @@ Periodoxical.generate(
|
|
403
404
|
|
404
405
|
### Example 8 - Every-other-nth day-of-week rules (ie. every other Tuesday, every 3rd Wednesday, every 10th Friday)
|
405
406
|
|
406
|
-
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
|
407
|
+
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 with the `every` and `every_other_nth` keys to specify the every-other-nth-rules.
|
407
408
|
|
408
409
|
This can be visualized as:
|
409
410
|
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Periodoxical
|
2
|
+
module Helpers
|
3
|
+
def deep_symbolize_keys(obj)
|
4
|
+
return unless obj
|
5
|
+
|
6
|
+
case obj
|
7
|
+
when Hash
|
8
|
+
obj.each_with_object({}) do |(key, value), result|
|
9
|
+
symbolized_key = key.to_sym rescue key
|
10
|
+
result[symbolized_key] = deep_symbolize_keys(value)
|
11
|
+
end
|
12
|
+
when Array
|
13
|
+
obj.map { |e| deep_symbolize_keys(e) }
|
14
|
+
else
|
15
|
+
obj
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param [Hash] time_block_1, time_block_2
|
20
|
+
# Ex: {
|
21
|
+
# start: #<DateTime>,
|
22
|
+
# end: #<DateTime>,
|
23
|
+
# }
|
24
|
+
def overlap?(time_block_1, time_block_2)
|
25
|
+
tb_1_start = time_block_1[:start]
|
26
|
+
tb_1_end = time_block_1[:end]
|
27
|
+
tb_2_start = time_block_2[:start]
|
28
|
+
tb_2_end = time_block_2[:end]
|
29
|
+
|
30
|
+
# Basicall overlap is when one starts before the other has ended
|
31
|
+
return true if tb_1_end > tb_2_start && tb_1_end < tb_2_end
|
32
|
+
# By symmetry
|
33
|
+
return true if tb_2_end > tb_1_start && tb_2_end < tb_1_end
|
34
|
+
|
35
|
+
false
|
36
|
+
end
|
37
|
+
|
38
|
+
def date_object_from(dt)
|
39
|
+
return unless dt
|
40
|
+
return dt if dt.is_a?(Date) || dt.is_a?(DateTime)
|
41
|
+
|
42
|
+
if dt.is_a?(String)
|
43
|
+
return Date.parse(dt) if /\A\d{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[12]\d|3[01])\z/ =~ dt
|
44
|
+
|
45
|
+
if /\A\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):[0-5]\d:[0-5]\d(\.\d+)?(Z|[+-][01]\d:[0-5]\d)?\z/ =~ dt
|
46
|
+
# convert to DateTime object
|
47
|
+
dt = DateTime.parse(dt)
|
48
|
+
# convert to given time_zone
|
49
|
+
return dt.to_time.localtime(@time_zone.utc_offset).to_datetime
|
50
|
+
end
|
51
|
+
|
52
|
+
raise "Could not parse date/datetime string #{dt}. Please README for examples."
|
53
|
+
else
|
54
|
+
raise "Invalid argument: #{dt}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def day_of_week_long_to_short(dow)
|
59
|
+
{
|
60
|
+
"Monday" => "mon",
|
61
|
+
"Tuesday" => "tue",
|
62
|
+
"Wednesday" => "wed",
|
63
|
+
"Thursday" => "thu",
|
64
|
+
"Friday" => "fri",
|
65
|
+
"Saturday" => "sat",
|
66
|
+
"Sunday" => "sun",
|
67
|
+
}[dow]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/periodoxical/version.rb
CHANGED
data/lib/periodoxical.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "periodoxical/version"
|
2
2
|
require "periodoxical/validation"
|
3
|
+
require "periodoxical/helpers"
|
3
4
|
require "date"
|
4
5
|
require "time"
|
5
6
|
require "tzinfo"
|
@@ -14,6 +15,7 @@ module Periodoxical
|
|
14
15
|
|
15
16
|
class Core
|
16
17
|
include Periodoxical::Validation
|
18
|
+
include Periodoxical::Helpers
|
17
19
|
# @param [String] time_zone
|
18
20
|
# Ex: 'America/Los_Angeles', 'America/Chicago',
|
19
21
|
# TZInfo::DataTimezone#name from the tzinfo gem (https://github.com/tzinfo/tzinfo)
|
@@ -82,16 +84,16 @@ module Periodoxical
|
|
82
84
|
|
83
85
|
@time_zone = TZInfo::Timezone.get(time_zone)
|
84
86
|
if days_of_week.is_a?(Array)
|
85
|
-
@days_of_week = days_of_week
|
87
|
+
@days_of_week = deep_symbolize_keys(days_of_week)
|
86
88
|
elsif days_of_week.is_a?(Hash)
|
87
|
-
@days_of_week_with_alternations = days_of_week
|
89
|
+
@days_of_week_with_alternations = deep_symbolize_keys(days_of_week)
|
88
90
|
end
|
89
|
-
@nth_day_of_week_in_month = nth_day_of_week_in_month
|
91
|
+
@nth_day_of_week_in_month = deep_symbolize_keys(nth_day_of_week_in_month)
|
90
92
|
@days_of_month = days_of_month
|
91
93
|
@weeks_of_month = weeks_of_month
|
92
94
|
@months = months
|
93
|
-
@time_blocks = time_blocks
|
94
|
-
@day_of_week_time_blocks = day_of_week_time_blocks
|
95
|
+
@time_blocks = deep_symbolize_keys(time_blocks)
|
96
|
+
@day_of_week_time_blocks = deep_symbolize_keys(day_of_week_time_blocks)
|
95
97
|
@starting_from = date_object_from(starting_from)
|
96
98
|
@ending_at = date_object_from(ending_at)
|
97
99
|
@limit = limit
|
@@ -99,7 +101,7 @@ module Periodoxical
|
|
99
101
|
exclusion_dates.map { |ed| Date.parse(ed) }
|
100
102
|
end
|
101
103
|
@exclusion_times = if exclusion_times
|
102
|
-
exclusion_times.map do |et|
|
104
|
+
deep_symbolize_keys(exclusion_times).map do |et|
|
103
105
|
{ start: DateTime.parse(et[:start]), end: DateTime.parse(et[:end]) }
|
104
106
|
end
|
105
107
|
end
|
@@ -130,18 +132,6 @@ module Periodoxical
|
|
130
132
|
|
131
133
|
private
|
132
134
|
|
133
|
-
def day_of_week_long_to_short(dow)
|
134
|
-
{
|
135
|
-
"Monday" => "mon",
|
136
|
-
"Tuesday" => "tue",
|
137
|
-
"Wednesday" => "wed",
|
138
|
-
"Thursday" => "thu",
|
139
|
-
"Friday" => "fri",
|
140
|
-
"Saturday" => "sat",
|
141
|
-
"Sunday" => "sun",
|
142
|
-
}[dow]
|
143
|
-
end
|
144
|
-
|
145
135
|
# @param [String] time_str
|
146
136
|
# Ex: '9:00AM'
|
147
137
|
# @param [Date] date
|
@@ -419,44 +409,5 @@ module Periodoxical
|
|
419
409
|
|
420
410
|
false
|
421
411
|
end
|
422
|
-
|
423
|
-
# @param [Hash] time_block_1, time_block_2
|
424
|
-
# Ex: {
|
425
|
-
# start: #<DateTime>,
|
426
|
-
# end: #<DateTime>,
|
427
|
-
# }
|
428
|
-
def overlap?(time_block_1, time_block_2)
|
429
|
-
tb_1_start = time_block_1[:start]
|
430
|
-
tb_1_end = time_block_1[:end]
|
431
|
-
tb_2_start = time_block_2[:start]
|
432
|
-
tb_2_end = time_block_2[:end]
|
433
|
-
|
434
|
-
# Basicall overlap is when one starts before the other has ended
|
435
|
-
return true if tb_1_end > tb_2_start && tb_1_end < tb_2_end
|
436
|
-
# By symmetry
|
437
|
-
return true if tb_2_end > tb_1_start && tb_2_end < tb_1_end
|
438
|
-
|
439
|
-
false
|
440
|
-
end
|
441
|
-
|
442
|
-
def date_object_from(dt)
|
443
|
-
return unless dt
|
444
|
-
return dt if dt.is_a?(Date) || dt.is_a?(DateTime)
|
445
|
-
|
446
|
-
if dt.is_a?(String)
|
447
|
-
return Date.parse(dt) if /\A\d{4}-(0?[1-9]|1[0-2])-(0?[1-9]|[12]\d|3[01])\z/ =~ dt
|
448
|
-
|
449
|
-
if /\A\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])T([01]\d|2[0-3]):[0-5]\d:[0-5]\d(\.\d+)?(Z|[+-][01]\d:[0-5]\d)?\z/ =~ dt
|
450
|
-
# convert to DateTime object
|
451
|
-
dt = DateTime.parse(dt)
|
452
|
-
# convert to given time_zone
|
453
|
-
return dt.to_time.localtime(@time_zone.utc_offset).to_datetime
|
454
|
-
end
|
455
|
-
|
456
|
-
raise "Could not parse date/datetime string #{dt}. Please README for examples."
|
457
|
-
else
|
458
|
-
raise "Invalid argument: #{dt}"
|
459
|
-
end
|
460
|
-
end
|
461
412
|
end
|
462
413
|
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: 1.
|
4
|
+
version: 1.1.0
|
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-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tzinfo
|
@@ -125,7 +125,6 @@ extra_rdoc_files: []
|
|
125
125
|
files:
|
126
126
|
- ".gitignore"
|
127
127
|
- ".rspec"
|
128
|
-
- ".travis.yml"
|
129
128
|
- CODE_OF_CONDUCT.md
|
130
129
|
- Gemfile
|
131
130
|
- Gemfile.lock
|
@@ -135,6 +134,7 @@ files:
|
|
135
134
|
- bin/console
|
136
135
|
- bin/setup
|
137
136
|
- lib/periodoxical.rb
|
137
|
+
- lib/periodoxical/helpers.rb
|
138
138
|
- lib/periodoxical/validation.rb
|
139
139
|
- lib/periodoxical/version.rb
|
140
140
|
- periodoxical.gemspec
|