I created a little utility extension to handle this situation. The extension is a little ugly, but it does make for neater code everywhere else.
It allows you to write code like :
nodes.each_position do |position|
position.first do |first_node|
# Do stuff on just the first node
end
position.all do |node|
# Do stuff on all the nodes
end
position.last do |last_node|
# Do some extra stuff on the last node
end
end
Add this somewhere :
#
# Extends enumerable to give us a function each_index
# This returns an Index class which will test if we are the first or last
# or so item in the list
# Allows us to perform operations on only selected positions of an enumerable.
#
module Enumerable
class Index
attr_accessor :index
attr_accessor :object
def initialize(count)
@index = 0
@count = count
@object = nil
end
def first
if @index == 0
yield(@object)
end
end
def not_first
if @index != 0
yield(@object)
end
end
def last
if @index == @count - 1
yield(@object)
end
end
def not_last
if @index != @count - 1
yield(@object)
end
end
def all
yield(@object)
end
def index(idx)
if @index == idx
yield(@object)
end
end
end
# Add the method to enumerables.
# Iterates through the list. For each element it creates an Index instance
# and passes it the index of the iteration, the length of our list and the
# object at the index.
#
def each_position
count = 0
index = Index.new(self.length)
self.each do |obj|
index.index = count
index.object = obj
yield index
count += 1
end
end
end