Almirah 0.4.4 → 0.4.5

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.
@@ -1,112 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'date'
4
- require 'set'
5
-
6
- # Projects the working-day planning axis (ADR-198 / ADR-195) onto real calendar
7
- # dates (ADR-205). Working day 1 is the first working date on or after the anchor;
8
- # Saturdays, Sundays, and any configured holiday are non-working — skipped when
9
- # counting working days, but still occupying calendar columns. This is a pure
10
- # projection: it never changes the schedule, the chain, or the buffer.
11
- class WorkingCalendar
12
- SATURDAY = 6
13
- SUNDAY = 0
14
- FRIDAY = 5
15
-
16
- def initialize(anchor: Date.today, holidays: [])
17
- @holidays = holidays.to_set
18
- @start = first_working_on_or_after(anchor)
19
- end
20
-
21
- # The calendar date of the n-th working day (1-based) counted from the anchor.
22
- def date_for(working_day)
23
- return @start if working_day <= 1
24
-
25
- date = @start
26
- remaining = working_day - 1
27
- while remaining.positive?
28
- date += 1
29
- remaining -= 1 if working?(date)
30
- end
31
- date
32
- end
33
-
34
- # Every calendar date from working day 1 through the working_day_count-th working
35
- # day inclusive, including the non-working dates in between. Empty for a count
36
- # below 1.
37
- def columns(working_day_count)
38
- return [] if working_day_count < 1
39
-
40
- (@start..date_for(working_day_count)).to_a
41
- end
42
-
43
- # The 0-based calendar column index of the n-th working day within columns.
44
- def column_index(working_day)
45
- (date_for(working_day) - @start).to_i
46
- end
47
-
48
- # The compact business-day axis (ADR-206): weekday dates from working day 1
49
- # through the working_day_count-th working day, excluding Saturdays and Sundays
50
- # but including weekday holidays. Empty for a count below 1.
51
- def business_columns(working_day_count)
52
- return [] if working_day_count < 1
53
-
54
- (@start..date_for(working_day_count)).reject { |date| weekend?(date) }
55
- end
56
-
57
- # The 0-based business-column index of the n-th working day: the count of
58
- # weekdays (holidays included, weekends excluded) from the anchor through it.
59
- def business_index(working_day)
60
- (@start..date_for(working_day)).count { |date| !weekend?(date) } - 1
61
- end
62
-
63
- # The first `count` business-day (weekday) dates from the anchor, holidays
64
- # included and weekends excluded — the calendar labels for an axis of `count`
65
- # columns, even when it runs past the schedule to cover authored actuals
66
- # (ADR-213). Empty for a count below 1.
67
- def business_axis(count)
68
- return [] if count < 1
69
-
70
- dates = []
71
- date = @start
72
- while dates.length < count
73
- dates << date unless weekend?(date)
74
- date += 1
75
- end
76
- dates
77
- end
78
-
79
- # The 0-based business-column index of a real calendar date relative to the
80
- # anchor (ADR-213): the count of weekdays from the anchor through the date, minus
81
- # one. A weekend date snaps to the preceding weekday's column; a date on or
82
- # before the anchor clamps to column 0. Used to place authored committed/logged
83
- # dates on the same business-day axis as the schedule.
84
- def business_column_for(date)
85
- return 0 if date <= @start
86
-
87
- (@start..date).count { |d| !weekend?(d) } - 1
88
- end
89
-
90
- def friday?(date)
91
- date.wday == FRIDAY
92
- end
93
-
94
- def working?(date)
95
- !non_working?(date)
96
- end
97
-
98
- def non_working?(date)
99
- weekend?(date) || @holidays.include?(date)
100
- end
101
-
102
- def weekend?(date)
103
- [SATURDAY, SUNDAY].include?(date.wday)
104
- end
105
-
106
- private
107
-
108
- def first_working_on_or_after(date)
109
- date += 1 while non_working?(date)
110
- date
111
- end
112
- end