class Fable::InkList

The InkList is the underlying type that's used to store an instance of a list in ink. It's not used for the definition of the list, but for a list value that's stored in a variable.

Attributes

list[RW]
origins[RW]

Public Class Methods

copy_list(other_list) click to toggle source
# File lib/fable/ink_list.rb, line 64
def self.copy_list(other_list)
  ink_list = self.new
  other_list_data = other_list.list.map{|item, int_value| [InkList::InkListItem.new(full_name: item.full_name), int_value] }
  ink_list.list = Hash[other_list_data]
  ink_list.origins = other_list.origins
  ink_list.set_initial_origin_names(other_list.origin_names)

  return ink_list
end
from_string(my_list_item, origin_story) click to toggle source

Converts a string to an ink list, and returns for use in the Story

# File lib/fable/ink_list.rb, line 99
def self.from_string(my_list_item, origin_story)
  list_value = origin_story.list_definitions[my_list_item]
  if list_value.nil?
    raise Error("Could not find the InkListItem from the string '#{my_list_item}' to create an InkList because it doesn't exist in the original list definition in ink.")
  else
    ink_list = self.new
    ink_list.list = list_value
  end

  return ink_list
end
new() click to toggle source

Create a new empty ink list

# File lib/fable/ink_list.rb, line 59
def initialize
  self.list = {}
  self.origins = []
end
new_for_origin_definition_and_story(single_origin_list_name, origin_story) click to toggle source

Create a new empty ink list that's intended to hold items from a particular origin list definition. The origin story is needed in order to be able to look up that definition

# File lib/fable/ink_list.rb, line 84
def self.new_for_origin_definition_and_story(single_origin_list_name, origin_story)
  ink_list = self.new
  ink_list.set_initial_origin_name(single_origin_list_name)

  list_definition = origin_story.list_definitions.find_list(single_origin_list_name)
  if list_definition.nil?
    raise Error("InkList origin could not be found in story when constructing new list: #{single_origin_list_name}")
  else
    ink_list.origins = [list_definition]
  end

  return ink_list
end
new_with_single_item(item, value) click to toggle source
# File lib/fable/ink_list.rb, line 74
def self.new_with_single_item(item, value)
  ink_list = self.new
  ink_list.list[item] = value

  return ink_list
end

Public Instance Methods

&(other_list) click to toggle source

Return a new list that is the intersection of the current list and one that's passed in. The equivalent of calling (list1 ^ list2) in ink.

# File lib/fable/ink_list.rb, line 269
def &(other_list)
  intersection_list = self.class.new
  self.list.each do |item, int_value|
    if other_list.list.any?{|other_item, other_value| other_item.equal?(item)}
      intersection_list.list[item] = int_value
    end
  end

  return intersection_list
end
+(other_list) click to toggle source

Return a new list that is a combination of the current list and one that's passed in. The equivalent of calling (list1 + list2) in ink.

# File lib/fable/ink_list.rb, line 258
def +(other_list)
  union_list = self.class.copy_list(self)
  other_list.list.each do |item, int_value|
    union_list.list[item] = int_value
  end

  return union_list
end
-(other_list) click to toggle source

Returns a new list that's the same as the current one, except with the given items removed that are in the passed-in list. Equivalent to calling (list1 - list2) in ink.

# File lib/fable/ink_list.rb, line 283
def -(other_list)
  without_list = self.class.copy_list(self)
  other_list.list.each do |item, int_value|
    without_list.list.delete_if{ |without_list_item, other_value| without_list_item.equal?(item)}
  end

  return without_list
end
<(other_list) click to toggle source

Returns true if all the item values in the current list are less than all the item values in the passed-in list. Equivalent to calling (list1 < list2 in ink)

# File lib/fable/ink_list.rb, line 325
def <(other_list)
  return false if other_list.list.empty?
  return true if self.list.empty?

  return self.max_item[1] < other_list.min_item[1]
end
<=(other_list) click to toggle source

Returns true if the item values in the current list overlap, or are all less than the item values in the passed in list. None of the item values in the current list must go above the item values in the passed in list. Equivalent to (list1 <= list2) in ink, or LIST_MAX(list1) <= LIST_MAX(list2) && LIST_MIN(list1) <= LIST_MIN(list2)

# File lib/fable/ink_list.rb, line 336
def <=(other_list)
  return false if other_list.list.empty?
  return true if self.list.empty?

  return (
    self.max_item[1] <= other_list.max_item[1] &&
    self.min_item[1] <= other_list.min_item[1]
  )
end
==(other_list) click to toggle source

Returns true if the passed object is also an ink list that contains the same items as the current list, false otherwise.

