Ouroboros (Class)

In: Ouroboros.rb
Parent: Object

The Ouroboros class represents a circular linked list of items. (The name comes from the symbol of a snake eating its own tail. See the Wikipedia for more information.)

In addition to the current method (showing the current ‘head’ of the list), the increment and decrement methods (which move the current pointer and return the new item), and the ability to access list items by offset (see #[]), you can navigate the list by using the custom next and prev attributes which are placed on every item in the list.

A new circular list can be created from an array (Ouroboros.from_a), by fixed number of ‘template’ instances (new without a block), or by calling an initialization block a fixed number of times and using the return values for each item in the list (new with a block).

Due to the reliance on the custom next and prev methods mixed into each instance in the circular list, the same item may not be placed into more than one circular list at a time.

Example:

 # Keep track of a running average of the frame rate
 total_samples = 10
 framerate_samples = Ouroboros.new( total_samples, { :fps => 0, :when => Time.new } )
 framerate_total = 0
 while app_is_running
   framerate_total -= framerate_samples[1][:fps]
   framerate_total += current_framerate
   framerate_samples.increment[:fps] = current_framerate
   $running_average_framerate = framerate_total.to_f / total_samples
 end

Attributes

current  [RW]  Gets or sets the item referred to as the current head of the list.
size  [R]  Returns the number of items in the list

Classes and Modules

Module Ouroboros::PrevNext

Public Class methods

Create a new circular list from an array. Each item in the array receives next and prev methods pointing to its neighbors. The current property for the circular list is set to the first item in the array.

Note that the items in the array are not duplicated, and the same item may not be in more than one circular list.

Create a new circular list.

size:The size of (number of items in) the circular list.
template:A template object to use for each item in the list. (optional)
initialize_block:A block to call to initialize the items in the list. (optional)

If template is passed, it is duplicated (using Object#dup) to create each item in the list. If it is not passed (and initialize_block is not given), an empty Hash will be used for each item.

If a block is supplied, template is ignored. Instead, the block will be yielded to once for each item to appear in the list, passing in an index value in the range 0...size. The result of each call to the block will be used for that item in the list.

At the end, every item in the list is extended by PrevNext to have a next and prev method pointing to adjacent items.

Example:

  list = Ouroboros.new( 5 )     # creates a circular list of 5 empty hashes,
                                # each with a .next and .prev method.

  p = Person.new( 'John Doe' )
  list = Ouroboros.new( 5, p )  # creates a circular list of 5 clones of John Doe

  list = Ouroboros.new( 10 ){ |i|
    Person.new( "Dummy Person #{i}" )
  }

See Ouroboros.from_a for a convenient way to convert an array into a circular list.

Public Instance methods

Returns the item in the list which is offset from the current item.

offset:The number of steps forwards (positive) or backwards (negative) to take.

the_list[0] returns the same item as the_list.current (but is slightly slower); the_list[1] is the same as the_list.current.next, the_list[2] is the same as the_list.current.next.next, and so on.

Sets the item at the specified offset from the current location.

offset:The number of steps forwards (positive) or backwards (negative) to take.
new_obj:The object to place into the list. (Does not have to be an object from the list.)

If new_obj already exists in the list, it will be removed from that location first.

Tests if any adjacent entries in the array are the ‘same’.

If a block is passed, each entry in the list will be passed to the block, and the return value is used to test if two entries are the ‘same’ or not. If no block is passed to the method, the objects themselves are used for comparison.

Applies the supplied block to each item in the list, returning an array of the results.

Starts with the current item and moves forward through the list.

Applies the supplied block to each item in the list, returning an array of the results.

Starts with the current item and moves backwards through the list.

Sets the current property to the previous item and returns it.

Removes an item from the circular list, returning it (or nil if the object is not in this list).

If obj is the current item, current will be set to obj.next.

Yield to the supplied block for each item in the circular list, starting with the current item and moving ‘forward’ through them.

Yield to the supplied block for each item in the circular list, starting with the current item and moving ‘backwards’ through them.

Sets the current property to the next item and returns it.

Insert an object into the circular list.

next_obj:The object to insert the new object ahead of.
new_obj:The object to insert into the list.

(new_obj.next will point to next_obj, next_obj.prev will point to new_obj, and so on).

Example:

 list = Ouroboros.from_a ['a','b','c','d','e']
 p list.to_a                                    #=> ["a", "b", "c", "d", "e"]
 d = list[ 3 ]
 2.times{ list.increment }
 p list.to_a                                    #=> ["c", "d", "e", "a", "b"]
 list.insert_before( d, 'zzz' )
 p list.to_a                                    #=> ["c", "zzz", "d", "e", "a", "b"]

Attemps to ensure that no adjacent entries in the list are the ‘same’. (A kind of ‘unsort’.)

If a block is passed, each entry in the array will be passed to the block, and the return value will be used to test if two entries are the ‘same’ or not. If no block is passed to the method, the objects themselves are used for comparison.

Some lists cannot be re-arranged to meet the the no-adjacent-duplicates criteria; if this occurs, an exception will be raised.

This method creates a new copy of the

Example:

 Ouroboros.from_a(%w|a a b c d e e a|).separate_duplicates!.to_a
 #=> ["a", "e", "a", "b", "a", "c", "d", "e"]

 separated_families = every_person.separate_duplicates{ |person|
    person.last_name
 }

 Ouroboros.from_a(%w|a a b c d e e a a a a|).separate_duplicates!.to_a
 #=> Error: #separate_duplicates! was unsuccessful after 121 rounds. (RuntimeError)

Swap the location of two items in the circular list.

Returns an array of all items in the list, starting at the current location.

Starting with the current item, calls to_s on each item in the list and returns each on its own line.

[Validate]