Module: RepoTender::Config::Duration
- Defined in:
- lib/repo_tender/config/duration.rb
Overview
CF1: parse a human-duration string into integer seconds.
The contract and model keep ‘refresh_interval` as an integer (types::Integer.constrained(gt: 0)); this module is the load- layer normalization that lets a hand-edited config.yaml contain “6h” / “90m” / “45s” / “30d” and have it round-trip through Config::Store.load as 21600 / 5400 / 45 / 2592000 — so a user who writes `refresh_interval: 6h` in their config gets the same effect as `refresh_interval: 21600` without ever touching the contract.
The write-back path emits integer seconds (the human form is not preserved on rewrite — consistent with Slice 1’s documented YAML comment-loss limitation, see test_write_emits_only_managed_fields).
Usage:
Duration.parse("6h") # => Success(21600)
Duration.parse(21600) # => Success(21600)
Duration.parse("-3h") # => Failure("invalid duration: \"-3h\"")
Duration.parse("6x") # => Failure("invalid duration: \"6x\"")
Constant Summary collapse
- UNIT_SECONDS =
Unit suffixes recognized (PRD §3.1 documents “6h” / “90m” / integer seconds; we also accept “s” and “d” for completeness — they’re natural extensions and cost zero code).
{ nil => 1, # bare integer string ("21600") or Integer input "s" => 1, "m" => 60, "h" => 3600, "d" => 86_400 }.freeze
- PATTERN =
Strictly positive integer (no sign, no decimal, no leading zeros that change the value’s magnitude). Bare integer strings (“21600”) are accepted by making the unit suffix optional in the pattern.
/\A(\d+)([smhd])?\z/
Class Method Summary collapse
Class Method Details
.failure_for(value) ⇒ Object
74 75 76 |
# File 'lib/repo_tender/config/duration.rb', line 74 def self.failure_for(value) Failure("invalid duration: #{value.inspect} (expected positive integer or \"<n>[s|m|h|d]\" e.g. \"6h\", \"90m\", \"21600\")") end |
.parse(value) ⇒ Object
47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/repo_tender/config/duration.rb', line 47 def self.parse(value) case value when Integer return failure_for(value) if value <= 0 Success(value) when String parse_string(value) else failure_for(value) end end |
.parse_string(str) ⇒ Object
59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/repo_tender/config/duration.rb', line 59 def self.parse_string(str) s = str.strip return failure_for(str) if s.empty? m = PATTERN.match(s) return failure_for(str) unless m n = m[1].to_i unit = m[2] # The pattern guarantees n is a positive integer ("\d+" matches # 1+ digits, never "0" with no other digits… well, "0" would # match with n=0). Reject zero explicitly to keep the # contract's "gt?: 0" guarantee. return failure_for(str) if n <= 0 Success(n * UNIT_SECONDS.fetch(unit)) end |