Class: RemLint::Trigger
- Inherits:
-
Object
- Object
- RemLint::Trigger
- Defined in:
- lib/remlint/trigger.rb
Overview
The clauses of one command's trigger, and where its body starts.
Everything before the reminder type -- MSG, MSF, RUN, CAL,
SATISFY, SPECIAL, PS, PSFILE -- is the trigger. Everything after is
the body, and the body is text.
That boundary is the whole point of this class. REM Tue AT 15:00 MSG Meet Bob at the pub contains the word at twice: once as the clause that sets
the time, once as an ordinary English preposition. A rule that grepped the
line for AT would find both. Scanning stops at the body keyword, so only
the first one is a clause.
Hyphenated clause keywords (MAX-OVERDUE, COMPLETE-THROUGH) lex as three
tokens, so a name followed by a hyphen and another name is retried as one
word before being taken as two.
Defined Under Namespace
Classes: Clause
Constant Summary collapse
- TRIGGER_COMMANDS =
The commands that open a trigger. Everything else --
ERRMSG,SET,BANNER,INCLUDE-- takes its own argument, and scanning that argument for a reminder type finds words rather than keywords. Remind's owntests/tstlang.remhaserrmsg Please run [filename()] with the -q and -r optionswhere
runis English. Treating it as the start of a RUN body makes the rest of the sentence look like a shell command. %w[REM OMIT IFTRIG].freeze
- EXPRESSION_BODIES =
A body Remind runs the substitution filter over: everything but SATISFY.
SATISFY's body is an expression, and in an expression
%is the modulo operator (expr.c:1473).SATISFY [($Ty % 4) == 0]in Remind's ownexamples/defs.remis arithmetic, not a malformed substitution, and a rule that scanned it for%sequences would say so on every leap-year test ever written. %w[SATISFY].freeze
Instance Attribute Summary collapse
-
#body ⇒ Object
readonly
Returns the value of attribute body.
-
#clauses ⇒ Object
readonly
Returns the value of attribute clauses.
Class Method Summary collapse
- .of(tokens, triggered: true) ⇒ Object
-
.triggered?(command) ⇒ Boolean
Whether this command carries a trigger at all: the three commands that open one, a bare reminder type (
MSG hello), or a trigger written with theREMleft off.
Instance Method Summary collapse
- #body? ⇒ Boolean
-
#body_offset ⇒ Object
Where the body's text begins in the logical line, or nil.
-
#body_tokens ⇒ Object
The tokens after the reminder type, which are the body's text.
-
#find(name) ⇒ Object
The clause of that name, or nil.
- #include?(*names) ⇒ Boolean
-
#initialize(tokens, triggered: true) ⇒ Trigger
constructor
A new instance of Trigger.
- #text_body? ⇒ Boolean
-
#triggered? ⇒ Boolean
Whether this command carries a trigger at all.
Constructor Details
#initialize(tokens, triggered: true) ⇒ Trigger
Returns a new instance of Trigger.
56 57 58 59 60 61 62 63 64 65 |
# File 'lib/remlint/trigger.rb', line 56 def initialize(tokens, triggered: true) @tokens = tokens @clauses = [] @body = nil @triggered = triggered if triggered scan end end |
Instance Attribute Details
#body ⇒ Object (readonly)
Returns the value of attribute body.
54 55 56 |
# File 'lib/remlint/trigger.rb', line 54 def body @body end |
#clauses ⇒ Object (readonly)
Returns the value of attribute clauses.
54 55 56 |
# File 'lib/remlint/trigger.rb', line 54 def clauses @clauses end |
Class Method Details
.of(tokens, triggered: true) ⇒ Object
74 75 76 |
# File 'lib/remlint/trigger.rb', line 74 def self.of(tokens, triggered: true) new(tokens, triggered: triggered) end |
.triggered?(command) ⇒ Boolean
Whether this command carries a trigger at all: the three commands that
open one, a bare reminder type (MSG hello), or a trigger written with
the REM left off.
81 82 83 84 85 |
# File 'lib/remlint/trigger.rb', line 81 def self.triggered?(command) command.implicit? || command.keyword?(*TRIGGER_COMMANDS) || !!command.keyword&.body? end |
Instance Method Details
#body? ⇒ Boolean
99 100 101 |
# File 'lib/remlint/trigger.rb', line 99 def body? !body.nil? end |
#body_offset ⇒ Object
Where the body's text begins in the logical line, or nil.
127 128 129 |
# File 'lib/remlint/trigger.rb', line 127 def body_offset body&.end_offset end |
#body_tokens ⇒ Object
The tokens after the reminder type, which are the body's text. Empty for a command with no body keyword at all.
118 119 120 121 122 123 124 |
# File 'lib/remlint/trigger.rb', line 118 def body_tokens if body @tokens[(body.token_index + 1)..] || [] else [] end end |
#find(name) ⇒ Object
The clause of that name, or nil. Names are canonical, so find("UNTIL")
matches an abbreviated UNTIL written as UNTI.
89 90 91 |
# File 'lib/remlint/trigger.rb', line 89 def find(name) clauses.find { |clause| clause.name == name.upcase } end |
#include?(*names) ⇒ Boolean
93 94 95 96 97 |
# File 'lib/remlint/trigger.rb', line 93 def include?(*names) wanted = names.map(&:upcase) clauses.any? { |clause| wanted.include?(clause.name) } end |
#text_body? ⇒ Boolean
112 113 114 |
# File 'lib/remlint/trigger.rb', line 112 def text_body? body? && !EXPRESSION_BODIES.include?(body.name) end |
#triggered? ⇒ Boolean
Whether this command carries a trigger at all. Rules that look for
something positional -- a repeat, a delta -- need it, because SET a 3*14
has a * in it and no trigger for that * to be part of.
70 71 72 |
# File 'lib/remlint/trigger.rb', line 70 def triggered? @triggered end |