I think the best solution would be to create some sort of objects to
handle being checked for position.  This way, you can change the
appropriate methods based on your enum (sure, a little more work, but
you can avoid O(N^2) work for last operations if you're smart...)

Here's what I envisioned:

---- Enumerable Hack ----

  module Enumerable
    class PositionVariable
      attr_reader :index, :enum
      def initialize(idx, enum)
        @index, @enum = idx, enum
      end
      
      def === (p)
        meth = "index_#{p}?".intern
        @enum.send(meth, @index)
      end

      def inspect
        "#{@index.inspect} : #{@enum.inspect}"
      end
      
      def is?(index_check)
        index_check.is?(self)
      end
    end

    def Enumerable.make_index_const(namestr)
      o = Object.new
      o.instance_eval {@name = namestr}
      class << o
        def ===(positionVar)
          self.is?(positionVar)
        end
        def to_s
          @name
        end

        def is?(positionVar)
          positionVar === self
        end
      end
      
      o
    end

    def each_with_pos
      fail "A block is needed for Enumerable#each_with_pos." unless block_given?
      self.each_with_index {|e, i|
        yield e, PositionVariable.new(i, self)
      }
    end
  end

---- end Enumerable Hack ----

then, in my program, I have somethnig like this:

  module Enumerable  
    FIRST, LAST, PRIME, EVEN, ODD = *%w{first last prime even odd}.map {|str|
      Enumerable.make_index_const(str)
    }

    def index_first?(idx)
      idx == 0
    end

    def index_last?(idx)
      self.size == idx + 1
    end

    def index_even?(idx)
      idx % 2 == 0
    end
    
    def index_odd?(idx)
      !index_even?(idx)
    end

    def index_prime?(idx)
       # standard prime test algorithm of your choice.
    end
  end


and then you can have something like this:

myenum.each_with_pos {|e, pos|
  case pos
    when Enumerable::FIRST then ...
    when Enumerable::LAST then ....
    when ...
  end

  if pos.is?(Enumerable::FIRST) then
     ...
  else
     ...
  end
}


it might be to `cluttery' for the enum namespace, though - but it's
also just dependent on you filling stuff out for the enums - or just
deciding to accept some defaults (like index_first? ...) (and
overriding the bad defaults when it comes time to...)


-- 
There's no word in the English language for what you do to a dead
thing to make it stop chasing you.