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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3836bd7c49ec987409e70592d93cb8c021a009ce3587e48a6419c12121af3b1d
4
- data.tar.gz: 510bb79570482c8019e911c8900ec15ee5016b59c1d51677d38d53f7c632523f
3
+ metadata.gz: 2b67da50d1bba17e1d25babaa937440ccad41bf152d1df8d3adb50ff8c9199b3
4
+ data.tar.gz: 954c91d5da06a9d4955fdb35576b11f1e209a8ab152825c3f09657e891787a5d
5
5
  SHA512:
6
- metadata.gz: 0afbe7ebba86480f7d04766a087020734135bb0075245fbe6ba03f75590eb0c74710991b14e5fad653779ba7d6a74811d11adaeb7cfa28ec194dc9eea05adfb9
7
- data.tar.gz: ddc843c9de7c3ae536f939f0c7bfc6c6d5ce2a37d4bde07d2941bd2ef7f7e0a41328d347fe1e9d8d1c1e1ba9bf916648424bd18795ad8642531d37529841d913
6
+ metadata.gz: ab9f0eb8538ea18407171b2d9dc435935821370f3f3d229f59d718e3e11f3eba6b6f926129274f33c5100b22a70d937ba6f9693d714f52abaf0f2a7be4965d28
7
+ data.tar.gz: 64503a74a1879ae8d0cda934ad511530ff6c22e5f1aeb9fe331f0dda99ccf8d7b81c735e2d10a9c6ce468010ea64674c1d8bc86a24fa8f18aa5382cfd29facdd
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- periodoxical (1.0.0)
4
+ periodoxical (1.1.0)
5
5
  tzinfo (~> 2.0, >= 2.0.0)
6
6
  week_of_month (= 1.2.6)
7
7
 
data/README.md CHANGED
@@ -29,7 +29,7 @@ Or install it yourself as:
29
29
 
30
30
  ## Usage
31
31
 
32
- ### Example 1
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 for more precision. This example generate all the datetime blocks of **9:00AM - 10:30AM** but starting from **May 23, 2024 at 9:30AM**.
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 timeslot was before the `starting_from` of '2024-05-23T09:30:00-07:00'
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
- ### Example 2 - specify days of the week
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 3 - using the `limit` key.
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** using the `limit` key.
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
- ### Example 4 - when time blocks vary between days
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
- ### Example 5 - when specifying time blocks using day-of-month and/or week-of-month and/or month.
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 "last" of the month.
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, but also using the `every` and `every_other_nth` keys to specify the every-other-nth-rules.
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
@@ -1,3 +1,3 @@
1
1
  module Periodoxical
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
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.0.0
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-04 00:00:00.000000000 Z
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
data/.travis.yml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
- rvm:
6
- - 2.6.10
7
- before_install: gem install bundler -v 1.17.2