timeboss 0.3.1

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.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +23 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. data/.gitignore +5 -0
  5. data/.replit +2 -0
  6. data/.rspec +2 -0
  7. data/.travis.yml +16 -0
  8. data/.yardopts +1 -0
  9. data/CODE_OF_CONDUCT.md +76 -0
  10. data/Gemfile +3 -0
  11. data/LICENSE.txt +22 -0
  12. data/README.md +233 -0
  13. data/Rakefile +5 -0
  14. data/bin/tbsh +15 -0
  15. data/lib/tasks/calendars.rake +22 -0
  16. data/lib/tasks/timeboss.rake +6 -0
  17. data/lib/timeboss.rb +6 -0
  18. data/lib/timeboss/calendar.rb +64 -0
  19. data/lib/timeboss/calendar/day.rb +48 -0
  20. data/lib/timeboss/calendar/half.rb +22 -0
  21. data/lib/timeboss/calendar/month.rb +22 -0
  22. data/lib/timeboss/calendar/parser.rb +53 -0
  23. data/lib/timeboss/calendar/period.rb +154 -0
  24. data/lib/timeboss/calendar/quarter.rb +22 -0
  25. data/lib/timeboss/calendar/support/formatter.rb +33 -0
  26. data/lib/timeboss/calendar/support/month_basis.rb +21 -0
  27. data/lib/timeboss/calendar/support/monthly_unit.rb +55 -0
  28. data/lib/timeboss/calendar/support/navigable.rb +72 -0
  29. data/lib/timeboss/calendar/support/shiftable.rb +241 -0
  30. data/lib/timeboss/calendar/support/translatable.rb +93 -0
  31. data/lib/timeboss/calendar/support/unit.rb +88 -0
  32. data/lib/timeboss/calendar/waypoints.rb +12 -0
  33. data/lib/timeboss/calendar/waypoints/absolute.rb +113 -0
  34. data/lib/timeboss/calendar/waypoints/relative.rb +267 -0
  35. data/lib/timeboss/calendar/week.rb +53 -0
  36. data/lib/timeboss/calendar/year.rb +18 -0
  37. data/lib/timeboss/calendars.rb +53 -0
  38. data/lib/timeboss/calendars/broadcast.rb +32 -0
  39. data/lib/timeboss/calendars/gregorian.rb +30 -0
  40. data/lib/timeboss/support/shellable.rb +17 -0
  41. data/lib/timeboss/version.rb +4 -0
  42. data/spec/calendar/day_spec.rb +60 -0
  43. data/spec/calendar/quarter_spec.rb +32 -0
  44. data/spec/calendar/support/monthly_unit_spec.rb +85 -0
  45. data/spec/calendar/support/unit_spec.rb +90 -0
  46. data/spec/calendar/week_spec.rb +80 -0
  47. data/spec/calendars/broadcast_spec.rb +796 -0
  48. data/spec/calendars/gregorian_spec.rb +684 -0
  49. data/spec/calendars_spec.rb +50 -0
  50. data/spec/spec_helper.rb +12 -0
  51. data/timeboss.gemspec +31 -0
  52. metadata +215 -0
