Class: Remind::Reminder
- Inherits:
-
Object
- Object
- Remind::Reminder
- Defined in:
- lib/remind/reminder.rb
Overview
One REM line, parsed by Remind.
This is the binding that exists because converting a reminder file to
anything else is otherwise a re-implementation of Remind. A trigger like
REM Mon 13 SKIP OMIT Sat MSG x means "the Monday of the week the 13th
falls in, unless that is a Saturday, in which case skip it" -- and every
program that has tried to read that with a regular expression has got some
of it wrong. Here the parse is ParseRem, the first date is
ComputeTrigger, the message is DoSubst, and the dates after the first
are ComputeTrigger again from further along. Nothing about the date
specification is interpreted on this side.
The fields are Remind's, with two translations and no others: months are 1..12 rather than 0..11, and a field the reminder did not mention is nil rather than Remind's sentinel for it.
Constant Summary collapse
- WEEKDAY_BITS =
What Remind numbers the weekday bits from: bit 0 is Monday.
%w[MO TU WE TH FR SA SU].freeze
- DISPLAY_TYPES =
A body a calendar can show. RUN reminders execute a shell command, CAL and PS reminders draw on a PostScript calendar; none of them is an event.
%i[msg msf].freeze
- TYPE_NAMES =
{ msg_type: :msg, msf_type: :msf, run_type: :run, cal_type: :cal, sat_type: :satisfy, passthru_type: :passthru, }.freeze
- DEFAULT_LIMIT =
How far a walk will go looking for the next occurrence before deciding there isn't one. Remind answers "cannot compute trigger" on its own for most run-out reminders; this bounds the ones it would keep answering.
100
Instance Attribute Summary collapse
-
#description ⇒ Object
readonly
Returns the value of attribute description.
-
#first ⇒ Object
readonly
Returns the value of attribute first.
-
#line ⇒ Object
readonly
Returns the value of attribute line.
-
#session ⇒ Object
readonly
Returns the value of attribute session.
-
#type ⇒ Object
readonly
Returns the value of attribute type.
Class Method Summary collapse
-
.parse(line, session: Session.new) ⇒ Object
nil when the line is not a reminder Remind can parse into an event: a comment, a SET, a REM with no body, a trigger that never fires.
Instance Method Summary collapse
-
#as_of(date) ⇒ Object
The same reminder as it reads on a given day.
-
#at ⇒ Object
Minutes since midnight, or nil for an all-day reminder.
-
#back ⇒ Object
The
-ninREM 1 -1: how many days back from the date the trigger names. -
#day ⇒ Object
The day of the month, or nil.
- #display? ⇒ Boolean
-
#duration ⇒ Object
DURATION, in minutes, or nil.
- #error ⇒ Object
-
#initialize(line, session: Session.new) ⇒ Reminder
constructor
A new instance of Reminder.
-
#month ⇒ Object
1..12, or nil.
-
#occurrences(limit: DEFAULT_LIMIT) ⇒ Object
Every date this reminder triggers on, starting at the first, asked of Remind one at a time.
- #omits_weekdays? ⇒ Boolean
- #once? ⇒ Boolean
-
#parse ⇒ Object
--- parsing ----------------------------------------------------------.
- #parsed? ⇒ Boolean
-
#presented ⇒ Object
nil rather than an unusable object, for the caller that is walking a file and does not want to ask about every line twice.
-
#repeat ⇒ Object
REM 1 *7repeats every seven days. -
#skip ⇒ Object
Whether the reminder skips or moves over OMITted days, which is a thing no RRULE can say.
-
#summary ⇒ Object
The message as a calendar wants it:
%"…%"marks the part of a reminder that is the entry's title, and CAL_MODE is the mode that honours it. -
#until_date ⇒ Object
The last date the reminder may trigger on -- UNTIL or THROUGH -- as a Date, or nil.
-
#warning_days ⇒ Object
Advance warning, in days: the
+ninREM 15 +3. -
#warning_minutes ⇒ Object
The alarm on an AT clause:
AT 9:30 +15, in minutes. -
#weekdays ⇒ Object
The weekdays named in the trigger, as RFC 5545 spells them, in Remind's bit order:
REM Mon Wed Friis ["MO", "WE", "FR"]. - #year ⇒ Object
Constructor Details
Instance Attribute Details
#description ⇒ Object (readonly)
Returns the value of attribute description.
47 48 49 |
# File 'lib/remind/reminder.rb', line 47 def description @description end |
#first ⇒ Object (readonly)
Returns the value of attribute first.
47 48 49 |
# File 'lib/remind/reminder.rb', line 47 def first @first end |
#line ⇒ Object (readonly)
Returns the value of attribute line.
47 48 49 |
# File 'lib/remind/reminder.rb', line 47 def line @line end |
#session ⇒ Object (readonly)
Returns the value of attribute session.
47 48 49 |
# File 'lib/remind/reminder.rb', line 47 def session @session end |
#type ⇒ Object (readonly)
Returns the value of attribute type.
47 48 49 |
# File 'lib/remind/reminder.rb', line 47 def type @type end |
Class Method Details
.parse(line, session: Session.new) ⇒ Object
nil when the line is not a reminder Remind can parse into an event: a comment, a SET, a REM with no body, a trigger that never fires.
52 53 54 55 56 |
# File 'lib/remind/reminder.rb', line 52 def parse(line, session: Session.new) new(line, session: session).tap(&:parse).presented rescue EvaluationError nil end |
Instance Method Details
#as_of(date) ⇒ Object
The same reminder as it reads on a given day.
A message is not fixed text: %b is "in 27 days' time" or "today"
depending on when it is read, and Remind expands it against whatever
DSEToday says at the moment it renders. remind therefore prints a
different message for each occurrence, and anything showing one
occurrence should show the message that occurrence would have had.
Today is process-wide, so it is pinned and put back.
194 195 196 197 198 199 200 201 |
# File 'lib/remind/reminder.rb', line 194 def as_of(date) was = session.today session.today = date self.class.parse(line, session: session) ensure session.today = was end |
#at ⇒ Object
Minutes since midnight, or nil for an all-day reminder.
137 138 139 140 141 142 143 144 145 |
# File 'lib/remind/reminder.rb', line 137 def at time = timetrig_field(:time) if time == native.no_time nil else time end end |
#back ⇒ Object
The -n in REM 1 -1: how many days back from the date the trigger
names. REM 1 -1 is the last day of the month before.
116 117 118 |
# File 'lib/remind/reminder.rb', line 116 def back positive(trigger_field(:back)) end |
#day ⇒ Object
The day of the month, or nil.
68 69 70 |
# File 'lib/remind/reminder.rb', line 68 def day field(:d, native.no_day) end |
#display? ⇒ Boolean
181 182 183 |
# File 'lib/remind/reminder.rb', line 181 def display? DISPLAY_TYPES.include?(type) end |
#duration ⇒ Object
DURATION, in minutes, or nil. Remind fills this with the same "no time given" sentinel as the AT clause, not with zero.
149 150 151 152 153 154 155 156 157 |
# File 'lib/remind/reminder.rb', line 149 def duration given = timetrig_field(:duration) if given == native.no_time nil else positive(given) end end |
#error ⇒ Object
240 241 242 243 244 |
# File 'lib/remind/reminder.rb', line 240 def error if @code&.positive? session.(@code) end end |
#month ⇒ Object
1..12, or nil. Remind counts months from zero; this does not.
73 74 75 76 77 78 79 |
# File 'lib/remind/reminder.rb', line 73 def month zero_based = field(:m, native.no_month) if zero_based zero_based + 1 end end |
#occurrences(limit: DEFAULT_LIMIT) ⇒ Object
Every date this reminder triggers on, starting at the first, asked of Remind one at a time. Lazy, because a daily reminder has no last one.
168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/remind/reminder.rb', line 168 def occurrences(limit: DEFAULT_LIMIT) Enumerator.new do |dates| cursor = first_dse taken = 0 while cursor >= 0 && taken < limit dates << session.date(cursor) taken += 1 cursor = next_dse(cursor + 1) end end end |
#omits_weekdays? ⇒ Boolean
126 127 128 |
# File 'lib/remind/reminder.rb', line 126 def omits_weekdays? trigger_field(:localomit) != 0 end |
#once? ⇒ Boolean
130 131 132 |
# File 'lib/remind/reminder.rb', line 130 def once? trigger_field(:once) != 0 end |
#parse ⇒ Object
--- parsing ----------------------------------------------------------
205 206 207 208 209 210 211 212 |
# File 'lib/remind/reminder.rb', line 205 def parse @trigger = Fiddle::Pointer.malloc(native.sizeof_trigger, Fiddle::RUBY_FREE) @timetrig = Fiddle::Pointer.malloc(native.sizeof_timetrig, Fiddle::RUBY_FREE) @code, @first_dse, @description = (native.normal_mode, @trigger, @timetrig) @type = TYPE_NAMES[type_name] @first = read_first end |
#parsed? ⇒ Boolean
236 237 238 |
# File 'lib/remind/reminder.rb', line 236 def parsed? @code&.zero? && @first_dse >= 0 end |
#presented ⇒ Object
nil rather than an unusable object, for the caller that is walking a file and does not want to ask about every line twice.
230 231 232 233 234 |
# File 'lib/remind/reminder.rb', line 230 def presented if parsed? self end end |
#repeat ⇒ Object
REM 1 *7 repeats every seven days. nil when the reminder does not.
95 96 97 |
# File 'lib/remind/reminder.rb', line 95 def repeat positive(trigger_field(:rep)) end |
#skip ⇒ Object
Whether the reminder skips or moves over OMITted days, which is a thing no RRULE can say.
122 123 124 |
# File 'lib/remind/reminder.rb', line 122 def skip trigger_field(:skip) end |
#summary ⇒ Object
The message as a calendar wants it: %"…%" marks the part of a reminder
that is the entry's title, and CAL_MODE is the mode that honours it. A
reminder that marks nothing has the whole message for a title.
It costs a second parse, because DoSubst consumes the parser as it renders and there is only one message in a line either way.
220 221 222 223 224 225 226 |
# File 'lib/remind/reminder.rb', line 220 def summary @summary ||= ( native.cal_mode, Fiddle::Pointer.malloc(native.sizeof_trigger, Fiddle::RUBY_FREE), Fiddle::Pointer.malloc(native.sizeof_timetrig, Fiddle::RUBY_FREE), ).last end |
#until_date ⇒ Object
The last date the reminder may trigger on -- UNTIL or THROUGH -- as a Date, or nil.
101 102 103 104 105 106 107 |
# File 'lib/remind/reminder.rb', line 101 def until_date last = field(:until, native.no_until) if last session.date(last) end end |
#warning_days ⇒ Object
Advance warning, in days: the +n in REM 15 +3.
110 111 112 |
# File 'lib/remind/reminder.rb', line 110 def warning_days positive(trigger_field(:delta)) end |
#warning_minutes ⇒ Object
The alarm on an AT clause: AT 9:30 +15, in minutes.
160 161 162 |
# File 'lib/remind/reminder.rb', line 160 def warning_minutes positive(timetrig_field(:delta)) end |
#weekdays ⇒ Object
The weekdays named in the trigger, as RFC 5545 spells them, in Remind's
bit order: REM Mon Wed Fri is ["MO", "WE", "FR"].
87 88 89 90 91 92 |
# File 'lib/remind/reminder.rb', line 87 def weekdays bits = trigger_field(:wd) WEEKDAY_BITS.each_index.select { |index| bits.anybits?(1 << index) } .map { |index| WEEKDAY_BITS[index] } end |
#year ⇒ Object
81 82 83 |
# File 'lib/remind/reminder.rb', line 81 def year field(:y, native.no_year) end |