class Gamefic::Query::Base

A base class for entity-based queries that can be applied to responses. Each query represents an attempt to match an argument in a command to a game entity.

Attributes

ambiguous[R]

@return [Boolean]

arguments[R]

@return [Array<Object>]

narrative[RW]

Public Class Methods

new(*arguments, ambiguous: false, name: self.class.to_s) click to toggle source

@raise [ArgumentError] if any of the arguments are nil

@param arguments [Array<Object>] @param ambiguous [Boolean] @param name [String]

# File lib/gamefic/query/base.rb, line 23
def initialize *arguments, ambiguous: false, name: self.class.to_s
  raise ArgumentError, "nil argument in query" if arguments.any?(&:nil?)

  @arguments = arguments
  @ambiguous = ambiguous
  @name = name
end

Public Instance Methods

accept?(subject, object) click to toggle source

True if the object is selectable by the subject.

@param subject [Entity] @param object [Array<Entity>, Entity] @return [Boolean]

# File lib/gamefic/query/base.rb, line 80
def accept?(subject, object)
  available = select(subject)
  if ambiguous?
    object & available == object
  else
    available.include?(object)
  end
end
ambiguous?() click to toggle source
# File lib/gamefic/query/base.rb, line 94
def ambiguous?
  @ambiguous
end
filter(subject, token)
Alias for: query
inspect() click to toggle source
# File lib/gamefic/query/base.rb, line 102
def inspect
  "##{ambiguous? ? '*' : ''}#{name}(#{normalized_arguments.map(&:inspect).join(', ')})"
end
name() click to toggle source
# File lib/gamefic/query/base.rb, line 98
def name
  @name || self.class.to_s
end
precision() click to toggle source

@return [Integer]

# File lib/gamefic/query/base.rb, line 90
def precision
  @precision ||= calculate_precision
end
query(subject, token) click to toggle source

Get a query result for a given subject and token.

@example

respond :reds do |actor|
  reds = available(ambiguous: true).query(actor, 'red').match
  actor.tell "The red things you can see here are #{reds.join_and}."
end

@param subject [Gamefic::Entity] @param token [String] @return [Result]

# File lib/gamefic/query/base.rb, line 42
def query(subject, token)
  first_pass = Scanner.scan(span(subject), token)
  if ambiguous?
    ambiguous_result(first_pass.filter(*normalized_arguments))
  elsif first_pass.match.one?
    unambiguous_result(first_pass.filter(*normalized_arguments))
  else
    unambiguous_result(first_pass)
  end
end
Also aliased as: filter
select(subject) click to toggle source

Get an array of entities that match the arguments from the context of the subject.

@param subject [Entity] @return [Array<Entity>]

# File lib/gamefic/query/base.rb, line 59
def select subject
  span(subject).that_are(*normalized_arguments)
end
span(_subject) click to toggle source

Get an array of entities that are candidates for selection from the context of the subject. These are the entities that select will filter through query’s arguments.

Subclasses should override this method.

@param subject [Entity] @return [Array<Entity>]

# File lib/gamefic/query/base.rb, line 71
def span _subject
  []
end

Private Instance Methods

ambiguous_result(scan) click to toggle source

@param scan [Scanner::Result]

# File lib/gamefic/query/base.rb, line 131
def ambiguous_result scan
  return Result.new(nil, scan.token) if scan.matched.empty?

  Result.new(scan.matched, scan.remainder)
end
calculate_precision() click to toggle source
# File lib/gamefic/query/base.rb, line 108
def calculate_precision
  normalized_arguments.sum(@ambiguous ? -1000 : 0) do |arg|
    case arg
    when Entity, Proxy, Proxy::Base
      1000
    when Class, Module
      class_depth(arg) * 100
    else
      1
    end
  end
end
class_depth(klass) click to toggle source
# File lib/gamefic/query/base.rb, line 121
def class_depth klass
  return 1 unless klass.is_a?(Class)

  depth = 1
  sup = klass
  depth += 1 while (sup = sup.superclass)
  depth
end
normalized_arguments() click to toggle source
# File lib/gamefic/query/base.rb, line 144
def normalized_arguments
  @normalized_arguments ||= arguments.map do |arg|
    case arg
    when Proxy, Proxy::Base
      arg.fetch(narrative)
    when String
      proc do |entity|
        arg.keywords.all? { |word| entity.keywords.include?(word) }
      end
    else
      arg
    end
  end
end
unambiguous_result(scan) click to toggle source

@param scan [Scanner::Result]

# File lib/gamefic/query/base.rb, line 138
def unambiguous_result scan
  return Result.new(nil, scan.token) unless scan.matched.one?

  Result.new(scan.matched.first, scan.remainder, scan.strictness)
end