sof-cycle 0.1.13 → 0.1.14
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/.tool-versions +1 -1
- data/CHANGELOG.md +2 -6
- data/lib/sof/cycle/version.rb +1 -1
- data/lib/sof/cycle.rb +2 -1
- data/lib/sof/cycles/lookback_end_of.rb +43 -0
- data/lib/sof/parser.rb +2 -1
- data/lib/sof/time_span.rb +2 -0
- metadata +3 -3
- data/.claude/settings.local.json +0 -17
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4bf300b22d76c7736f524022360c052b1546fa573ca39e851d4ce2a2ec2de4b7
|
|
4
|
+
data.tar.gz: 30f5a7972655d52acd3a547f59482c32d6c8fbdf22711f9f23eca27e695053cf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 63208d5574eaf86293c0a39214155f7a645b74d51b2dd23bfd03ae83b9dcbd032d145ffd909a8b3a675caef7485f6abe14d5b4bbfcbaafac3c383e29193fa8a7
|
|
7
|
+
data.tar.gz: e4caecf602ea58c7b0cec5a27b1efe36e23b65d0cf191b9c71eb7415e75a01c05079d4783c75d69e02d1ed31da76ef2765a15bc93ee84d43b39c8f03d615a17d
|
data/.tool-versions
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
ruby
|
|
1
|
+
ruby 4.0.2
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.1.14] - 2026-04-27
|
|
9
|
+
|
|
8
10
|
## [0.1.13] - 2026-03-20
|
|
9
11
|
|
|
10
12
|
### Added
|
|
@@ -18,9 +20,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
18
20
|
### Fixed
|
|
19
21
|
|
|
20
22
|
- EndOf cycle `final_date` was off by one period — `V1E12M` now correctly expires at the end of the 12th month, not the 11th
|
|
21
|
-
|
|
22
|
-
## [0.1.12] - 2025-09-05
|
|
23
|
-
|
|
24
|
-
### Added
|
|
25
|
-
|
|
26
|
-
- Missing code coverage and updated EndOf to properly handle dormant cycles.
|
data/lib/sof/cycle/version.rb
CHANGED
data/lib/sof/cycle.rb
CHANGED
|
@@ -6,6 +6,7 @@ require_relative "parser"
|
|
|
6
6
|
module SOF
|
|
7
7
|
class Cycle
|
|
8
8
|
extend ::Forwardable
|
|
9
|
+
|
|
9
10
|
class InvalidInput < StandardError; end
|
|
10
11
|
|
|
11
12
|
class InvalidPeriod < InvalidInput; end
|
|
@@ -223,7 +224,7 @@ module SOF
|
|
|
223
224
|
delegate [:kind, :recurring?, :volume_only?, :valid_periods] => "self.class"
|
|
224
225
|
delegate [:period_count, :duration] => :time_span
|
|
225
226
|
delegate [:calendar?, :dormant?, :end_of?, :interval?, :lookback?,
|
|
226
|
-
:volume_only?, :within?] => :kind_inquiry
|
|
227
|
+
:lookback_end_of?, :volume_only?, :within?] => :kind_inquiry
|
|
227
228
|
|
|
228
229
|
def kind_inquiry = ActiveSupport::StringInquirer.new(kind.to_s)
|
|
229
230
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SOF
|
|
4
|
+
module Cycles
|
|
5
|
+
class LookbackEndOf < Cycle
|
|
6
|
+
@volume_only = false
|
|
7
|
+
@notation_id = "LE"
|
|
8
|
+
@kind = :lookback_end_of
|
|
9
|
+
@valid_periods = %w[D W M Q Y]
|
|
10
|
+
|
|
11
|
+
def self.recurring? = true
|
|
12
|
+
|
|
13
|
+
def self.description
|
|
14
|
+
"Lookback End of Period - occurrences within a prior time period, expiring at the end of the calendar period"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.examples
|
|
18
|
+
["V1LE24M - once in the prior 24 months (expires end of month)", "V2LE3W - twice in the prior 3 weeks (expires end of week)"]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def to_s = "#{volume}x in the prior #{period_count} #{humanized_period} (end of period)"
|
|
22
|
+
|
|
23
|
+
def expiration_of(completion_dates, anchor: Date.current)
|
|
24
|
+
oldest = completion_dates.max_by(volume) { it }.min
|
|
25
|
+
return unless satisfied_by?(completion_dates, anchor:)
|
|
26
|
+
|
|
27
|
+
final_date(oldest)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def final_date(anchor)
|
|
31
|
+
return if anchor.nil?
|
|
32
|
+
|
|
33
|
+
time_span.end_date_of_period(time_span.end_date(anchor.to_date))
|
|
34
|
+
end
|
|
35
|
+
alias_method :window_end, :final_date
|
|
36
|
+
|
|
37
|
+
def start_date(anchor)
|
|
38
|
+
time_span.begin_date_of_period(time_span.begin_date(anchor.to_date))
|
|
39
|
+
end
|
|
40
|
+
alias_method :window_start, :start_date
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/lib/sof/parser.rb
CHANGED
|
@@ -12,9 +12,10 @@ module SOF
|
|
|
12
12
|
# This is an internal implementation of Cycle behavior.
|
|
13
13
|
class Parser
|
|
14
14
|
extend Forwardable
|
|
15
|
+
|
|
15
16
|
PARTS_REGEX = /
|
|
16
17
|
^(?<vol>V(?<volume>\d*))? # optional volume
|
|
17
|
-
(?<set>(?<kind>L|C|W|E|I) # kind
|
|
18
|
+
(?<set>(?<kind>LE|L|C|W|E|I) # kind
|
|
18
19
|
(?<period_count>\d+) # period count
|
|
19
20
|
(?<period_key>D|W|M|Q|Y)?)? # period_key
|
|
20
21
|
(?<from>F(?<from_date>\d{4}-\d{2}-\d{2}))?$ # optional from
|
data/lib/sof/time_span.rb
CHANGED
|
@@ -5,6 +5,7 @@ module SOF
|
|
|
5
5
|
# This is an internal implementation of Cycle behavior.
|
|
6
6
|
class TimeSpan
|
|
7
7
|
extend Forwardable
|
|
8
|
+
|
|
8
9
|
# TimeSpan objects map Cycle notations to behaviors for their periods
|
|
9
10
|
#
|
|
10
11
|
# For example:
|
|
@@ -58,6 +59,7 @@ module SOF
|
|
|
58
59
|
# quarter, etc.
|
|
59
60
|
class DatePeriod
|
|
60
61
|
extend Forwardable
|
|
62
|
+
|
|
61
63
|
class << self
|
|
62
64
|
def for(count, period_notation)
|
|
63
65
|
@cached_periods ||= {}
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sof-cycle
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.14
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jim Gay
|
|
@@ -43,7 +43,6 @@ executables: []
|
|
|
43
43
|
extensions: []
|
|
44
44
|
extra_rdoc_files: []
|
|
45
45
|
files:
|
|
46
|
-
- ".claude/settings.local.json"
|
|
47
46
|
- ".rspec"
|
|
48
47
|
- ".simplecov"
|
|
49
48
|
- ".tool-versions"
|
|
@@ -69,6 +68,7 @@ files:
|
|
|
69
68
|
- lib/sof/cycles/end_of.rb
|
|
70
69
|
- lib/sof/cycles/interval.rb
|
|
71
70
|
- lib/sof/cycles/lookback.rb
|
|
71
|
+
- lib/sof/cycles/lookback_end_of.rb
|
|
72
72
|
- lib/sof/cycles/volume_only.rb
|
|
73
73
|
- lib/sof/cycles/within.rb
|
|
74
74
|
- lib/sof/parser.rb
|
|
@@ -92,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
92
92
|
- !ruby/object:Gem::Version
|
|
93
93
|
version: '0'
|
|
94
94
|
requirements: []
|
|
95
|
-
rubygems_version:
|
|
95
|
+
rubygems_version: 4.0.6
|
|
96
96
|
specification_version: 4
|
|
97
97
|
summary: Parse and interact with SOF cycle notation.
|
|
98
98
|
test_files: []
|
data/.claude/settings.local.json
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Bash(find:*)",
|
|
5
|
-
"Bash(ls:*)",
|
|
6
|
-
"Bash(mkdir:*)",
|
|
7
|
-
"Bash(touch:*)",
|
|
8
|
-
"Bash(rm:*)",
|
|
9
|
-
"Bash(bundle exec rspec:*)",
|
|
10
|
-
"Bash(bundle exec rake:*)",
|
|
11
|
-
"Bash(bundle exec standardrb:*)",
|
|
12
|
-
"Bash(git checkout:*)",
|
|
13
|
-
"Bash(bundle exec ruby:*)"
|
|
14
|
-
],
|
|
15
|
-
"deny": []
|
|
16
|
-
}
|
|
17
|
-
}
|