# A collection is a list (or an array, if you will) of symbols. This class is inspired by # Ada 95's Enumeration Types, although the only relevant components of which are essentially just 'an array that wraps.' # This class maintains an internal pointer, which points to the current symbol in the collection. # Author: Allyn Bauer # v1.2 3 February 2009 # class Collection # Items is a list or an Array of the items this method will contain. These items are not changeable. def initialize(*items) if items.first.is_a? Array # if items is an array @collection = *items else @collection = items end @collection.collect! { |item| item.to_sym } @collection.freeze # Collection does not allow changes to its data # the only real reason for this is not wanting to handle pointer issues that could result from modification @pointer = 0 # Our internal pointer rescue NoMethodError => exc # A collection maintains symbols. raise ArgumentError.new("Cannot instantiate Collection because an item can't be made into a symbol.\n#{exc}") end # Advances the pointer and returns the element that is amt from the current, wrapping. def next(amt = 1) @pointer = up(amt) current end # Reduces the pointer and return the element that is amt before the current, wrapping. def prev(amt = 1) @pointer = down(amt) current end # Return the item that is before object def predecessor_of(object) action_of(object, :down) end # Return the item that is after object def successor_of(object) action_of(object, :up) end # Sets the internal pointer to the position provided, or the position of the object provided # If the provided input is invalid, @pointer is reset def set_to(pos) if index?(pos) @pointer = wrap(pos) elsif @collection.include?(pos) @pointer = index(pos) else @pointer = 0 end current end # Returns the current pointer location as an integer def pos @pointer end # Return the current element without advancing the pointer def current item_at pos end # The item at position def item_at(position) @collection[position] end def index(object) @collection.index(object.to_sym) end # Reset the internal pointer to the beginning. def reset @pointer = 0 end def to_s @collection.collect { |x| x == current ? "(#{x})" : x }.join(" ") end def to_a @collection end protected # If we can't find a method here, give it to the array. def method_missing(*args, &block) @collection.send(*args, &block) end private def index?(item) item.is_a? Fixnum or item.is_a? Integer end def action_of(object, direction) if index?(object) item_at(send(direction, 1, object)) else item_at(send(direction, 1, @collection.index(object))) end end # Return an wrapped integer, which is @pointer++ or from++ def up(amt = 1, from = @pointer) wrap(from + amt) end def down(amt = 1, from = @pointer) wrap(from - amt) end def wrap(int) int % @collection.length end end