Created
February 1, 2009 19:30
-
-
Save allynbauer/55955 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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