Skip to content

Instantly share code, notes, and snippets.

@allynbauer
Created February 1, 2009 19:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save allynbauer/55955 to your computer and use it in GitHub Desktop.
Save allynbauer/55955 to your computer and use it in GitHub Desktop.
# 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 <allyn.bauer@gmail.com>
# v1.2 3 February 2009
# v1.3 7 March 2010 - change to Array delegate
#
require 'delegate'
class Collection < DelegateClass(Array)
# 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
super(@collection)
@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)
super(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
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment