class Gamefic::Syntax
Syntax.new(‘search :container for :thing’, ‘look :thing :container’)
Syntax.new(‘look at :thing inside :container’, ‘look :thing :container’)
Syntax.new(‘examine :thing in :container’, ‘look :thing :container’)
form “look thing container”
@example All of these syntaxes will translate input into a command of the
`:thing`) to identify phrases that should be tokenized into arguments.
The template and command patterns use words beginning with a colon (e.g.,
variations in sentence structure.
Common uses are to provide synonyms for response verbs and allow for
Syntaxes provide rules for matching input patterns to existing responses.
def self.literal_or_nil(string)
-
(Symbol, nil)
-
Parameters:
-
string
(String
) --
def self.literal_or_nil(string) string.start_with?(':') ? nil : string.to_sym end
def self.tokenize(text, syntaxes)
-
(Array
- The tokenized expressions.)
Parameters:
-
syntaxes
(Array
) -- The syntaxes to use. -
text
(String
) -- The text to tokenize.
def self.tokenize(text, syntaxes) syntaxes .map { |syn| syn.tokenize(text) } .compact .uniq { |exp| [exp.verb, exp.tokens] } .sort_by { |exp| [-exp.tokens.compact.length] } end
def ==(other)
def ==(other) signature == other&.signature end
def accept?(text)
-
(Boolean)
-
Parameters:
-
text
(String
) --
def accept?(text) !!text.match(regexp) end
def initialize(template, command)
-
command
(String
) -- -
template
(String
) --
def initialize(template, command) @template = template.normalize @params = @template.keywords.select { |word| word.start_with?(':') } @command = command.normalize @verb = Syntax.literal_or_nil(@command.keywords[0]) @replace = parse_replace end
def make_tokens
-
(Array
-)
def make_tokens template.keywords.map.with_index do |word, idx| next word unless word.match?(PARAM_REGEXP) next nil if idx.positive? && template.keywords[idx - 1].match?(PARAM_REGEXP) '([\w\W\s\S]*?)' end.compact end
def match_to_args(match)
def match_to_args(match) start = replace.start_with?('{') ? 0 : 1 replace.keywords[start..].map do |str| str.match?(/^\{\$[0-9]+\}$/) ? match[str[2..-2].to_i] : str end end
def parse_replace
def parse_replace command.keywords.map do |word| next word unless word.start_with?(':') index = params.index(word) || raise(ArgumentError, "syntax command references undefined parameter `#{word}`") "{$#{index + 1}}" end.join(' ') end
def regexp
-
(Regexp)
-
def regexp @regexp ||= Regexp.new("^#{make_tokens.join(' ')}$", Regexp::IGNORECASE) end
def signature
Signatures are used to compare Syntaxes to each other.
Get a signature that identifies the form of the Syntax.
def signature [regexp, replace] end
def synonym
-
(Symbol)
-
def synonym @synonym ||= Syntax.literal_or_nil(template.keywords.first) end
def tokenize(text)
-
(Expression, nil)
-
Parameters:
-
text
(String
) --
def tokenize(text) match = text&.match(regexp) return nil unless match Expression.new(verb, match_to_args(match)) end