Class: SpectatorSport::SearchQuery::Lexer
- Inherits:
-
Object
- Object
- SpectatorSport::SearchQuery::Lexer
- Defined in:
- app/models/spectator_sport/search_query/lexer.rb
Overview
Turns a query string into a flat array of Tokens. Knows nothing about grammar/precedence - that's the Parser's job.
Terms combine by simple juxtaposition (implicit AND, like Gmail search), or with the explicit AND / OR keywords:
label:a label:b => a AND b
label:a AND label:b => a AND b (same as juxtaposition, just explicit)
label:a OR label:b => a OR b
{label:a label:b} => a OR b
{label:key:v1 label:key:v2} => (key:v1 OR key:v2)
-label:a => NOT a
-(label:a label:b) => NOT (a AND b)
created:2026-01-31 => created on that day
created:>=2026-01-31 => created on or after that day (also <, >, <=; same for updated:)
A leading "-" only negates when directly (no space) followed by "(", "{", "label:", "created:", or "updated:", matching Gmail's minus-operator convention. A "-" with no valid target directly after it is a no-op and is silently dropped, rather than raising a syntax error.
A word immediately followed by ":" that isn't one of the recognized prefixes (e.g. a typo like "labe:foo") raises a specific "unknown keyword" error instead of a generic "unexpected input" one.
Defined Under Namespace
Classes: Token
Constant Summary collapse
- LABEL_PREFIX =
/label:/i- DATE_PREFIX =
/(created|updated):/i- DATE_OPERATOR =
/>=|<=|>|</- NOT_PREFIX =
/-(?=[({]|label:|created:|updated:)/i- AND_KEYWORD =
/AND\b/i- OR_KEYWORD =
/OR\b/i- KEYWORD_LOOKALIKE =
/([A-Za-z_][A-Za-z0-9_]*):/- DANGLING_NOT =
/-/- BAREWORD =
/[^\s(){}:]+/
Class Method Summary collapse
Instance Method Summary collapse
-
#initialize(input) ⇒ Lexer
constructor
A new instance of Lexer.
- #tokenize ⇒ Object
Constructor Details
#initialize(input) ⇒ Lexer
Returns a new instance of Lexer.
47 48 49 |
# File 'app/models/spectator_sport/search_query/lexer.rb', line 47 def initialize(input) @scanner = StringScanner.new(input.to_s) end |
Class Method Details
.tokenize(input) ⇒ Object
43 44 45 |
# File 'app/models/spectator_sport/search_query/lexer.rb', line 43 def self.tokenize(input) new(input).tokenize end |
Instance Method Details
#tokenize ⇒ Object
51 52 53 54 55 56 57 58 59 60 61 |
# File 'app/models/spectator_sport/search_query/lexer.rb', line 51 def tokenize tokens = [] loop do @scanner.skip(/\s+/) break if @scanner.eos? token = next_token tokens << token if token end tokens end |