# File lib/fable/ink_list.rb, line 400
def ==(other_list)
  return false if !other_list.is_a?(InkList)
  return false if other_list.list.size != self.list.size

  return self.list.all?{|item, int_value| other_list.list.has_key?(item) }
end
>(other_list) click to toggle source

Returns true if all the item values in the current list are greater than all the item values in the passed-in list. Equivalent to calling (list1 > list2) in ink.

# File lib/fable/ink_list.rb, line 301
def >(other_list)
  return false if self.list.empty?
  return true if other_list.list.empty?

  return self.min_item[1] > other_list.max_item[1]
end
>=(other_list) click to toggle source

Returns true if the item values in the current list overlap, or are all greater than the item values in the passed-in list. None of the item values in the current list must fall below the item values in the passed-in list Equivalent to (list1 >= list2) in ink, or LIST_MIN(list1) >= LIST_MIN(list2) && LIST_MAX(list1) >= LIST_MAX(list2)

# File lib/fable/ink_list.rb, line 313
def >=(other_list)
  return false if self.list.empty?
  return true if other_list.list.empty?

  return (
    self.min_item[1] >= other_list.min_item[1] &&
    self.max_item[1] >= other_list.max_item[1]
  )
end
add_ink_list_item(item) click to toggle source

Adds the given item to the ink list. Note that the item must come from a list definition that is already “known” to this list, so that teh item's value can be looked up. By “known”, we mean that it alreadyu has items in it from that source, or did at one point. It can't be a completely fresh empty list, or a list that only contains items from a different list definition

# File lib/fable/ink_list.rb, line 128
def add_ink_list_item(item)
  if item.origin_name.nil?
    return add_item_from_string(item.item_name)
  end

  origins.each do |origin|
    if origin.name == item.origin_name
      integer_value = origin.items[item]

      if integer_value.nil?
        raise Error("Could not add the item '#{item.item_name}' to this list because it doesn't exist in the original list definition in ink.")
      else
        self.list[item] = integer_value
      end
    end
  end

  raise Error("Failed to add item to list because the item was from a new list definition that wasn't previously known to this list. Only items from previously known lists can be used, so that the int value can be found.")
end
add_item(item_or_item_name) click to toggle source
# File lib/fable/ink_list.rb, line 115
def add_item(item_or_item_name)
  if item_or_item_name.is_a?(InkListItem)
    add_ink_list_item(item_or_item_name)
  else
    add_item_from_string(item_or_item_name)
  end
end
add_item_from_string(item_name) click to toggle source

Adds the given item to the ink list, attempting to find the origin list definition that it belongs to. The item must therefore come from a list definition that is already “known” to this list, so that the item's value can be looked up. By “known”, we mean that it already has items in it from that source, or it did at one point. It can't be a completely fresh empty list, or a list that only contains items from a different list definition

# File lib/fable/ink_list.rb, line 153
def add_item_from_string(item_name)
  found_list_definition = nil
  origins.each do |origin|
    if origin.items.any?{|item, int_value| item.name == item_name }
      if found_list_definition.nil?
        found_list_definition = origin
      else
        raise Error("Could not add the item '#{item_name}' to this list because it could come from either '#{origin.name}' or '#{found_list_definition.name}'")
      end
    end
  end

  if found_list_definition.nil?
    raise Error("Could not add the item '#{item_name}' to this list because it isn't known to any list definitions previously associated with this list.")
  end

  item = InkListItem.new(origin_name: found_list_definition.name, item_name: item_name)
  item_value = found_list_definition.value_for_item(item)
  self.items[item] = item_value
end
all() click to toggle source

The list of all items from the original list definition, equivalent to calling LIST_ALL(list) in ink.

# File lib/fable/ink_list.rb, line 245
def all
  new_list = self.class.new
  origins.each do |origin|
    origin.items.each do |item, int_value|
      new_list.list[item] = int_value
    end
  end

  new_list
end
contains?(other_list) click to toggle source

Returns true if the current list contains all the items that are in the list that is passed in. Equivalent to calling (list1 ? list2) in ink.

# File lib/fable/ink_list.rb, line 294
def contains?(other_list)
  other_list.list.all?{|other_item, other_value| self.list.any?{|item, value| other_item.equal?(item) }}
end
count() click to toggle source
# File lib/fable/ink_list.rb, line 207
def count
  list.size
end
include_item_named?(item_name) click to toggle source
# File lib/fable/ink_list.rb, line 174
def include_item_named?(item_name)
  list.any?{|item, int_value|  item.name == item_name}
end
inverse() click to toggle source

