timeboss 1.0.0 → 1.1.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.
- checksums.yaml +4 -4
- data/.github/workflows/gem-push.yml +31 -0
- data/.github/workflows/ruby.yml +35 -0
- data/.travis.yml +3 -2
- data/Gemfile +2 -1
- data/README.md +17 -2
- data/Rakefile +3 -1
- data/bin/tbsh +2 -2
- data/lib/tasks/calendars.rake +5 -5
- data/lib/tasks/timeboss.rake +2 -2
- data/lib/timeboss/calendar/day.rb +3 -2
- data/lib/timeboss/calendar/half.rb +2 -1
- data/lib/timeboss/calendar/month.rb +2 -1
- data/lib/timeboss/calendar/parser.rb +9 -8
- data/lib/timeboss/calendar/period.rb +9 -6
- data/lib/timeboss/calendar/quarter.rb +2 -1
- data/lib/timeboss/calendar/support/formatter.rb +5 -4
- data/lib/timeboss/calendar/support/has_fiscal_weeks.rb +17 -0
- data/lib/timeboss/calendar/support/has_iso_weeks.rb +30 -0
- data/lib/timeboss/calendar/support/month_basis.rb +1 -1
- data/lib/timeboss/calendar/support/monthly_unit.rb +8 -8
- data/lib/timeboss/calendar/support/navigable.rb +2 -1
- data/lib/timeboss/calendar/support/shiftable.rb +12 -11
- data/lib/timeboss/calendar/support/translatable.rb +3 -2
- data/lib/timeboss/calendar/support/unit.rb +20 -13
- data/lib/timeboss/calendar/waypoints/absolute.rb +4 -3
- data/lib/timeboss/calendar/waypoints/relative.rb +14 -13
- data/lib/timeboss/calendar/week.rb +3 -2
- data/lib/timeboss/calendar/year.rb +2 -1
- data/lib/timeboss/calendar.rb +8 -7
- data/lib/timeboss/calendars/broadcast.rb +10 -7
- data/lib/timeboss/calendars/gregorian.rb +4 -5
- data/lib/timeboss/calendars.rb +3 -2
- data/lib/timeboss/version.rb +2 -1
- data/lib/timeboss.rb +2 -0
- data/spec/{calendar → lib/timeboss/calendar}/day_spec.rb +14 -14
- data/spec/{calendar → lib/timeboss/calendar}/quarter_spec.rb +9 -9
- data/spec/lib/timeboss/calendar/support/monthly_unit_spec.rb +91 -0
- data/spec/{calendar → lib/timeboss/calendar}/support/unit_spec.rb +23 -22
- data/spec/{calendar → lib/timeboss/calendar}/week_spec.rb +20 -20
- data/spec/lib/timeboss/calendars/broadcast_spec.rb +796 -0
- data/spec/lib/timeboss/calendars/gregorian_spec.rb +793 -0
- data/spec/{calendars_spec.rb → lib/timeboss/calendars_spec.rb} +19 -19
- data/spec/spec_helper.rb +2 -2
- data/timeboss.gemspec +16 -14
- metadata +51 -20
- data/lib/timeboss/support/shellable.rb +0 -17
- data/spec/calendar/support/monthly_unit_spec.rb +0 -85
- data/spec/calendars/broadcast_spec.rb +0 -796
- data/spec/calendars/gregorian_spec.rb +0 -684
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d4780b44297b7a8ca671619625c7c868a1ca3293452c0be5e3fede1fc533da8
|
4
|
+
data.tar.gz: '0668065a605519760653ede09a54ce458e4ed78ec7a34bec5013a0fe7e4ffb2f'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ce4fe447803b784adea3a2f397d031a669fc158046659b98b0994e8f707707c32b87930815cf5cae2774b03950f801033c355dea4efaf685b0b9e23e099e65f
|
7
|
+
data.tar.gz: 4b73ad3248db6c0e4c359b433bf011c1ce20647a5611415b7b56969e96d2b5aa62ea33d5247491aced44fa0f2dfc529300deac36d1dbd20370482d0b48ef232b
|
@@ -0,0 +1,31 @@
|
|
1
|
+
name: Ruby Gem
|
2
|
+
|
3
|
+
on:
|
4
|
+
release:
|
5
|
+
types: [published]
|
6
|
+
|
7
|
+
jobs:
|
8
|
+
build:
|
9
|
+
name: Build + Publish
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
permissions:
|
12
|
+
contents: read
|
13
|
+
packages: write
|
14
|
+
|
15
|
+
steps:
|
16
|
+
- uses: actions/checkout@v2
|
17
|
+
- name: Set up Ruby 2.6
|
18
|
+
uses: actions/setup-ruby@v1
|
19
|
+
with:
|
20
|
+
ruby-version: 2.6.x
|
21
|
+
|
22
|
+
- name: Publish to RubyGems
|
23
|
+
run: |
|
24
|
+
mkdir -p $HOME/.gem
|
25
|
+
touch $HOME/.gem/credentials
|
26
|
+
chmod 0600 $HOME/.gem/credentials
|
27
|
+
printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
|
28
|
+
gem build *.gemspec
|
29
|
+
gem push *.gem
|
30
|
+
env:
|
31
|
+
GEM_HOST_API_KEY: "${{secrets.RUBYGEMS_AUTH_TOKEN}}"
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Ruby
|
9
|
+
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
branches: [ master ]
|
13
|
+
pull_request:
|
14
|
+
branches: [ master ]
|
15
|
+
|
16
|
+
jobs:
|
17
|
+
test:
|
18
|
+
|
19
|
+
runs-on: ubuntu-latest
|
20
|
+
strategy:
|
21
|
+
matrix:
|
22
|
+
ruby-version: ['2.7', '3.0']
|
23
|
+
|
24
|
+
steps:
|
25
|
+
- uses: actions/checkout@v2
|
26
|
+
- name: Set up Ruby
|
27
|
+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
28
|
+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
29
|
+
# uses: ruby/setup-ruby@v1
|
30
|
+
uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
|
31
|
+
with:
|
32
|
+
ruby-version: ${{ matrix.ruby-version }}
|
33
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
34
|
+
- name: Run tests
|
35
|
+
run: bundle exec rspec
|
data/.travis.yml
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 2.4
|
4
3
|
- 2.5
|
5
4
|
- 2.6
|
5
|
+
- 2.7
|
6
|
+
- 3.0
|
6
7
|
script:
|
7
8
|
- bundle exec rspec
|
8
9
|
deploy:
|
9
10
|
provider: rubygems
|
10
11
|
api_key:
|
11
|
-
secure:
|
12
|
+
secure: f7s86k3ZRgaao32goumx0EFSquj8v8vwLBQP0uPd5lZ5OlDjUIbzAGCLpP4IARFf7MhYUUxWqwU7A0Z2MJHgmf4hT2VdVco4kGC4WztMgSI2JwY8Uo21/QJgI82jIfZ6yfSjF8OC3eh9irqJxXfhzspO9DY4p+nJkMJnpG5Y1e5FjS9zM3gS80TD9fauIMEi3fOLDNYEZ95SgjrkX2MHDYQWN1nfFlkRtybSHJ2u2Ad3Ulr5c/1gIoJviJCm8l5Bwo3MnvBtSuHHjFOaH9UTcmDUGpBjr7GMoqn3m053aB1F3ImYwL9+il0rtj+PE1lNaVbUM/QDKp8gDcbo433m8oMiGRpouz0fdIi95fqsshZmSU9sZX6HPiOuURXXwrjW7n3bj71+qZ7zWPTyZB8p3Y6ocp/r6Aj0ewELJksjnbYqSuyYv0o5sKTh2AUMawcqWAnDlZWgMq4UqKQiaWlhZMN1guQIWO6Xq9xdoiIxcqRUTJ7dUAGsfv+GIs2iPLvh20DHudYN70J5b4xzZLFgPQOJbTGlQQtC18m2PaYvcdsZ1qzttQIs0fcgeKno1Ltcman6/yqbAdKsSjifLUcdqHiWOUk5Dh5l4S+iSVazILVFFHwV89JI1+ipuS1nnIaRcmfIkV3GB+aXcbwwYc89mLkXBVmezs+scygK0KUhoyU=
|
12
13
|
gem: timeboss
|
13
14
|
on:
|
14
15
|
tags: true
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# TimeBoss
|
1
|
+
# TimeBoss  [](https://badge.fury.io/rb/timeboss)
|
2
2
|
|
3
3
|
A gem providing convenient navigation of the [Broadcast Calendar](https://en.wikipedia.org/wiki/Broadcast_calendar), the standard Gregorian calendar, and is easily extensible to support multiple financial calendars.
|
4
4
|
|
@@ -139,7 +139,7 @@ period = calendar.parse('2020W3..2020Q1')
|
|
139
139
|
The examples above are just samples. Try different periods, operators, etc. All of the non-week-based operations will work similarly on the `TimeBoss::Calendars::Gregorian` calendar.
|
140
140
|
|
141
141
|
### REPL
|
142
|
-
To open a REPL for the broadcast calendar, use the `tbsh` executable, or the `timeboss:calendars:broadcast:repl` rake task.
|
142
|
+
To open a [REPL](https://repl.it/github/kevinstuffandthings/timeboss) locally for the broadcast calendar, use the `tbsh` executable, or the `timeboss:calendars:broadcast:repl` rake task.
|
143
143
|
|
144
144
|
For the Gregorian calendar (or any other implemented calendars), supply the name on the command line.
|
145
145
|
- `tbsh gregorian`
|
@@ -157,6 +157,12 @@ $ tbsh
|
|
157
157
|
=> ["2020M7", "2020M8", "2020M9", "2020M10", "2020M11", "2020M12", "2021M1", "2021M2", "2021M3", "2021M4", "2021M5", "2021M6", "2021M7", "2021M8", "2021M9"]
|
158
158
|
```
|
159
159
|
|
160
|
+
If you want to try things out locally without installing the gem or updating your ruby environment, you can use [Docker](https://docker.com):
|
161
|
+
|
162
|
+
```bash
|
163
|
+
$ docker run --rm -it ruby:3.0-slim /bin/bash -c "gem install timeboss shellable >/dev/null && tbsh"
|
164
|
+
```
|
165
|
+
|
160
166
|
_Having trouble with the REPL? If you are using the examples from the [Usage](#Usage) section, keep in mind that the REPL is already in the context of the calendar -- so you don't need to specify the receiver!_
|
161
167
|
|
162
168
|
## Creating new calendars
|
@@ -164,9 +170,14 @@ To create a custom calendar, simply extend the `TimeBoss::Calendar` class, and i
|
|
164
170
|
|
165
171
|
```ruby
|
166
172
|
require 'timeboss/calendar'
|
173
|
+
require 'timeboss/calendar/support/has_fiscal_weeks'
|
167
174
|
|
168
175
|
module MyCalendars
|
169
176
|
class AugustFiscal < TimeBoss::Calendar
|
177
|
+
# The calendar we wish to implement has "fiscal weeks", meaning that the weeks start on
|
178
|
+
# the day of the containing period.
|
179
|
+
include TimeBoss::Calendar::Support::HasFiscalWeeks
|
180
|
+
|
170
181
|
def initialize
|
171
182
|
# For each calendar, operation, the class will be instantiated with an ordinal value
|
172
183
|
# for `year` and `month`. It is the instance's job to translate those ordinals into
|
@@ -231,3 +242,7 @@ With the new calendar implemented, it can be accessed in one of 2 ways:
|
|
231
242
|
calendar = TimeBoss::Calendars[:august_fiscal]
|
232
243
|
calendar.this_year
|
233
244
|
```
|
245
|
+
|
246
|
+
# Problems?
|
247
|
+
Please submit an [issue](https://github.com/kevinstuffandthings/timeboss/issues).
|
248
|
+
We'll figure out how to get you up and running with TimeBoss as smoothly as possible.
|
data/Rakefile
CHANGED
data/bin/tbsh
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'timeboss/calendars'
|
4
|
-
require '
|
4
|
+
require 'shellable'
|
5
5
|
|
6
6
|
calendar = if ARGV.length == 1
|
7
7
|
TimeBoss::Calendars[ARGV.first]
|
@@ -12,4 +12,4 @@ calendar = if ARGV.length == 1
|
|
12
12
|
abort "Unknown calendar" if calendar.nil?
|
13
13
|
|
14
14
|
puts "Active calendar: #{calendar.title}"
|
15
|
-
|
15
|
+
Shellable.open(calendar)
|
data/lib/tasks/calendars.rake
CHANGED
@@ -1,18 +1,18 @@
|
|
1
|
-
require
|
1
|
+
require "./lib/timeboss/calendars"
|
2
2
|
|
3
3
|
namespace :timeboss do
|
4
4
|
namespace :calendars do
|
5
5
|
TimeBoss::Calendars.each do |entry|
|
6
6
|
namespace entry.name do
|
7
7
|
desc "Evaluate an expression for the #{entry.name} calendar"
|
8
|
-
task :evaluate, %i[expression] => [
|
8
|
+
task :evaluate, %i[expression] => ["timeboss:init"] do |_, args|
|
9
9
|
puts entry.calendar.parse(args[:expression])
|
10
10
|
end
|
11
11
|
|
12
12
|
desc "Open a REPL with the #{entry.name} calendar"
|
13
|
-
task repl: [
|
14
|
-
require
|
15
|
-
|
13
|
+
task repl: ["timeboss:init"] do
|
14
|
+
require "shellable"
|
15
|
+
Shellable.open(entry.calendar)
|
16
16
|
end
|
17
17
|
|
18
18
|
task shell: ["timeboss:calendars:#{entry.name}:repl"]
|
data/lib/tasks/timeboss.rake
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require_relative "./support/unit"
|
3
4
|
|
4
5
|
module TimeBoss
|
5
6
|
class Calendar
|
@@ -17,7 +18,7 @@ module TimeBoss
|
|
17
18
|
# Get a "pretty" representation of this day.
|
18
19
|
# @return [String] (e.g. "August 3, 2020")
|
19
20
|
def title
|
20
|
-
start_date.strftime(
|
21
|
+
start_date.strftime("%B %-d, %Y")
|
21
22
|
end
|
22
23
|
|
23
24
|
alias_method :to_s, :name
|
@@ -1,8 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module TimeBoss
|
3
4
|
class Calendar
|
4
5
|
class Parser
|
5
|
-
RANGE_DELIMITER =
|
6
|
+
RANGE_DELIMITER = ".."
|
6
7
|
InvalidPeriodIdentifierError = Class.new(StandardError)
|
7
8
|
attr_reader :calendar
|
8
9
|
|
@@ -11,7 +12,7 @@ module TimeBoss
|
|
11
12
|
end
|
12
13
|
|
13
14
|
def parse(identifier = nil)
|
14
|
-
return nil unless (identifier ||
|
15
|
+
return nil unless (identifier || "").strip.length > 0
|
15
16
|
return parse_identifier(identifier) unless identifier&.include?(RANGE_DELIMITER)
|
16
17
|
bases = identifier.split(RANGE_DELIMITER).map { |i| parse_identifier(i.strip) } unless identifier.nil?
|
17
18
|
bases ||= [parse_identifier(nil)]
|
@@ -24,13 +25,13 @@ module TimeBoss
|
|
24
25
|
|
25
26
|
def parse_identifier(identifier)
|
26
27
|
captures = identifier&.match(/^([^-]+)(\s*[+-]\s*[0-9]+)$/)&.captures
|
27
|
-
base, offset = captures || [identifier,
|
28
|
-
period = parse_period(base&.strip)
|
29
|
-
period.offset(offset.gsub(/\s+/,
|
28
|
+
base, offset = captures || [identifier, "0"]
|
29
|
+
(period = parse_period(base&.strip)) || raise(InvalidPeriodIdentifierError)
|
30
|
+
period.offset(offset.gsub(/\s+/, "").to_i)
|
30
31
|
end
|
31
32
|
|
32
33
|
def parse_period(identifier)
|
33
|
-
return calendar.
|
34
|
+
return calendar.public_send(identifier) if calendar.respond_to?(identifier.to_s)
|
34
35
|
parse_term(identifier || Date.today.year.to_s)
|
35
36
|
end
|
36
37
|
|
@@ -38,13 +39,13 @@ module TimeBoss
|
|
38
39
|
return Day.new(calendar, Date.parse(identifier)) if identifier.match?(/^[0-9]{4}-?[01][0-9]-?[0-3][0-9]$/)
|
39
40
|
|
40
41
|
raise InvalidPeriodIdentifierError unless identifier.match?(/^[HQMWD0-9]+$/)
|
41
|
-
period =
|
42
|
+
period = identifier.to_i == 0 ? calendar.this_year : calendar.year(identifier.to_i)
|
42
43
|
%w[half quarter month week day].each do |size|
|
43
44
|
prefix = size[0].upcase
|
44
45
|
next unless identifier.include?(prefix)
|
45
46
|
junk, identifier = identifier.split(prefix)
|
46
47
|
raise InvalidPeriodIdentifierError if junk.match?(/\D/)
|
47
|
-
period = period.
|
48
|
+
(period = period.public_send(size.pluralize)[identifier.to_i - 1]) || raise(InvalidPeriodIdentifierError)
|
48
49
|
end
|
49
50
|
period
|
50
51
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module TimeBoss
|
3
4
|
class Calendar
|
4
5
|
class Period
|
@@ -28,8 +29,8 @@ module TimeBoss
|
|
28
29
|
|
29
30
|
%i[name title to_s].each do |message|
|
30
31
|
define_method(message) do
|
31
|
-
text = self.begin.
|
32
|
-
text = "#{text} #{Parser::RANGE_DELIMITER} #{self.end.
|
32
|
+
text = self.begin.public_send(message)
|
33
|
+
text = "#{text} #{Parser::RANGE_DELIMITER} #{self.end.public_send(message)}" unless self.end == self.begin
|
33
34
|
text
|
34
35
|
end
|
35
36
|
end
|
@@ -112,12 +113,14 @@ module TimeBoss
|
|
112
113
|
|
113
114
|
%w[day week month quarter half year].each do |size|
|
114
115
|
define_method(size.pluralize) do
|
115
|
-
entry = calendar.
|
116
|
-
build_entries
|
116
|
+
entry = calendar.public_send("#{size}_for", self.begin.start_date) || self.begin.public_send(size, 1)
|
117
|
+
entries = build_entries(entry)
|
118
|
+
entries.pop if size == "week" && self.end.next.public_send(size, 1) == entries.last
|
119
|
+
entries
|
117
120
|
end
|
118
121
|
|
119
122
|
define_method(size) do |index = nil|
|
120
|
-
entries =
|
123
|
+
entries = public_send(size.pluralize)
|
121
124
|
return entries[index - 1] unless index.nil?
|
122
125
|
return nil unless entries.length == 1
|
123
126
|
entries.first
|
@@ -127,7 +130,7 @@ module TimeBoss
|
|
127
130
|
# Express this period as a date range.
|
128
131
|
# @return [Range<Date, Date>]
|
129
132
|
def to_range
|
130
|
-
@_to_range ||= start_date
|
133
|
+
@_to_range ||= start_date..end_date
|
131
134
|
end
|
132
135
|
|
133
136
|
def inspect
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require_relative "./translatable"
|
3
4
|
|
4
5
|
module TimeBoss
|
5
6
|
class Calendar
|
@@ -18,10 +19,10 @@ module TimeBoss
|
|
18
19
|
end
|
19
20
|
|
20
21
|
def to_s
|
21
|
-
base, text =
|
22
|
+
base, text = "year", unit.year.name
|
22
23
|
periods.each do |period|
|
23
|
-
sub = unit.
|
24
|
-
index = sub.
|
24
|
+
(sub = unit.public_send(period)) || break
|
25
|
+
index = sub.public_send("in_#{base}")
|
25
26
|
text += "#{period[0].upcase}#{index}"
|
26
27
|
base = period
|
27
28
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TimeBoss
|
4
|
+
class Calendar
|
5
|
+
module Support
|
6
|
+
module HasFiscalWeeks
|
7
|
+
def weeks_in(year:)
|
8
|
+
num_weeks = (((year.end_date - year.start_date) + 1) / 7.0).to_i
|
9
|
+
num_weeks.times.map do |i|
|
10
|
+
start_date = year.start_date + (i * 7).days
|
11
|
+
Week.new(self, start_date, start_date + 6.days)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module TimeBoss
|
4
|
+
class Calendar
|
5
|
+
module Support
|
6
|
+
module HasIsoWeeks
|
7
|
+
def weeks_in(year:)
|
8
|
+
weeks = []
|
9
|
+
start_date = Date.commercial(year.year_index)
|
10
|
+
end_date = Date.commercial(year.next.year_index)
|
11
|
+
while start_date < end_date
|
12
|
+
weeks << Week.new(self, start_date, start_date + 6.days)
|
13
|
+
start_date += 7.days
|
14
|
+
end
|
15
|
+
weeks
|
16
|
+
end
|
17
|
+
|
18
|
+
class Week < Calendar::Week
|
19
|
+
def index
|
20
|
+
start_date.cweek
|
21
|
+
end
|
22
|
+
|
23
|
+
def year
|
24
|
+
calendar.year(start_date.cwyear)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require_relative "./unit"
|
3
4
|
|
4
5
|
module TimeBoss
|
5
6
|
class Calendar
|
@@ -22,10 +23,9 @@ module TimeBoss
|
|
22
23
|
# Get a list of weeks contained within this period.
|
23
24
|
# @return [Array<Week>]
|
24
25
|
def weeks
|
26
|
+
raise UnsupportedUnitError unless calendar.supports_weeks?
|
25
27
|
base = calendar.year(year_index)
|
26
|
-
|
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) }
|
28
|
+
calendar.weeks_in(year: base).select { |w| (w.dates & dates).count >= 4 }
|
29
29
|
end
|
30
30
|
|
31
31
|
private
|
@@ -36,17 +36,17 @@ module TimeBoss
|
|
36
36
|
|
37
37
|
def up
|
38
38
|
if index == max_index
|
39
|
-
calendar.
|
39
|
+
calendar.public_send(self.class.type, year_index + 1, 1)
|
40
40
|
else
|
41
|
-
calendar.
|
41
|
+
calendar.public_send(self.class.type, year_index, index + 1)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
45
|
def down
|
46
46
|
if index == 1
|
47
|
-
calendar.
|
47
|
+
calendar.public_send(self.class.type, year_index - 1, max_index)
|
48
48
|
else
|
49
|
-
calendar.
|
49
|
+
calendar.public_send(self.class.type, year_index, index - 1)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module TimeBoss
|
3
4
|
class Calendar
|
4
5
|
module Support
|
@@ -61,7 +62,7 @@ module TimeBoss
|
|
61
62
|
entry = self
|
62
63
|
while quantity > 0
|
63
64
|
entries << entry
|
64
|
-
entry = entry.
|
65
|
+
entry = entry.public_send(navigator)
|
65
66
|
quantity -= 1
|
66
67
|
end
|
67
68
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module TimeBoss
|
3
4
|
class Calendar
|
4
5
|
module Support
|
@@ -7,21 +8,21 @@ module TimeBoss
|
|
7
8
|
periods = period.pluralize
|
8
9
|
|
9
10
|
define_method("in_#{period}") do
|
10
|
-
base =
|
11
|
+
base = public_send(periods)
|
11
12
|
return unless base.length == 1
|
12
|
-
base.first.
|
13
|
+
base.first.public_send(self.class.type.to_s.pluralize).find_index { |p| p == self } + 1
|
13
14
|
end
|
14
15
|
|
15
16
|
define_method("#{periods}_ago") do |offset|
|
16
|
-
base_offset =
|
17
|
-
(calendar.
|
17
|
+
(base_offset = public_send("in_#{period}")) || return
|
18
|
+
(calendar.public_send("this_#{period}") - offset).public_send(self.class.type.to_s.pluralize)[base_offset - 1]
|
18
19
|
end
|
19
20
|
|
20
|
-
define_method("#{periods}_ahead") { |o|
|
21
|
+
define_method("#{periods}_ahead") { |o| public_send("#{periods}_ago", o * -1) }
|
21
22
|
|
22
|
-
define_method("last_#{period}") {
|
23
|
-
define_method("this_#{period}") {
|
24
|
-
define_method("next_#{period}") {
|
23
|
+
define_method("last_#{period}") { public_send("#{periods}_ago", 1) }
|
24
|
+
define_method("this_#{period}") { public_send("#{periods}_ago", 0) }
|
25
|
+
define_method("next_#{period}") { public_send("#{periods}_ahead", 1) }
|
25
26
|
end
|
26
27
|
|
27
28
|
alias_method :yesterday, :last_day
|
@@ -133,7 +134,7 @@ module TimeBoss
|
|
133
134
|
# Get the index-relative month 1 month forward.
|
134
135
|
# Returns nil if no single month can be identified.
|
135
136
|
# @return [Calendar::Month, nil]
|
136
|
-
|
137
|
+
|
137
138
|
### Quarters
|
138
139
|
|
139
140
|
# @!method in_quarter
|
@@ -167,7 +168,7 @@ module TimeBoss
|
|
167
168
|
# Get the index-relative quarter 1 quarter forward.
|
168
169
|
# Returns nil if no single quarter can be identified.
|
169
170
|
# @return [Calendar::Quarter, nil]
|
170
|
-
|
171
|
+
|
171
172
|
### Halves
|
172
173
|
|
173
174
|
# @!method in_half
|
@@ -201,7 +202,7 @@ module TimeBoss
|
|
201
202
|
# Get the index-relative half 1 half forward.
|
202
203
|
# Returns nil if no single half can be identified.
|
203
204
|
# @return [Calendar::Half, nil]
|
204
|
-
|
205
|
+
|
205
206
|
### Years
|
206
207
|
|
207
208
|
# @!method in_year
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module TimeBoss
|
3
4
|
class Calendar
|
4
5
|
module Support
|
@@ -8,10 +9,10 @@ module TimeBoss
|
|
8
9
|
PERIODS.each do |period|
|
9
10
|
periods = period.pluralize
|
10
11
|
|
11
|
-
define_method(periods) { calendar.
|
12
|
+
define_method(periods) { calendar.public_send("#{periods}_for", self) }
|
12
13
|
|
13
14
|
define_method(period) do |index = nil|
|
14
|
-
entries =
|
15
|
+
entries = public_send(periods)
|
15
16
|
return entries[index - 1] unless index.nil?
|
16
17
|
return nil unless entries.length == 1
|
17
18
|
entries.first
|