@@ -0,0 +1,21 @@
1
+ module TimeBoss
2
+ class Calendar
3
+ module Support
4
+ # @abstract
5
+ # A MonthBasis must define a `#start_date` and `#end_date` method.
6
+ # These methods should be calculated based on the incoming `#year` and `#month` values.
7
+ class MonthBasis
8
+ attr_reader :year, :month
9
+
10
+ def initialize(year, month)
11
+ @year = year
12
+ @month = month
13
+ end
14
+
15
+ def to_range
16
+ @_to_range ||= start_date .. end_date
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+ require_relative './unit'
3
+
4
+ module TimeBoss
5
+ class Calendar
6
+ module Support
7
+ class MonthlyUnit < Unit
8
+ attr_reader :year_index, :index
9
+
10
+ def initialize(calendar, year_index, index, start_date, end_date)
11
+ super(calendar, start_date, end_date)
12
+ @year_index = year_index
13
+ @index = index
14
+ end
15
+
16
+ # Get a stringified representation of this unit.
17
+ # @return [String] (e.g. "2020Q3: 2020-06-29 thru 2020-09-27")
18
+ def to_s
19
+ "#{name}: #{start_date} thru #{end_date}"
20
+ end
21
+
22
+ # Get a list of weeks contained within this period.
23
+ # @return [Array<Week>]
24
+ def weeks
25
+ base = calendar.year(year_index)
26
+ num_weeks = (((base.end_date - base.start_date) + 1) / 7.0).to_i
27
+ num_weeks.times.map { |i| Week.new(calendar, base.start_date + (i * 7).days, base.start_date + ((i * 7) + 6).days) }
28
+ .select { |w| w.start_date.between?(start_date, end_date) }
29
+ end
30
+
31
+ private
32
+
33
+ def max_index
34
+ 12 / self.class::NUM_MONTHS
35
+ end
36
+
37
+ def up
38
+ if index == max_index
39
+ calendar.send(self.class.type, year_index + 1, 1)
40
+ else
41
+ calendar.send(self.class.type, year_index, index + 1)
42
+ end
43
+ end
44
+
45
+ def down
46
+ if index == 1
47
+ calendar.send(self.class.type, year_index - 1, max_index)
48
+ else
49
+ calendar.send(self.class.type, year_index, index - 1)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+ module TimeBoss
3
+ class Calendar
4
+ module Support
5
+ module Navigable
6
+ # @overload previous
7
+ # Fetch the previous unit relative to this unit.
8
+ # @return [Unit]
9
+ # @overload previous(value)
10
+ # Fetch some previous number of units relative to this unit
11
+ # @param quantity [Integer]
12
+ # @return [Array<Unit>]
13
+ def previous(quantity = nil)
14
+ return down if quantity.nil?
15
+ gather(:previous, quantity).reverse
16
+ end
17
+
18
+ # @overload next
19
+ # Fetch the next unit relative to this unit.
20
+ # @return [Unit]
21
+ # @overload next(value)
22
+ # Fetch some next number of units relative to this unit
23
+ # @param quantity [Integer]
24
+ # @return [Array<Unit>]
25
+ def next(quantity = nil)
26
+ return up if quantity.nil?
27
+ gather(:next, quantity)
28
+ end
29
+
30
+ # Fetch the unit some number of units prior to this unit.
31
+ # @param quantity [Integer]
32
+ # @return [Unit]
33
+ def ago(quantity)
34
+ previous(quantity + 1).first
35
+ end
36
+
37
+ # Fetch the unit some number of units after this unit.
38
+ # @param quantity [Integer]
39
+ # @return [Unit]
40
+ def ahead(quantity)
41
+ self.next(quantity + 1).last
42
+ end
43
+
44
+ # Fetch a list of units from this unit until some date.
45
+ # @param end_date [Date]
46
+ # @return [Array<Unit>]
47
+ def until(end_date)
48
+ entry = self
49
+ [entry].tap do |entries|
50
+ until entry.end_date >= end_date
51
+ entry = entry.next
52
+ entries << entry
53
+ end
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def gather(navigator, quantity)
60
+ [].tap do |entries|
61
+ entry = self
62
+ while quantity > 0
63
+ entries << entry
64
+ entry = entry.send(navigator)
65
+ quantity -= 1
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,241 @@
1
+ # frozen_string_literal: true
2
+ module TimeBoss
3
+ class Calendar
4
+ module Support
5
+ module Shiftable
6
+ Support::Translatable::PERIODS.each do |period|
7
+ periods = period.pluralize
8
+
9
+ define_method("in_#{period}") do
10
+ base = send(periods)
11
+ return unless base.length == 1
12
+ base.first.send(self.class.type.to_s.pluralize).find_index { |p| p == self } + 1
13
+ end
14
+
15
+ define_method("#{periods}_ago") do |offset|
16
+ base_offset = send("in_#{period}") or return
17
+ (calendar.send("this_#{period}") - offset).send(self.class.type.to_s.pluralize)[base_offset - 1]
18
+ end
19
+
20
+ define_method("#{periods}_ahead") { |o| send("#{periods}_ago", o * -1) }
21
+
22
+ define_method("last_#{period}") { send("#{periods}_ago", 1) }
23
+ define_method("this_#{period}") { send("#{periods}_ago", 0) }
24
+ define_method("next_#{period}") { send("#{periods}_ahead", 1) }
25
+ end
26
+
27
+ alias_method :yesterday, :last_day
28
+ alias_method :today, :this_day
29
+ alias_method :tomorrow, :next_day
30
+
31
+ #
32
+ # i hate this
33
+ #
34
+
35
+ ### Days
36
+
37
+ # @!method in_day
38
+ # Get the index within the day that this unit falls in.
39
+ # Returns nil if no single day can be identified.
40
+ # @return [Integer, nil]
41
+
42
+ # @!method days_ago
43
+ # Get the index-relative day some number of days ago.
44
+ # Returns nil if no single day can be identified.
45
+ # @param offset [Integer] the number of days back to shift this period
46
+ # @return [Calendar::Day, nil]
47
+
48
+ # @!method days_ahead
49
+ # Get the index-relative day some number of days ahead.
50
+ # Returns nil if no single day can be identified.
51
+ # @param offset [Integer] the number of days forward to shift this period
52
+ # @return [Calendar::Day, nil]
53
+
54
+ # @!method last_day
55
+ # Get the index-relative day 1 day ago.
56
+ # Returns nil if no single day can be identified.
57
+ # @return [Calendar::Day, nil]
58
+
59
+ # @!method this_day
60
+ # Get the index-relative day for this day.
61
+ # Returns nil if no single day can be identified.
62
+ # @return [Calendar::Day, nil]
63
+
64
+ # @!method next_day
65
+ # Get the index-relative day 1 day forward.
66
+ # Returns nil if no single day can be identified.
67
+ # @return [Calendar::Day, nil]
68
+
69
+ ### Weeks
70
+
71
+ # @!method in_week
72
+ # Get the index within the week that this unit falls in.
73
+ # Returns nil if no single week can be identified.
74
+ # @return [Integer, nil]
75
+
76
+ # @!method weeks_ago
77
+ # Get the index-relative week some number of weeks ago.
78
+ # Returns nil if no single week can be identified.
79
+ # @param offset [Integer] the number of weeks back to shift this period
80
+ # @return [Calendar::Week, nil]
81
+
82
+ # @!method weeks_ahead
83
+ # Get the index-relative week some number of weeks ahead.
84
+ # Returns nil if no single week can be identified.
85
+ # @param offset [Integer] the number of weeks forward to shift this period
86
+ # @return [Calendar::Week, nil]
87
+
88
+ # @!method last_week
89
+ # Get the index-relative week 1 week ago.
90
+ # Returns nil if no single week can be identified.
91
+ # @return [Calendar::Week, nil]
92
+
93
+ # @!method this_week
94
+ # Get the index-relative week for this week.
95
+ # Returns nil if no single week can be identified.
96
+ # @return [Calendar::Week, nil]
97
+
98
+ # @!method next_week
99
+ # Get the index-relative week 1 week forward.
100
+ # Returns nil if no single week can be identified.
101
+ # @return [Calendar::Week, nil]
102
+
103
+ ### Months
104
+
105
+ # @!method in_month
106
+ # Get the index within the month that this unit falls in.
107
+ # Returns nil if no single month can be identified.
108
+ # @return [Integer, nil]
109
+
110
+ # @!method months_ago
111
+ # Get the index-relative month some number of months ago.
112
+ # Returns nil if no single month can be identified.
113
+ # @param offset [Integer] the number of months back to shift this period
114
+ # @return [Calendar::Month, nil]
115
+
116
+ # @!method months_ahead
117
+ # Get the index-relative month some number of months ahead.
118
+ # Returns nil if no single month can be identified.
119
+ # @param offset [Integer] the number of months forward to shift this period
120
+ # @return [Calendar::Month, nil]
121
+
122
+ # @!method last_month
123
+ # Get the index-relative month 1 month ago.
124
+ # Returns nil if no single month can be identified.
125
+ # @return [Calendar::Month, nil]
126
+
127
+ # @!method this_month
128
+ # Get the index-relative month for this month.
129
+ # Returns nil if no single month can be identified.
130
+ # @return [Calendar::Month, nil]
131
+
132
+ # @!method next_month
133
+ # Get the index-relative month 1 month forward.
134
+ # Returns nil if no single month can be identified.
135
+ # @return [Calendar::Month, nil]
136
+
137
+ ### Quarters
138
+
139
+ # @!method in_quarter
140
+ # Get the index within the quarter that this unit falls in.
141
+ # Returns nil if no single quarter can be identified.
142
+ # @return [Integer, nil]
143
+
144
+ # @!method quarters_ago
145
+ # Get the index-relative quarter some number of quarters ago.
146
+ # Returns nil if no single quarter can be identified.
147
+ # @param offset [Integer] the number of quarters back to shift this period
148
+ # @return [Calendar::Quarter, nil]
149
+
150
+ # @!method quarters_ahead
151
+ # Get the index-relative quarter some number of quarters ahead.
152
+ # Returns nil if no single quarter can be identified.
153
+ # @param offset [Integer] the number of quarters forward to shift this period
154
+ # @return [Calendar::Quarter, nil]
155
+
156
+ # @!method last_quarter
157
+ # Get the index-relative quarter 1 quarter ago.
158
+ # Returns nil if no single quarter can be identified.
159
+ # @return [Calendar::Quarter, nil]
160
+
161
+ # @!method this_quarter
162
+ # Get the index-relative quarter for this quarter.
163
+ # Returns nil if no single quarter can be identified.
164
+ # @return [Calendar::Quarter, nil]
165
+
166
+ # @!method next_quarter
167
+ # Get the index-relative quarter 1 quarter forward.
168
+ # Returns nil if no single quarter can be identified.
169
+ # @return [Calendar::Quarter, nil]
170
+
171
+ ### Halves
172
+
173
+ # @!method in_half
174
+ # Get the index within the half that this unit falls in.
175
+ # Returns nil if no single half can be identified.
176
+ # @return [Integer, nil]
177
+
178
+ # @!method halves_ago
179
+ # Get the index-relative half some number of halves ago.
180
+ # Returns nil if no single half can be identified.
181
+ # @param offset [Integer] the number of halves back to shift this period
182
+ # @return [Calendar::Half, nil]
183
+
184
+ # @!method halves_ahead
185
+ # Get the index-relative half some number of halves ahead.
186
+ # Returns nil if no single half can be identified.
187
+ # @param offset [Integer] the number of halves forward to shift this period
188
+ # @return [Calendar::Half, nil]
189
+
190
+ # @!method last_half
191
+ # Get the index-relative half 1 half ago.
192
+ # Returns nil if no single half can be identified.
193
+ # @return [Calendar::Half, nil]
194
+
195
+ # @!method this_half
196
+ # Get the index-relative half for this half.
197
+ # Returns nil if no single half can be identified.
198
+ # @return [Calendar::Half, nil]
199
+
200
+ # @!method next_half
201
+ # Get the index-relative half 1 half forward.
202
+ # Returns nil if no single half can be identified.
203
+ # @return [Calendar::Half, nil]
204
+
205
+ ### Years
206
+
207
+ # @!method in_year
208
+ # Get the index within the year that this unit falls in.
209
+ # Returns nil if no single year can be identified.
210
+ # @return [Integer, nil]
211
+
212
+ # @!method years_ago
213
+ # Get the index-relative year some number of years ago.
214
+ # Returns nil if no single year can be identified.
215
+ # @param offset [Integer] the number of years back to shift this period
216
+ # @return [Calendar::Year, nil]
217
+
218
+ # @!method years_ahead
219
+ # Get the index-relative year some number of years ahead.
220
+ # Returns nil if no single year can be identified.
221
+ # @param offset [Integer] the number of years forward to shift this period
222
+ # @return [Calendar::Year, nil]
223
+
224
+ # @!method last_year
225
+ # Get the index-relative year 1 year ago.
226
+ # Returns nil if no single year can be identified.
227
+ # @return [Calendar::Year, nil]
228
+
229
+ # @!method this_year
230
+ # Get the index-relative year for this year.
231
+ # Returns nil if no single year can be identified.
232
+ # @return [Calendar::Year, nil]
233
+
234
+ # @!method next_year
235
+ # Get the index-relative year 1 year forward.
236
+ # Returns nil if no single year can be identified.
237
+ # @return [Calendar::Year, nil]
238
+ end
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+ module TimeBoss
3
+ class Calendar
4
+ module Support
5
+ module Translatable
6
+ PERIODS = %w[day week month quarter half year]
7
+
8
+ PERIODS.each do |period|
9
+ periods = period.pluralize
10
+
11
+ define_method(periods) { calendar.send("#{periods}_for", self) }
12
+
13
+ define_method(period) do |index = nil|
14
+ entries = send(periods)
15
+ return entries[index - 1] unless index.nil?
16
+ return nil unless entries.length == 1
17
+ entries.first
18
+ end
19
+ end
20
+
21
+ #
22
+ # i hate this
23
+ #
24
+
25
+ ### Days
26
+
27
+ # @!method days
28
+ # Get a list of days that fall within this unit.
29
+ # @return [Array<Calendar::Day>]
30
+
31
+ # @!method day(index = nil)
32
+ # Get the day this unit represents.
33
+ # Returns nil if no single day can be identified.
34
+ # @return [Array<Calendar::Day>, nil]
35
+
36
+ ### Weeks
37
+
38
+ # @!method weeks
39
+ # Get a list of weeks that fall within this unit.
40
+ # @return [Array<Calendar::Week>]
41
+
42
+ # @!method week(index = nil)
43
+ # Get the week this unit represents.
44
+ # Returns nil if no single week can be identified.
45
+ # @return [Array<Calendar::Week>, nil]
46
+
47
+ ### Months
48
+
49
+ # @!method months
50
+ # Get a list of months that fall within this unit.
51
+ # @return [Array<Calendar::Month>]
52
+
53
+ # @!method month(index = nil)
54
+ # Get the month this unit represents.
55
+ # Returns nil if no single month can be identified.
56
+ # @return [Array<Calendar::Month>, nil]
57
+
58
+ ### Quarters
59
+
60
+ # @!method quarters
61
+ # Get a list of quarters that fall within this unit.
62
+ # @return [Array<Calendar::Quarter>]
63
+
64
+ # @!method quarter(index = nil)
65
+ # Get the quarter this unit represents.
66
+ # Returns nil if no single quarter can be identified.
67
+ # @return [Array<Calendar::Quarter>, nil]
68
+
69
+ ### Halves
70
+
71
+ # @!method halves
72
+ # Get a list of halves that fall within this unit.
73
+ # @return [Array<Calendar::Half>]
74
+
75
+ # @!method half(index = nil)
76
+ # Get the half this unit represents.
77
+ # Returns nil if no single half can be identified.
78
+ # @return [Array<Calendar::Half>, nil]
79
+
80
+ ### Years
81
+
82
+ # @!method years
83
+ # Get a list of years that fall within this unit.
84
+ # @return [Array<Calendar::Year>]
85
+
86
+ # @!method year(index = nil)
87
+ # Get the year this unit represents.
88
+ # Returns nil if no single year can be identified.
89
+ # @return [Array<Calendar::Year>, nil]
90
+ end
91
+ end
92
+ end
93
+ end