availabiliter 0.1.0 → 0.2.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/.github/workflows/main.yml +8 -5
- data/.gitignore +1 -0
- data/CHANGELOG.md +7 -0
- data/README.md +6 -11
- data/availabiliter.gemspec +0 -1
- data/lib/availabiliter/date_range.rb +47 -45
- data/lib/availabiliter/timeframe.rb +46 -44
- data/lib/availabiliter/version.rb +1 -1
- metadata +7 -22
- data/Gemfile.lock +0 -71
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4398863d21393841d616f4fd47c7cfd3d5c7c3c04839735e4508cae695f07f1
|
4
|
+
data.tar.gz: dc7736e7c8a5ee4498719a8976e73b5923b35b0f32154bac151009db6eeb98b7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60eb5709da8cd9dedee6e7246c517f27117e23aa04cfeb69e8945e67acdaada2e5b86e1b0c5ba67a94dcd2e88b06841b8881b5a9bd179e8d76f090cb09c66240
|
7
|
+
data.tar.gz: cf00b270e3afbef8253100d3784ce435ada6f2ef69a00ba6af41e01e26a6473295f339dc6f9ceaaa1f21ec9136c806c1d7bccb8c06e54bc6233b9773d40a89d5
|
data/.github/workflows/main.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
name:
|
1
|
+
name: Tests
|
2
2
|
|
3
|
-
on: [
|
3
|
+
on: [pull_request]
|
4
4
|
|
5
5
|
jobs:
|
6
6
|
build:
|
@@ -10,9 +10,12 @@ jobs:
|
|
10
10
|
- name: Set up Ruby
|
11
11
|
uses: ruby/setup-ruby@v1
|
12
12
|
with:
|
13
|
-
ruby-version:
|
14
|
-
- name:
|
13
|
+
ruby-version: 2.7.2
|
14
|
+
- name: Set up gems
|
15
15
|
run: |
|
16
16
|
gem install bundler -v 2.2.15
|
17
17
|
bundle install
|
18
|
-
|
18
|
+
- name: Run rspec
|
19
|
+
run: rspec spec
|
20
|
+
- name: Run rubocop
|
21
|
+
run: rubocop
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -5,7 +5,7 @@ Availabiliter is a Ruby availability calculator for date ranges. It handles the
|
|
5
5
|
- endless date ranges
|
6
6
|
- overlapping date ranges
|
7
7
|
- consecutive date ranges
|
8
|
-
- one day ranges
|
8
|
+
- one day date ranges
|
9
9
|
|
10
10
|
It also allows to calculate availabilities from a dedicated date in time.
|
11
11
|
|
@@ -29,29 +29,24 @@ Or install it yourself as:
|
|
29
29
|
|
30
30
|
```ruby
|
31
31
|
# Build an array with all the date ranges you are looking an availability for
|
32
|
-
|
32
|
+
holidays = [Date.new(1999, 1, 2)..Date.new(1999, 5, 1), Date.new(2000, 1, 1)..Date.new(2000, 2, 1), Date.new(2000, 3, 1)..nil]
|
33
33
|
|
34
|
-
Availabiliter.get_availabilities(
|
34
|
+
Availabiliter.get_availabilities(holidays)
|
35
35
|
# => [Date.new(1999, 5, 2)..Date.new(1999, 12, 31), Date.new(2000, 2, 2)..Date.new(2000, 2, 29)]
|
36
36
|
|
37
37
|
# If you want to retrieve availabilities starting from a specific date simply add it as a second argument
|
38
|
-
Availabiliter.get_availabilities(
|
38
|
+
Availabiliter.get_availabilities(holidays, Date.new(1999, 12, 15))
|
39
39
|
# => [Date.new(1999, 12, 15)..Date.new(1999, 12, 31), Date.new(2000, 2, 2)..Date.new(2000, 2, 29)]
|
40
40
|
|
41
41
|
# If all of your date ranges have an end the last availability will be endless
|
42
|
-
|
42
|
+
holidays = [Date.new(1999, 1, 2)..Date.new(1999, 5, 1)]
|
43
43
|
|
44
|
-
Availabiliter.get_availabilities(
|
44
|
+
Availabiliter.get_availabilities(holidays)
|
45
45
|
# => [Date.new(1999, 5, 2)..]
|
46
46
|
|
47
47
|
```
|
48
|
-
## Dependencies
|
49
|
-
|
50
|
-
This gem depends solely on Active Support gem. One of the future planned improvement is to remove this dependency.
|
51
|
-
|
52
48
|
## Future improvements
|
53
49
|
|
54
|
-
- remove any dependency from the project
|
55
50
|
- support Datetime
|
56
51
|
- support beginless ranges
|
57
52
|
|
data/availabiliter.gemspec
CHANGED
@@ -28,7 +28,6 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
29
29
|
spec.require_paths = ["lib"]
|
30
30
|
|
31
|
-
spec.add_dependency "activesupport", "~> 6.1.3.2"
|
32
31
|
spec.add_development_dependency "byebug", "~> 11.1.3"
|
33
32
|
spec.add_development_dependency "rake", "~> 13.0.3"
|
34
33
|
spec.add_development_dependency "rspec", "~> 3.10"
|
@@ -1,66 +1,68 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "date"
|
4
4
|
|
5
|
-
|
6
|
-
# DateRange
|
7
|
-
|
8
|
-
|
5
|
+
module Availabiliter
|
6
|
+
# DateRange is a Range with only dates
|
7
|
+
# DateRange start_date is always the earliest date and end_date the latest date
|
8
|
+
class DateRange < Range
|
9
|
+
include Comparable
|
9
10
|
|
10
|
-
|
11
|
-
|
11
|
+
alias start_date begin
|
12
|
+
alias end_date end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
def initialize(start_date, end_date)
|
15
|
+
super
|
16
|
+
raise ArgumentError, "bad value for DateRange" unless valid?
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
-
|
19
|
+
def independent?(other)
|
20
|
+
return true if other.nil?
|
20
21
|
|
21
|
-
|
22
|
-
|
22
|
+
!overlaps?(other) && !adjacent?(other)
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
25
|
+
def tomorrow
|
26
|
+
end_date&.next_day
|
27
|
+
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
def yesterday
|
30
|
+
start_date.prev_day
|
31
|
+
end
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
33
|
+
## adjacent == touches but doesn't overlap other DateRange
|
34
|
+
def adjacent?(other)
|
35
|
+
return other.end_date == yesterday if end_date.nil?
|
35
36
|
|
36
|
-
|
37
|
-
|
37
|
+
other.end_date == yesterday || other.start_date == tomorrow
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
def overlaps?(other)
|
41
|
+
cover?(other.begin) || other.cover?(first)
|
42
|
+
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
def next_availability(next_date_range)
|
45
|
+
return if end_date.nil?
|
46
|
+
return tomorrow..nil if next_date_range.nil?
|
47
|
+
return unless independent?(next_date_range)
|
47
48
|
|
48
|
-
|
49
|
-
|
49
|
+
gap_start = tomorrow
|
50
|
+
gap_end = next_date_range.yesterday
|
50
51
|
|
51
|
-
|
52
|
-
|
52
|
+
gap_start..gap_end
|
53
|
+
end
|
53
54
|
|
54
|
-
|
55
|
-
|
56
|
-
|
55
|
+
def furthest(other)
|
56
|
+
return self if end_date.nil? || other.nil?
|
57
|
+
return other if other.end_date.nil?
|
57
58
|
|
58
|
-
|
59
|
-
|
59
|
+
[self, other].max_by(&:end_date)
|
60
|
+
end
|
60
61
|
|
61
|
-
|
62
|
+
private
|
62
63
|
|
63
|
-
|
64
|
-
|
64
|
+
def valid?
|
65
|
+
start_date.instance_of?(Date) && (end_date.nil? || start_date < end_date)
|
66
|
+
end
|
65
67
|
end
|
66
68
|
end
|
@@ -2,66 +2,68 @@
|
|
2
2
|
|
3
3
|
require_relative "date_range"
|
4
4
|
|
5
|
-
|
6
|
-
#
|
7
|
-
|
8
|
-
|
5
|
+
module Availabiliter
|
6
|
+
# A TimeFrame is an object representing several DateRange instances. It can have a start.
|
7
|
+
# It can have only one endless DateRange.
|
8
|
+
class TimeFrame
|
9
|
+
attr_reader :start_date, :date_ranges
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
def initialize(array, start_date = nil)
|
12
|
+
@start_date = start_date
|
13
|
+
@date_ranges = build_date_ranges(array)
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
raise ArgumentError unless valid?
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
def availabilities
|
19
|
+
return [start_date..nil] if date_ranges.empty?
|
20
|
+
return build_availabilities if start_date.nil?
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
availabilities = build_availabilities
|
23
|
+
start_date < first_date_range.start_date ? availabilities.unshift(first_availability) : availabilities
|
24
|
+
end
|
24
25
|
|
25
|
-
|
26
|
+
private
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
def build_date_ranges(array)
|
29
|
+
date_range_array = array.filter_map do |range|
|
30
|
+
next if out_of_timeframe?(range.end)
|
30
31
|
|
31
|
-
|
32
|
-
|
32
|
+
DateRange.new(range.begin, range.end)
|
33
|
+
end
|
33
34
|
|
34
|
-
|
35
|
-
|
35
|
+
date_range_array.sort_by(&:start_date)
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
38
|
+
def build_availabilities
|
39
|
+
furthest_date_range = first_date_range
|
39
40
|
|
40
|
-
|
41
|
-
|
41
|
+
date_ranges.filter_map.with_index do |date_range, index|
|
42
|
+
next_date_range = date_ranges[index + 1]
|
42
43
|
|
43
|
-
|
44
|
-
|
44
|
+
furthest_date_range = furthest_date_range.furthest(date_range)
|
45
|
+
furthest_date_range.next_availability(next_date_range)
|
46
|
+
end
|
45
47
|
end
|
46
|
-
end
|
47
48
|
|
48
|
-
|
49
|
-
|
50
|
-
|
49
|
+
def out_of_timeframe?(range_end)
|
50
|
+
!start_date.nil? && (!range_end.nil? && range_end < start_date)
|
51
|
+
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
53
|
+
def first_availability
|
54
|
+
start_date..first_date_range.yesterday
|
55
|
+
end
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
57
|
+
def first_date_range
|
58
|
+
date_ranges.first
|
59
|
+
end
|
59
60
|
|
60
|
-
|
61
|
-
|
62
|
-
|
61
|
+
def valid?
|
62
|
+
end_date_valid? && date_ranges.count { |date_range| date_range.end_date.nil? } <= 1
|
63
|
+
end
|
63
64
|
|
64
|
-
|
65
|
-
|
65
|
+
def end_date_valid?
|
66
|
+
start_date.instance_of?(Date) || start_date.instance_of?(NilClass)
|
67
|
+
end
|
66
68
|
end
|
67
69
|
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: availabiliter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- lioneldebauge
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: activesupport
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 6.1.3.2
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: 6.1.3.2
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: byebug
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,7 +66,7 @@ dependencies:
|
|
80
66
|
- - "~>"
|
81
67
|
- !ruby/object:Gem::Version
|
82
68
|
version: 1.16.1
|
83
|
-
description:
|
69
|
+
description:
|
84
70
|
email:
|
85
71
|
- lionel@livecolonies.com
|
86
72
|
executables: []
|
@@ -93,7 +79,6 @@ files:
|
|
93
79
|
- ".rubocop.yml"
|
94
80
|
- CHANGELOG.md
|
95
81
|
- Gemfile
|
96
|
-
- Gemfile.lock
|
97
82
|
- LICENSE.txt
|
98
83
|
- README.md
|
99
84
|
- Rakefile
|
@@ -112,7 +97,7 @@ metadata:
|
|
112
97
|
homepage_uri: https://github.com/lioneldebauge/availabiliter.git
|
113
98
|
source_code_uri: https://github.com/lioneldebauge/availabiliter.git
|
114
99
|
changelog_uri: https://github.com/lioneldebauge/availabiliter/blob/main/CHANGELOG.md
|
115
|
-
post_install_message:
|
100
|
+
post_install_message:
|
116
101
|
rdoc_options: []
|
117
102
|
require_paths:
|
118
103
|
- lib
|
@@ -127,8 +112,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
112
|
- !ruby/object:Gem::Version
|
128
113
|
version: '0'
|
129
114
|
requirements: []
|
130
|
-
rubygems_version: 3.
|
131
|
-
signing_key:
|
115
|
+
rubygems_version: 3.1.4
|
116
|
+
signing_key:
|
132
117
|
specification_version: 4
|
133
118
|
summary: Availabiliter calculates availabilities for ruby ranges within a given time
|
134
119
|
frame.
|
data/Gemfile.lock
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
availabiliter (0.1.0)
|
5
|
-
activesupport (~> 6.1.3.2)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
activesupport (6.1.3.2)
|
11
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
12
|
-
i18n (>= 1.6, < 2)
|
13
|
-
minitest (>= 5.1)
|
14
|
-
tzinfo (~> 2.0)
|
15
|
-
zeitwerk (~> 2.3)
|
16
|
-
ast (2.4.2)
|
17
|
-
byebug (11.1.3)
|
18
|
-
concurrent-ruby (1.1.9)
|
19
|
-
diff-lcs (1.4.4)
|
20
|
-
i18n (1.8.10)
|
21
|
-
concurrent-ruby (~> 1.0)
|
22
|
-
minitest (5.14.4)
|
23
|
-
parallel (1.20.1)
|
24
|
-
parser (3.0.1.1)
|
25
|
-
ast (~> 2.4.1)
|
26
|
-
rainbow (3.0.0)
|
27
|
-
rake (13.0.3)
|
28
|
-
regexp_parser (2.1.1)
|
29
|
-
rexml (3.2.5)
|
30
|
-
rspec (3.10.0)
|
31
|
-
rspec-core (~> 3.10.0)
|
32
|
-
rspec-expectations (~> 3.10.0)
|
33
|
-
rspec-mocks (~> 3.10.0)
|
34
|
-
rspec-core (3.10.1)
|
35
|
-
rspec-support (~> 3.10.0)
|
36
|
-
rspec-expectations (3.10.1)
|
37
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
38
|
-
rspec-support (~> 3.10.0)
|
39
|
-
rspec-mocks (3.10.2)
|
40
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
41
|
-
rspec-support (~> 3.10.0)
|
42
|
-
rspec-support (3.10.2)
|
43
|
-
rubocop (1.16.1)
|
44
|
-
parallel (~> 1.10)
|
45
|
-
parser (>= 3.0.0.0)
|
46
|
-
rainbow (>= 2.2.2, < 4.0)
|
47
|
-
regexp_parser (>= 1.8, < 3.0)
|
48
|
-
rexml
|
49
|
-
rubocop-ast (>= 1.7.0, < 2.0)
|
50
|
-
ruby-progressbar (~> 1.7)
|
51
|
-
unicode-display_width (>= 1.4.0, < 3.0)
|
52
|
-
rubocop-ast (1.7.0)
|
53
|
-
parser (>= 3.0.1.1)
|
54
|
-
ruby-progressbar (1.11.0)
|
55
|
-
tzinfo (2.0.4)
|
56
|
-
concurrent-ruby (~> 1.0)
|
57
|
-
unicode-display_width (2.0.0)
|
58
|
-
zeitwerk (2.4.2)
|
59
|
-
|
60
|
-
PLATFORMS
|
61
|
-
arm64-darwin-20
|
62
|
-
|
63
|
-
DEPENDENCIES
|
64
|
-
availabiliter!
|
65
|
-
byebug (~> 11.1.3)
|
66
|
-
rake (~> 13.0.3)
|
67
|
-
rspec (~> 3.10)
|
68
|
-
rubocop (~> 1.16.1)
|
69
|
-
|
70
|
-
BUNDLED WITH
|
71
|
-
2.2.15
|