class Gamefic::Syntax

Syntaxes provide rules for matching input patterns to existing responses. Common uses are to provide synonyms for response verbs and allow for variations in sentence structure.

The template and command patterns use words beginning with a colon (e.g., ‘:thing`) to identify phrases that should be tokenized into arguments.

@example All of these syntaxes will translate input into a command of the

form "look thing container"

  Syntax.new('examine :thing in :container', 'look :thing :container')
  Syntax.new('look at :thing inside :container', 'look :thing :container')
  Syntax.new('search :container for :thing', 'look :thing :container')

Attributes

command[R]

The pattern that will be used to tokenize the input into a command.

@return [String]

replace[R]

@return [String]

template[R]

The pattern that matching input is expected to follow.

@return [Template]

verb[R]

The response verb to which the command will be translated.

@example

syntax = Syntax.new('examine :thing', 'look :thing')
syntax.verb #=> :look

@return [Symbol]

Public Class Methods

literal_or_nil(string) click to toggle source

@param string [String] @return [Symbol, nil]

# File lib/gamefic/syntax.rb, line 113
def self.literal_or_nil string
  string.start_with?(':') ? nil : string.to_sym
end
new(template, command) click to toggle source

@param template [Template, String] @param command [String]

# File lib/gamefic/syntax.rb, line 42
def initialize template, command
  @template = Template.to_template(template)
  @command = command.normalize
  @verb = Syntax.literal_or_nil(@command.keywords[0])
  @replace = parse_replace
end
tokenize(text, syntaxes) click to toggle source

Tokenize an array of commands from the specified text. The resulting array is in descending order of precision, i.e., most to least matched tokens.

@param text [String] The text to tokenize. @param syntaxes [Array<Syntax>] The syntaxes to use. @return [Array<Expression>] The tokenized expressions.

# File lib/gamefic/syntax.rb, line 98
def self.tokenize text, syntaxes
  syntaxes
    .map { |syn| syn.tokenize(text) }
    .compact
    .sort { |syn, other_syn| syn.compare other_syn }
end

Public Instance Methods

==(other) click to toggle source
# File lib/gamefic/syntax.rb, line 87
def ==(other)
  signature == other&.signature
end
accept?(text) click to toggle source

Determine if the specified text matches the syntax’s expected pattern.

@param text [String] @return [Boolean]

# File lib/gamefic/syntax.rb, line 76
def accept? text
  !!text.match(template.regexp)
end
compare(other) click to toggle source

Compare two syntaxes for the purpose of ordering them in rulebooks.

# File lib/gamefic/syntax.rb, line 107
def compare other
  template.compare other.template
end
signature() click to toggle source

Get a signature that identifies the form of the Syntax. Signatures are used to compare Syntaxes to each other.

# File lib/gamefic/syntax.rb, line 83
def signature
  [template.regexp, replace]
end
synonym() click to toggle source

A symbol for the first word in the template. Used by rulebooks to classify groups of related syntaxes.

@example

syntax = Syntax.new('examine :thing', 'look :thing')
syntax.synonym #=> :examine

@return [Symbol]

# File lib/gamefic/syntax.rb, line 57
def synonym
  template.verb
end
tokenize(text) click to toggle source

Convert a String into a Command.

@param text [String] @return [Expression, nil]

# File lib/gamefic/syntax.rb, line 65
def tokenize text
  match = text&.match(template.regexp)
  return nil unless match

  Expression.new(verb, match_to_args(match))
end

Private Instance Methods

match_to_args(match) click to toggle source
# File lib/gamefic/syntax.rb, line 132
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
parse_replace() click to toggle source
# File lib/gamefic/syntax.rb, line 122
def parse_replace
  command.keywords.map do |word|
    next word unless word.start_with?(':')

    index = template.params.index(word) ||
            raise(ArgumentError, "syntax command references undefined parameter `#{word}`")
    "{$#{index + 1}}"
  end.join(' ')
end