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
Public Class Methods
# 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
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
Create a new empty ink list
# File lib/fable/ink_list.rb, line 59 def initialize self.list = {} self.origins = [] end
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
# 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
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
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
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
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
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
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
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
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
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
# 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
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
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
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
# File lib/fable/ink_list.rb, line 207 def count list.size end
# File lib/fable/ink_list.rb, line 174 def include_item_named?(item_name) list.any?{|item, int_value| item.name == item_name} end
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
# File lib/fable/ink_list.rb, line 111 def item_with_value(value) list.key(value) end
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
# 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
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
# 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
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
# 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 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
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
# File lib/fable/ink_list.rb, line 199 def set_initial_origin_name(initial_origin_name) @origin_names = [initial_origin_name] end
# File lib/fable/ink_list.rb, line 203 def set_initial_origin_names(initial_origin_names) @origin_names = initial_origin_names end
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