timeboss 0.2.2 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9d4c953bb1ef449bdc7d37f0ac3061da752b28a9f4df8c1901f9507c447ac89b
4
- data.tar.gz: 752abd38f0afee607b6529894eec4189dfbbc462f5a27ddb4a6238720db35b4e
3
+ metadata.gz: cfac166bdd92d5f95689183603c5af386100642526cea8cbc405765655a1eb26
4
+ data.tar.gz: 00dfb8323ed9317cb214f532a7431bb9dc40d0ca3027ecda5f922bf72949ff0d
5
5
  SHA512:
6
- metadata.gz: b1d04714bcb3514b386fda20f1aaad42f1db96382719848ef9ee5cf889b5c855a26bbb6c6039f50e08ce2484194924ceb8a2ee32f0242b1e3bbc928a9156a0b8
7
- data.tar.gz: 1662c699fc80d9b37744a2f7f4fffa5d72e64d912bab4e19b1d113ba466a16201c003e32b26d1d8697da8c2feb21d4e16be344bc2bacdb2358f2a46ed6646c49
6
+ metadata.gz: bf61f841ed2aa51150656da6d849b01a44511e478a8a0012e0074ec9a85fee8569a0bd162c22f3105b33d565c863df556bbee8bb65ea8d9b938272ff4b702b76
7
+ data.tar.gz: 1dff56f1577ab2e91eb4b5fcfee2928979c261ae02812eec1d2ab0c8788bd7078fbba7f95aec56c830f219d3c07f92513402cd3bb9035233283ffabdcb17fb0e
data/.replit ADDED
@@ -0,0 +1,2 @@
1
+ language = "ruby"
2
+ run = "bundle exec rake timeboss:calendars:broadcast:repl"
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # TimeBoss [![Build Status](https://travis-ci.com/kevinstuffandthings/timeboss.svg?branch=master)](https://travis-ci.com/kevinstuffandthings/timeboss) [![Gem Version](https://badge.fury.io/rb/timeboss.svg)](https://badge.fury.io/rb/timeboss)
1
+ # TimeBoss [![Build Status](https://travis-ci.com/kevinstuffandthings/timeboss.svg?branch=master)](https://travis-ci.com/kevinstuffandthings/timeboss) [![Gem Version](https://badge.fury.io/rb/timeboss.svg)](https://badge.fury.io/rb/timeboss) [![Run on Repl.it](https://repl.it/badge/github/kevinstuffandthings/timeboss)](https://repl.it/github/kevinstuffandthings/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
 
@@ -135,12 +135,12 @@ period = calendar.parse('2020W3..2020Q1')
135
135
 
136
136
  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.
137
137
 
138
- ### Shell
139
- To open an IRB shell for the broadcast calendar, use the `tbsh` executable, or the `timeboss:calendars:broadcast:shell` rake task.
138
+ ### REPL
139
+ To open a REPL for the broadcast calendar, use the `tbsh` executable, or the `timeboss:calendars:broadcast:repl` rake task.
140
140
 
141
141
  For the Gregorian calendar (or any other implemented calendars), supply the name on the command line.
142
142
  - `tbsh gregorian`
143
- - `rake timeboss:calendars:gregorian:shell`
143
+ - `rake timeboss:calendars:gregorian:repl`
144
144
 
145
145
  You will find yourself in the context of an instantiated `TimeBoss::Calendar` object:
146
146
 
@@ -154,7 +154,7 @@ $ tbsh
154
154
  => ["2020M7", "2020M8", "2020M9", "2020M10", "2020M11", "2020M12", "2021M1", "2021M2", "2021M3", "2021M4", "2021M5", "2021M6", "2021M7", "2021M8", "2021M9"]
155
155
  ```
156
156
 
157
- _Having trouble with the shell? If you are using the examples from the [Usage](#Usage) section, keep in mind that the shell is already in the context of the calendar -- so you don't need to specify the receiver!_
157
+ _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!_
158
158
 
159
159
  ## Creating new calendars
160
160
  To create a custom calendar, simply extend the `TimeBoss::Calendar` class, and implement a new `TimeBoss::Calendar::Support::MonthBasis` for it.
@@ -221,6 +221,10 @@ With the new calendar implemented, it can be accessed in one of 2 ways:
221
221
 
222
222
  ```ruby
223
223
  require 'timeboss/calendars'
224
+ TimeBoss::Calendars.register(:august_fiscal, MyCalendars::AugustFiscal)
225
+
226
+ # You'll get a cached instance of your calendar here.
227
+ # Handy when switching back and forth between different calendar implementations.
224
228
  calendar = TimeBoss::Calendars[:august_fiscal]
225
229
  calendar.this_year
