sof-cycle 0.1.7 → 0.1.8
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/.claude/settings.local.json +17 -0
- data/.simplecov +6 -0
- data/CHANGELOG.md +6 -6
- data/CLAUDE.md +34 -0
- data/checksums/sof-cycle-0.1.7.gem.sha512 +1 -0
- data/lib/sof/cycle/version.rb +1 -1
- data/lib/sof/cycle.rb +82 -8
- data/lib/sof/cycles/calendar.rb +9 -1
- data/lib/sof/cycles/end_of.rb +8 -0
- data/lib/sof/cycles/lookback.rb +9 -1
- data/lib/sof/cycles/volume_only.rb +1 -1
- data/lib/sof/cycles/within.rb +9 -1
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bcb187376738c3b567bf2bc9fc68bba6f1cb7e766302a897ab272db848b1b081
|
4
|
+
data.tar.gz: d841689c22f68f7f273d1791feb7753826c3b5c2235deb467fad88ee163ec18f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f193e2a83e149315956c99df5efebabfd05c9ade453bb4e4763db1a39870c62c63bae5e6c82379bddd1f07a85a1a6f898fb90d53a753f0936f146efdf6e5f786
|
7
|
+
data.tar.gz: 7000bd01fd3c3302756b757b406f36ec75db9125a3acf597e5c6fb54ab811356e076b4d45087098db94ffb4d4f0151b33d8bd4ce3c1ebe4e4844ae20029aec66
|
@@ -0,0 +1,17 @@
|
|
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
|
+
}
|
data/.simplecov
CHANGED
data/CHANGELOG.md
CHANGED
@@ -5,6 +5,12 @@ 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.8] - 2025-09-04
|
9
|
+
|
10
|
+
### Changed
|
11
|
+
|
12
|
+
- Simplified `handles?` logic to do string comparison instead of symbol comparison.
|
13
|
+
|
8
14
|
## [0.1.7] - 2025-06-09
|
9
15
|
|
10
16
|
### Added
|
@@ -16,9 +22,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
16
22
|
|
17
23
|
- `Cycles::Lookback.volume_to_delay_expiration` now computes correctly when the
|
18
24
|
`#considered_dates` is smaller than the `#covered_dates` of the cycle.
|
19
|
-
|
20
|
-
## [0.1.6] - 2024-09-04
|
21
|
-
|
22
|
-
### Added
|
23
|
-
|
24
|
-
- `Cycle.extend_period(count)` to get a new cycle with the modified period count
|
data/CLAUDE.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# CLAUDE.md
|
2
|
+
|
3
|
+
## Agent OS Documentation
|
4
|
+
|
5
|
+
### Product Context
|
6
|
+
- **Mission & Vision:** @.agent-os/product/mission.md
|
7
|
+
- **Technical Architecture:** @.agent-os/product/tech-stack.md
|
8
|
+
- **Development Roadmap:** @.agent-os/product/roadmap.md
|
9
|
+
- **Decision History:** @.agent-os/product/decisions.md
|
10
|
+
|
11
|
+
### Development Standards
|
12
|
+
- **Code Style:** @~/.agent-os/standards/code-style.md
|
13
|
+
- **Best Practices:** @~/.agent-os/standards/best-practices.md
|
14
|
+
|
15
|
+
### Project Management
|
16
|
+
- **Active Specs:** @.agent-os/specs/
|
17
|
+
- **Spec Planning:** Use `@~/.agent-os/instructions/create-spec.md`
|
18
|
+
- **Tasks Execution:** Use `@~/.agent-os/instructions/execute-tasks.md`
|
19
|
+
|
20
|
+
## Workflow Instructions
|
21
|
+
|
22
|
+
When asked to work on this codebase:
|
23
|
+
|
24
|
+
1. **First**, check @.agent-os/product/roadmap.md for current priorities
|
25
|
+
2. **Then**, follow the appropriate instruction file:
|
26
|
+
- For new features: @~/.agent-os/instructions/create-spec.md
|
27
|
+
- For tasks execution: @~/.agent-os/instructions/execute-tasks.md
|
28
|
+
3. **Always**, adhere to the standards in the files listed above
|
29
|
+
|
30
|
+
## Important Notes
|
31
|
+
|
32
|
+
- Product-specific files in `.agent-os/product/` override any global standards
|
33
|
+
- User's specific instructions override (or amend) instructions found in `.agent-os/specs/...`
|
34
|
+
- Always adhere to established patterns, code style, and best practices documented above.
|
@@ -0,0 +1 @@
|
|
1
|
+
10f35795f9559afbf1b87c26b76c5458fbdca373705539bfb55e3702c372b9198dba2cf1986489c5a95b55359dcdcfe39e27b10564e6570a94552ab95f31de7f
|
data/lib/sof/cycle/version.rb
CHANGED
data/lib/sof/cycle.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "forwardable"
|
3
4
|
require_relative "parser"
|
4
5
|
|
5
6
|
module SOF
|
6
7
|
class Cycle
|
7
|
-
extend Forwardable
|
8
|
+
extend ::Forwardable
|
8
9
|
class InvalidInput < StandardError; end
|
9
10
|
|
10
11
|
class InvalidPeriod < InvalidInput; end
|
@@ -99,12 +100,26 @@ module SOF
|
|
99
100
|
end || raise(InvalidKind, "':#{sym}' is not a valid kind of Cycle")
|
100
101
|
end
|
101
102
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
103
|
+
# Return a legend explaining all notation components
|
104
|
+
#
|
105
|
+
# @return [Hash] hash with notation components organized by category
|
106
|
+
def legend
|
107
|
+
{
|
108
|
+
"quantity" => {
|
109
|
+
"V" => {
|
110
|
+
description: "Volume - the number of times something should occur",
|
111
|
+
examples: ["V1L1D - once in the prior 1 day", "V3L3D - three times in the prior 3 days", "V10L10D - ten times in the prior 10 days"]
|
112
|
+
}
|
113
|
+
},
|
114
|
+
"kind" => build_kind_legend,
|
115
|
+
"period" => build_period_legend,
|
116
|
+
"date" => {
|
117
|
+
"F" => {
|
118
|
+
description: "From - specifies the anchor date for Within cycles",
|
119
|
+
examples: ["F2024-01-01 - from January 1, 2024", "F2024-12-31 - from December 31, 2024"]
|
120
|
+
}
|
121
|
+
}
|
122
|
+
}
|
108
123
|
end
|
109
124
|
|
110
125
|
@volume_only = false
|
@@ -127,6 +142,65 @@ module SOF
|
|
127
142
|
#{valid_periods.join(", ")}
|
128
143
|
ERR
|
129
144
|
end
|
145
|
+
|
146
|
+
def handles?(sym)
|
147
|
+
kind.to_s == sym.to_s
|
148
|
+
end
|
149
|
+
|
150
|
+
def cycle_handlers
|
151
|
+
@cycle_handlers ||= Set.new
|
152
|
+
end
|
153
|
+
|
154
|
+
def inherited(klass)
|
155
|
+
cycle_handlers << klass
|
156
|
+
end
|
157
|
+
|
158
|
+
private
|
159
|
+
|
160
|
+
def build_kind_legend
|
161
|
+
legend = {}
|
162
|
+
cycle_handlers.each do |handler|
|
163
|
+
# Skip volume_only since it doesn't have a notation_id
|
164
|
+
next if handler.instance_variable_get(:@volume_only)
|
165
|
+
|
166
|
+
notation_id = handler.instance_variable_get(:@notation_id)
|
167
|
+
next unless notation_id
|
168
|
+
|
169
|
+
legend[notation_id] = {
|
170
|
+
description: handler.description,
|
171
|
+
examples: handler.examples
|
172
|
+
}
|
173
|
+
end
|
174
|
+
legend
|
175
|
+
end
|
176
|
+
|
177
|
+
def build_period_legend
|
178
|
+
legend = {}
|
179
|
+
# Use known period codes since DatePeriod is private
|
180
|
+
period_mappings = {
|
181
|
+
"D" => "day",
|
182
|
+
"W" => "week",
|
183
|
+
"M" => "month",
|
184
|
+
"Q" => "quarter",
|
185
|
+
"Y" => "year"
|
186
|
+
}
|
187
|
+
|
188
|
+
period_mappings.each do |code, period_name|
|
189
|
+
legend[code] = {
|
190
|
+
description: "#{period_name.capitalize} - period notation",
|
191
|
+
examples: period_examples_for(code, period_name)
|
192
|
+
}
|
193
|
+
end
|
194
|
+
legend
|
195
|
+
end
|
196
|
+
|
197
|
+
def period_examples_for(code, period_name)
|
198
|
+
base_example = (code == "D") ? "3#{code} - 3 #{period_name}s" : "2#{code} - 2 #{period_name}s"
|
199
|
+
lookback_example = "L#{(code == "D") ? "7" : "4"}#{code} - in the prior #{(code == "D") ? "7" : "4"} #{period_name}s"
|
200
|
+
calendar_example = "C1#{code} - this calendar #{period_name}"
|
201
|
+
|
202
|
+
[base_example, lookback_example, calendar_example]
|
203
|
+
end
|
130
204
|
end
|
131
205
|
|
132
206
|
def initialize(notation, parser: Parser.new(notation))
|
@@ -176,7 +250,7 @@ module SOF
|
|
176
250
|
end
|
177
251
|
|
178
252
|
def considered_dates(completion_dates, anchor: Date.current)
|
179
|
-
covered_dates(completion_dates, anchor:).max_by(volume) {
|
253
|
+
covered_dates(completion_dates, anchor:).max_by(volume) { it }
|
180
254
|
end
|
181
255
|
|
182
256
|
def covered_dates(dates, anchor: Date.current)
|
data/lib/sof/cycles/calendar.rb
CHANGED
@@ -10,6 +10,14 @@ module SOF
|
|
10
10
|
|
11
11
|
class << self
|
12
12
|
def frame_of_reference = "total"
|
13
|
+
|
14
|
+
def description
|
15
|
+
"Calendar - occurrences within the current calendar period"
|
16
|
+
end
|
17
|
+
|
18
|
+
def examples
|
19
|
+
["V2C1M - twice this calendar month", "V4C1Y - 4 times this calendar year"]
|
20
|
+
end
|
13
21
|
end
|
14
22
|
|
15
23
|
def self.recurring? = true
|
@@ -22,7 +30,7 @@ module SOF
|
|
22
30
|
# @return [Date, nil] the date on which the cycle will expire given the
|
23
31
|
# provided completion dates. Returns nil if the cycle is already unsatisfied.
|
24
32
|
def expiration_of(completion_dates)
|
25
|
-
anchor = completion_dates.max_by(volume) {
|
33
|
+
anchor = completion_dates.max_by(volume) { it }.min
|
26
34
|
return unless satisfied_by?(completion_dates, anchor:)
|
27
35
|
|
28
36
|
window_end(anchor) + duration
|
data/lib/sof/cycles/end_of.rb
CHANGED
@@ -18,6 +18,14 @@ module SOF
|
|
18
18
|
|
19
19
|
def self.recurring? = true
|
20
20
|
|
21
|
+
def self.description
|
22
|
+
"End of - occurrences by the end of a time period"
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.examples
|
26
|
+
["V1E1M - once by the end of next month", "V2E2Q - twice by the end of 2 quarters"]
|
27
|
+
end
|
28
|
+
|
21
29
|
def to_s
|
22
30
|
return dormant_to_s if dormant?
|
23
31
|
|
data/lib/sof/cycles/lookback.rb
CHANGED
@@ -10,6 +10,14 @@ module SOF
|
|
10
10
|
|
11
11
|
def self.recurring? = true
|
12
12
|
|
13
|
+
def self.description
|
14
|
+
"Lookback - occurrences within a prior time period counting backwards from today"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.examples
|
18
|
+
["V3L3D - 3 times in the prior 3 days", "V1L2W - once in the prior 2 weeks"]
|
19
|
+
end
|
20
|
+
|
13
21
|
def to_s = "#{volume}x in the prior #{period_count} #{humanized_period}"
|
14
22
|
|
15
23
|
def volume_to_delay_expiration(completion_dates, anchor:)
|
@@ -25,7 +33,7 @@ module SOF
|
|
25
33
|
# @return [Date, nil] the date on which the cycle will expire given the
|
26
34
|
# provided completion dates. Returns nil if the cycle is already unsatisfied.
|
27
35
|
def expiration_of(completion_dates)
|
28
|
-
anchor = completion_dates.max_by(volume) {
|
36
|
+
anchor = completion_dates.max_by(volume) { it }.min
|
29
37
|
return unless satisfied_by?(completion_dates, anchor:)
|
30
38
|
|
31
39
|
window_end anchor
|
data/lib/sof/cycles/within.rb
CHANGED
@@ -10,6 +10,14 @@ module SOF
|
|
10
10
|
|
11
11
|
def self.recurring? = false
|
12
12
|
|
13
|
+
def self.description
|
14
|
+
"Within - occurrences within a time period from a specific date"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.examples
|
18
|
+
["V2W3DF2024-01-01 - twice within 3 days from Jan 1, 2024"]
|
19
|
+
end
|
20
|
+
|
13
21
|
def to_s = "#{volume}x within #{date_range}"
|
14
22
|
|
15
23
|
def extend_period(count)
|
@@ -23,7 +31,7 @@ module SOF
|
|
23
31
|
def date_range
|
24
32
|
return humanized_span unless active?
|
25
33
|
|
26
|
-
[start_date, final_date].map {
|
34
|
+
[start_date, final_date].map { it.to_fs(:american) }.join(" - ")
|
27
35
|
end
|
28
36
|
|
29
37
|
def final_date(_ = nil) = time_span.end_date(start_date)
|
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.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jim Gay
|
@@ -43,15 +43,18 @@ executables: []
|
|
43
43
|
extensions: []
|
44
44
|
extra_rdoc_files: []
|
45
45
|
files:
|
46
|
+
- ".claude/settings.local.json"
|
46
47
|
- ".rspec"
|
47
48
|
- ".simplecov"
|
48
49
|
- CHANGELOG.md
|
50
|
+
- CLAUDE.md
|
49
51
|
- README.md
|
50
52
|
- Rakefile
|
51
53
|
- checksums/sof-cycle-0.1.0.gem.sha512
|
52
54
|
- checksums/sof-cycle-0.1.1.gem.sha512
|
53
55
|
- checksums/sof-cycle-0.1.2.gem.sha512
|
54
56
|
- checksums/sof-cycle-0.1.6.gem.sha512
|
57
|
+
- checksums/sof-cycle-0.1.7.gem.sha512
|
55
58
|
- lib/sof-cycle.rb
|
56
59
|
- lib/sof/cycle.rb
|
57
60
|
- lib/sof/cycle/version.rb
|