Module: Flycal::SlotTemplates
- Defined in:
- lib/flycal/slot_templates.rb
Overview
Named and custom slot windows. YAML/JSON shape matches ~/.flycal/config.yml:
days: [1, 2, 3, 4, 5]
hours:
- 9:30-13:00
- 14:00-18:30
Constant Summary collapse
- BUILTIN =
{ "work" => { "days" => [ 1, 2, 3, 4, 5 ], "hours" => [ "9:30-13:00", "14:00-18:30" ] }, "dinner" => { "days" => [ 1, 2, 3, 4, 5, 6 ], "hours" => [ "19-23" ] } }.freeze
Class Method Summary collapse
- .custom_present?(custom) ⇒ Boolean
- .indifferent(value) ⇒ Object
- .names(catalog = nil) ⇒ Object
- .normalize_catalog(catalog) ⇒ Object
- .parse(definition) ⇒ Object
- .parse_clock(value) ⇒ Object
- .parse_days(values) ⇒ Object
- .parse_hour_range(item) ⇒ Object
- .parse_hours(values) ⇒ Object
-
.resolve(name: nil, custom: nil, catalog: nil) ⇒ Object
Resolve a named template, or a custom YAML-shaped hash.
Class Method Details
.custom_present?(custom) ⇒ Boolean
108 109 110 111 112 113 114 |
# File 'lib/flycal/slot_templates.rb', line 108 def custom_present?(custom) return false if custom.nil? return false if custom.respond_to?(:blank?) && custom.blank? return false if custom.respond_to?(:empty?) && custom.empty? true end |
.indifferent(value) ⇒ Object
122 123 124 125 126 127 |
# File 'lib/flycal/slot_templates.rb', line 122 def indifferent(value) return {} if value.nil? return value.with_indifferent_access if value.respond_to?(:with_indifferent_access) value end |
.names(catalog = nil) ⇒ Object
24 25 26 |
# File 'lib/flycal/slot_templates.rb', line 24 def names(catalog = nil) normalize_catalog(catalog || DefaultSlots.templates).keys end |
.normalize_catalog(catalog) ⇒ Object
116 117 118 119 120 |
# File 'lib/flycal/slot_templates.rb', line 116 def normalize_catalog(catalog) indifferent(catalog).each_with_object({}) do |(key, value), out| out[key.to_s] = value end end |
.parse(definition) ⇒ Object
48 49 50 51 52 53 |
# File 'lib/flycal/slot_templates.rb', line 48 def parse(definition) data = indifferent(definition) days = parse_days(data[:days]) hours = parse_hours(data[:hours]) { days: days, hours: hours } end |
.parse_clock(value) ⇒ Object
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/flycal/slot_templates.rb', line 89 def parse_clock(value) str = value.to_s.strip if str.match?(/\A\d{1,2}\z/) hour = str.to_i raise Error, "Invalid hour #{value.inspect}. Must be 0-23." unless hour.between?(0, 23) return [ hour, 0 ] end hour_s, minute_s = str.split(":", 2) hour = hour_s.to_i minute = minute_s.to_i unless hour.between?(0, 23) && minute.between?(0, 59) raise Error, "Invalid time #{value.inspect}. Use HH:MM (e.g. 9:00, 18:30)." end [ hour, minute ] end |
.parse_days(values) ⇒ Object
55 56 57 58 59 60 61 62 63 |
# File 'lib/flycal/slot_templates.rb', line 55 def parse_days(values) days = Array(values).map(&:to_i) raise Error, "slots template days cannot be empty." if days.empty? invalid = days.reject { |d| d.between?(1, 7) } raise Error, "Invalid template days #{invalid.inspect}. Use 1 (Mon) .. 7 (Sun)." unless invalid.empty? days.uniq end |
.parse_hour_range(item) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/flycal/slot_templates.rb', line 74 def parse_hour_range(item) start_str, end_str = item.to_s.strip.split("-", 2) if start_str.nil? || end_str.nil? || start_str.empty? || end_str.empty? raise Error, "Invalid hours item #{item.inspect}. Use format like '9-13' or '14:30-18:00'." end sh, sm = parse_clock(start_str) eh, em = parse_clock(end_str) start_minutes = (sh * 60) + sm end_minutes = (eh * 60) + em raise Error, "Invalid hours range #{item.inspect}: end must be after start." if end_minutes <= start_minutes [ sh, sm, eh, em ] end |
.parse_hours(values) ⇒ Object
65 66 67 68 69 70 71 72 |
# File 'lib/flycal/slot_templates.rb', line 65 def parse_hours(values) return values if values.is_a?(Array) && values.first.is_a?(Array) ranges = Array(values).map { |item| parse_hour_range(item) } raise Error, "template hours cannot be empty." if ranges.empty? ranges.sort_by { |sh, sm, _eh, _em| (sh * 60) + sm } end |
.resolve(name: nil, custom: nil, catalog: nil) ⇒ Object
Resolve a named template, or a custom YAML-shaped hash.
custom wins over name when present.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/flycal/slot_templates.rb', line 30 def resolve(name: nil, custom: nil, catalog: nil) if custom_present?(custom) parsed = parse(custom) return parsed.merge(name: "custom") end source = normalize_catalog(catalog || DefaultSlots.templates) raise Error, "slots.templates is missing." if source.empty? key = name.to_s.strip key = source.keys.first.to_s if key.empty? definition = source[key] unless definition raise Error, "Unknown slots template #{key.inspect}. Available: #{source.keys.join(", ")}" end parse(definition).merge(name: key) end |