226
230
  ```
@@ -9,11 +9,13 @@ namespace :timeboss do
9
9
  puts entry.calendar.parse(args[:expression])
10
10
  end
11
11
 
12
- desc "Open a shell with the #{entry.name} calendar"
13
- task shell: ['timeboss:init'] do
12
+ desc "Open a REPL with the #{entry.name} calendar"
13
+ task repl: ['timeboss:init'] do
14
14
  require 'timeboss/support/shellable'
15
15
  TimeBoss::Support::Shellable.open(entry.calendar)
16
16
  end
17
+
18
+ task shell: ["timeboss:calendars:#{entry.name}:repl"]
17
19
  end
18
20
  end
19
21
  end
@@ -25,6 +25,7 @@ module TimeBoss
25
25
  def name
26
26
  self.class.to_s.demodulize.underscore
27
27
  end
28
+ alias_method :to_s, :name
28
29
 
29
30
  # Get a friendly title for this calendar.
30
31
  # @return [String]
@@ -40,6 +41,12 @@ module TimeBoss
40
41
  true
41
42
  end
42
43
 
44
+ def self.register!
45
+ return unless TimeBoss::Calendars.method_defined?(:register)
46
+ TimeBoss::Calendars.register(self.name.to_s.demodulize.underscore, self)
47
+ end
48
+ private_class_method :register!
49
+
43
50
  protected
44
51
 
45
52
  attr_reader :basis
@@ -11,7 +11,8 @@ module TimeBoss
11
11
  end
12
12
 
13
13
  def parse(identifier = nil)
14
- return parse_identifier(identifier.presence) unless identifier&.include?(RANGE_DELIMITER)
14
+ return nil unless (identifier || '').strip.length > 0
15
+ return parse_identifier(identifier) unless identifier&.include?(RANGE_DELIMITER)
15
16
  bases = identifier.split(RANGE_DELIMITER).map { |i| parse_identifier(i.strip) } unless identifier.nil?
16
17
  bases ||= [parse_identifier(nil)]
17
18
  Period.new(calendar, *bases)
@@ -34,25 +34,96 @@ module TimeBoss
34
34
  end
35
35
  end
36
36
 
37
+ #
38
+ # i hate this
39
+ #
40
+
41
+ ### Days
42
+
43
+ # @!method days
44
+ # Get a list of days that fall within this period.
45
+ # @return [Array<Calendar::Day>]
46
+
47
+ # @!method day(index = nil)
48
+ # Get the day this period represents.
49
+ # Returns nil if no single day can be identified.
50
+ # @return [Array<Calendar::Day>, nil]
51
+
52
+ ### Weeks
53
+
54
+ # @!method weeks
55
+ # Get a list of weeks that fall within this period.
56
+ # @return [Array<Calendar::Week>]
57
+
58
+ # @!method week(index = nil)
59
+ # Get the week this period represents.
60
+ # Returns nil if no single week can be identified.
61
+ # @return [Array<Calendar::Week>, nil]
62
+
63
+ ### Months
64
+
65
+ # @!method months
66
+ # Get a list of months that fall within this period.
67
+ # @return [Array<Calendar::Month>]
68
+
69
+ # @!method month(index = nil)
70
+ # Get the month this period represents.
71
+ # Returns nil if no single month can be identified.
72
+ # @return [Array<Calendar::Month>, nil]
73
+
74
+ ### Quarters
75
+
76
+ # @!method quarters
77
+ # Get a list of quarters that fall within this period.
78
+ # @return [Array<Calendar::Quarter>]
79
+
80
+ # @!method quarter(index = nil)
81
+ # Get the quarter this period represents.
82
+ # Returns nil if no single quarter can be identified.
83
+ # @return [Array<Calendar::Quarter>, nil]
84
+
85
+ ### Halves
86
+
87
+ # @!method halves
88
+ # Get a list of halves that fall within this period.
89
+ # @return [Array<Calendar::Half>]
90
+
91
+ # @!method half(index = nil)
92
+ # Get the half this period represents.
93
+ # Returns nil if no single half can be identified.
94
+ # @return [Array<Calendar::Half>, nil]
95
+
96
+ ### Years
97
+
98
+ # @!method years
99
+ # Get a list of years that fall within this period.
100
+ # @return [Array<Calendar::Year>]
101
+
102
+ # @!method year(index = nil)
103
+ # Get the year this period represents.
104
+ # Returns nil if no single year can be identified.
105
+ # @return [Array<Calendar::Year>, nil]
106
+
107
+ # Does this period cover the current date?
108
+ # @return [Boolean]
109
+ def current?
110
+ to_range.include?(Date.today)
111
+ end
112
+
37
113
  %w[day week month quarter half year].each do |size|
38
114
  define_method(size.pluralize) do
39
115
  entry = calendar.send("#{size}_for", self.begin.start_date)
40
116
  build_entries entry
41
117
  end
42
118
 
43
- define_method(size) do
119
+ define_method(size) do |index = nil|
44
120
  entries = send(size.pluralize)
121
+ return entries[index - 1] unless index.nil?
45
122
  return nil unless entries.length == 1
46
123
  entries.first
47
124
  end
48
125
  end
49
126
 
50
- # Does this period cover the current date?
51
- # @return [Boolean]
52
- def current?
53
- to_range.include?(Date.today)
54
- end
55
-
56
127
  # Express this period as a date range.
57
128
  # @return [Range<Date, Date>]
58
129
  def to_range
@@ -2,6 +2,8 @@ module TimeBoss
2
2
  class Calendar
3
3
  module Support
4
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.
5
7
  class MonthBasis
6
8
  attr_reader :year, :month
7
9
 
@@ -10,8 +10,9 @@ module TimeBoss
10
10
 
11
11
  define_method(periods) { calendar.send("#{periods}_for", self) }
12
12
 
13
- define_method(period) do
13
+ define_method(period) do |index = nil|
14
14
  entries = send(periods)
15
+ return entries[index - 1] unless index.nil?
15
16
  return nil unless entries.length == 1
16
17
  entries.first
17
18
  end
@@ -27,7 +28,7 @@ module TimeBoss
27
28
  # Get a list of days that fall within this unit.
28
29
  # @return [Array<Calendar::Day>]
29
30
 
30
- # @!method day
31
+ # @!method day(index = nil)
31
32
  # Get the day this unit represents.
32
33
  # Returns nil if no single day can be identified.
33
34
  # @return [Array<Calendar::Day>, nil]
@@ -38,7 +39,7 @@ module TimeBoss
38
39
  # Get a list of weeks that fall within this unit.
39
40
  # @return [Array<Calendar::Week>]
40
41
 
41
- # @!method week
42
+ # @!method week(index = nil)
42
43
  # Get the week this unit represents.
43
44
  # Returns nil if no single week can be identified.
44
45
  # @return [Array<Calendar::Week>, nil]
@@ -49,7 +50,7 @@ module TimeBoss
49
50
  # Get a list of months that fall within this unit.
50
51
  # @return [Array<Calendar::Month>]
51
52
 
52
- # @!method month
53
+ # @!method month(index = nil)
53
54
  # Get the month this unit represents.
54
55
  # Returns nil if no single month can be identified.
55
56
  # @return [Array<Calendar::Month>, nil]
@@ -60,7 +61,7 @@ module TimeBoss
60
61
  # Get a list of quarters that fall within this unit.
61
62
  # @return [Array<Calendar::Quarter>]
62
63
 
63
- # @!method quarter
64
+ # @!method quarter(index = nil)
64
65
  # Get the quarter this unit represents.
65
66
  # Returns nil if no single quarter can be identified.
66
67
  # @return [Array<Calendar::Quarter>, nil]
@@ -71,7 +72,7 @@ module TimeBoss
71
72
  # Get a list of halves that fall within this unit.
72
73
  # @return [Array<Calendar::Half>]
73
74
 
74
- # @!method half
75
+ # @!method half(index = nil)
75
76
  # Get the half this unit represents.
76
77
  # Returns nil if no single half can be identified.
77
78
  # @return [Array<Calendar::Half>, nil]
@@ -82,7 +83,7 @@ module TimeBoss
82
83
  # Get a list of years that fall within this unit.
83
84
  # @return [Array<Calendar::Year>]
84
85
 
85
- # @!method year
86
+ # @!method year(index = nil)
86
87
  # Get the year this unit represents.
87
88
  # Returns nil if no single year can be identified.
88
89
  # @return [Array<Calendar::Year>, nil]
@@ -1,28 +1,33 @@
1
1
  # frozen_string_literal: true
2
- require 'active_support/core_ext/class/subclasses'
3
2
  require_relative 'calendar'
4
3
 
5
- Dir[File.expand_path('../calendars/*.rb', __FILE__)].each { |f| require f }
6
-
7
4
  module TimeBoss
8
5
  module Calendars
9
6
  extend self
10
7
  extend Enumerable
11
8
  delegate :each, :length, to: :all
12
9
 
10
+ # Register a new calendar
11
+ # @return [Entry]
12
+ def register(name, klass)
13
+ Entry.new(name.to_sym, klass).tap do |entry|
14
+ (@entries ||= {})[name.to_sym] = entry
15
+ end
16
+ end
17
+
13
18
  # Retrieve a list of all registered calendars.
14
19
  # @return [Array<Entry>]
15
20
  def all
16
- @_all ||= TimeBoss::Calendar.subclasses.map do |klass|
17
- Entry.new(klass.to_s.demodulize.underscore.to_sym, klass)
18
- end
21
+ return if @entries.nil?
22
+ @entries.values.sort_by { |e| e.name.to_s }
19
23
  end
20
24
 
21
25
  # Retrieve an instance of the specified named calendar.
22
26
  # @param name [String, Symbol] the name of the calendar to retrieve.
23
27
  # @return [Calendar]
24
28
  def [](name)
25
- find { |e| e.name == name&.to_sym }&.calendar
29
+ return if @entries.nil?
30
+ @entries[name&.to_sym]&.calendar
26
31
  end
27
32
 
28
33
  private
@@ -44,3 +49,5 @@ module TimeBoss
44
49
  end
45
50
  end
46
51
  end
52
+
53
+ Dir[File.expand_path('../calendars/*.rb', __FILE__)].each { |f| require f }
@@ -4,6 +4,8 @@ require_relative '../calendar'
4
4
  module TimeBoss
5
5
  module Calendars
6
6
  class Broadcast < Calendar
7
+ register!
8
+
7
9
  def initialize
8
10
  super(basis: Basis)
9
11
  end
@@ -4,6 +4,8 @@ require_relative '../calendar'
4
4
  module TimeBoss
5
5
  module Calendars
6
6
  class Gregorian < Calendar
7
+ register!
8
+
7
9
  def initialize
8
10
  super(basis: Basis)
9
11
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module TimeBoss
3
- VERSION = "0.2.2"
3
+ VERSION = "0.3.1"
4
4
  end
@@ -493,10 +493,9 @@ module TimeBoss
493
493
  expect(date.end_date).to eq Date.parse('2017-04-08')
494
494
  end
495
495
 
496
- it 'gives you this year if you give it nothing' do
497
- year = subject.this_year
498
- expect(subject.parse(nil)).to eq year
499
- expect(subject.parse('')).to eq year
496
+ it 'gives you nothing if you give it nothing' do
497
+ expect(subject.parse(nil)).to be nil
498
+ expect(subject.parse('')).to be nil
500
499
  end
501
500
  end
502
501
 
@@ -475,10 +475,9 @@ module TimeBoss
475
475
  expect(date.end_date).to eq Date.parse('2017-04-08')
476
476
  end
477
477
 
478
- it 'gives you this year if you give it nothing' do
479
- year = subject.this_year
480
- expect(subject.parse(nil)).to eq year
481
- expect(subject.parse('')).to eq year
478
+ it 'gives you nothing if you give it nothing' do
479
+ expect(subject.parse(nil)).to be nil
480
+ expect(subject.parse('')).to be nil
482
481
  end
483
482
  end
484
483
 
@@ -1,11 +1,13 @@
1
1
  module TimeBoss
2
2
  describe Calendars do
3
- class MyTestCalendar < TimeBoss::Calendar
3
+ class MyCal < TimeBoss::Calendar
4
4
  def initialize
5
5
  super(basis: nil)
6
6
  end
7
7
  end
8
8
 
9
+ TimeBoss::Calendars.register(:my_amazing_calendar, MyCal)
10
+
9
11
  describe '#all' do
10
12
  let(:all) { described_class.all }
11
13
 
@@ -17,7 +19,7 @@ module TimeBoss
17
19
 
18
20
  context 'enumerability' do
19
21
  it 'can get a list of names' do
20
- expect(described_class.map(&:name)).to include(:broadcast, :my_test_calendar)
22
+ expect(described_class.map(&:name)).to include(:broadcast, :my_amazing_calendar)
21
23
  end
22
24
  end
23
25
  end
@@ -34,10 +36,10 @@ module TimeBoss
34
36
  end
35
37
 
36
38
  it 'can return a new calendar' do
37
- c1 = described_class[:my_test_calendar]
38
- expect(c1).to be_instance_of MyTestCalendar
39
- expect(c1.name).to eq 'my_test_calendar'
40
- expect(c1.title).to eq 'My Test Calendar'
39
+ c1 = described_class[:my_amazing_calendar]
40
+ expect(c1).to be_instance_of MyCal
41
+ expect(c1.name).to eq 'my_cal'
42
+ expect(c1.title).to eq 'My Cal'
41
43
  end
42
44
 
43
45
  it 'can graceully give you nothing' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timeboss
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin McDonald
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-19 00:00:00.000000000 Z
11
+ date: 2020-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -133,6 +133,7 @@ files:
133
133
  - ".github/ISSUE_TEMPLATE/bug_report.md"
134
134
  - ".github/ISSUE_TEMPLATE/feature_request.md"
135
135
  - ".gitignore"
136
+ - ".replit"
136
137
  - ".rspec"
137
138
  - ".travis.yml"
138
139
  - ".yardopts"