The inverse of the list, equivalent to colling LIST_INVERSE(list) in ink.

# File lib/fable/ink_list.rb, line 230
def inverse
  new_list = self.class.new
  origins.each do |origin|
    origin.items.each do |item, int_value|
      if self.list.none?{|item_to_search, other_value| item_to_search.equal?(item)}
        new_list.list[item] = int_value
      end
    end
  end

  new_list
end
item_with_value(value) click to toggle source
# File lib/fable/ink_list.rb, line 111
def item_with_value(value)
  list.key(value)
end
list_with_subrange(min_bound, max_bound) click to toggle source

Returns a sublist with the elements given in the minimum & maximum bounds. The bounds can either be ints, which are indicies into the entire (sorted) list, or they can be InkLists themsevles. These are intended to be single-item lists, so you can specify the upper & lower bounds. If you pass in multi-item lists, it'll use the minimum and maximum items in those lists, respectively.

# File lib/fable/ink_list.rb, line 367
def list_with_subrange(min_bound, max_bound)
  return self.class.new if self.list.empty?

  ordered = self.ordered_items

  min_value = 0
  max_value = Float::INFINITY

  if min_bound.is_a?(Numeric)
    min_value = min_bound
  elsif min_bound.is_a?(InkList) && !min_bound.list.empty?
    min_value = min_bound.min_item[1]
  end

  if max_bound.is_a?(Numeric)
    max_value = max_bound
  elsif max_bound.is_a?(InkList) && !max_bound.list.empty?
    max_value = max_bound.max_item[1]
  end

  sublist = self.class.new
  sublist.set_initial_origin_names(origin_names)
  ordered.each do |item, int_value|
    if int_value >= min_value && int_value <= max_value
      sublist.list[item] = int_value
    end
  end

  sublist
end
max_as_list() click to toggle source
# File lib/fable/ink_list.rb, line 346
def max_as_list
  if self.list.empty?
    return self.class.new
  else
    return self.class.new_with_single_item(max_item)
  end
end
max_item() click to toggle source

Get the maximum item in the list, equivalent to calling LIST_MAX(list) in ink.

# File lib/fable/ink_list.rb, line 212
def max_item
  list.max do |a, b|
    return -1 if a[0].null_item?
    return 1 if b[0].null_item?
    a[1] <=> b[1]
  end
end
min_as_list() click to toggle source
# File lib/fable/ink_list.rb, line 354
def min_as_list
  if self.list.empty?
    return self.class.new
  else
    return self.class.new_with_single_item(min_item)
  end
end
min_item() click to toggle source

Get the minimum item in the list, equivalent to calling LIST_MIN(list) in ink.

# File lib/fable/ink_list.rb, line 221
def min_item
  list.min do |a, b|
    return -1 if a[0].null_item?
    return 1 if b[0].null_item?
    a[1] <=> b[1]
  end
end
ordered_items() click to toggle source
# File lib/fable/ink_list.rb, line 407
def ordered_items
  self.list.sort do |a, b|
    # ensure consistent ordering of mixed lists
    if(a[1] == b[1])
      a[0].origin_name <=> b[0].origin_name
    else
      a[1] <=> b[1]
    end
  end
end
origin_names() click to toggle source

Origin name needs to be serialized when content is empty, assuming a name is available, for list definitions with variable that is currently empty

# File lib/fable/ink_list.rb, line 191
def origin_names
  if self.list.any?
    @origin_names = self.list.map{|item, int_value| item.origin_name }.compact.uniq
  end

  return @origin_names
end
origin_of_max_item() click to toggle source

Story has to set this so that the value knows its origin, necessary for certain operations (eg: iteracting with ints). Only the story has access to the full set of lists, so that the origin can be resolved from the origin_list_name

# File lib/fable/ink_list.rb, line 182
def origin_of_max_item
  return nil if origins.nil?
  max_origin_name = max_item.origin_name
  origins.find{|origin| origin.name == max_origin_name }
end
set_initial_origin_name(initial_origin_name) click to toggle source
# File lib/fable/ink_list.rb, line 199
def set_initial_origin_name(initial_origin_name)
  @origin_names = [initial_origin_name]
end
set_initial_origin_names(initial_origin_names) click to toggle source
# File lib/fable/ink_list.rb, line 203
def set_initial_origin_names(initial_origin_names)
  @origin_names = initial_origin_names
end
to_s() click to toggle source

Returns a string in the form “a, b, c” with the names of the items in the list, without the origin list definition names. Equivalent to writing {list} in ink

# File lib/fable/ink_list.rb, line 421
def to_s
  ordered_items.map{|item, int_value| item.item_name }.join(", ")
end