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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0eb9458907426d68d8fc05c159a9bb782819b2ec821baf2ec24109b45c6794ff
4
- data.tar.gz: e4c0b55074d59aad3f4e562e579759d8d85413b1fd93c93c873b79bdbff1c629
3
+ metadata.gz: 4bf300b22d76c7736f524022360c052b1546fa573ca39e851d4ce2a2ec2de4b7
4
+ data.tar.gz: 30f5a7972655d52acd3a547f59482c32d6c8fbdf22711f9f23eca27e695053cf
5
5
  SHA512:
6
- metadata.gz: c799aed72bf8973a8b6438cab7d2635f2563575fcf3d16eac4b4bf38df409953000d78afc8b691ed4b5e4eb40b39a7969858e79d9ee844697ce113e1f0170ae5
7
- data.tar.gz: c99b76559985729d0ea59ee3ff5be523500965578c450c85a90c24fd2d958ebd6eb4ff4ad550d101e8178423f2f39d02ffe79a47a28f716e34865c4028ce83a5
6
+ metadata.gz: 63208d5574eaf86293c0a39214155f7a645b74d51b2dd23bfd03ae83b9dcbd032d145ffd909a8b3a675caef7485f6abe14d5b4bbfcbaafac3c383e29193fa8a7
7
+ data.tar.gz: e4caecf602ea58c7b0cec5a27b1efe36e23b65d0cf191b9c71eb7415e75a01c05079d4783c75d69e02d1ed31da76ef2765a15bc93ee84d43b39c8f03d615a17d
data/.tool-versions CHANGED
@@ -1 +1 @@
1
- ruby 3.4.3
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.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module SOF
4
4
  class Cycle
5
- VERSION = "0.1.13"
5
+ VERSION = "0.1.14"
6
6
  end
7
7
  end
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.13
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: 3.6.7
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: []
@@ -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
- }