periodoxical 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|