Hi all,

Here's the latest incarnation I've come up with, stealing bits of code from James Hranicky and 
ideas from Curt Sampson.

The inode and dev checks are untested, so if there's a logic flaw there, please let me know.

Opions & feedback welcome/desired.

Regards,

Dan

# Da code!
class Tail < File

   def initialize(file,sleeptime=10)
      @filename = file
      @fh = File.open(file,"r")
      @sleeptime = sleeptime

      @ino = @fh.stat.ino
      @dev = @fh.stat.dev

      @ino_changed = false
      @dev_changed = false
   end

   ##############################################################
   # In block form, read a line at a time in a loop.  Otherwise,
   # just return the number of lines specified as an array.
   ##############################################################
   def tail(max=10)
      if block_given?
         yield get_lines(max)
         loop do
            line = @fh.gets
            yield line unless line.nil?
            if @fh.eof?
               check_move()
               if (@ino_changed == true) || (@dev_changed == true)
                  @fh.close
                  initialize(@filename,@sleeptime)
                  next
               end
               @fh.seek(@fh.pos)
            end
            sleep @sleeptime
         end
      else
         get_lines(max)
      end
   end

   def check_move
      begin
         if(File.stat(@filename).ino != @ino)
            @ino_changed = true
         end
         if(File.stat(@filename).dev != @dev)
            @dev_changed = true
         end
      rescue Errno::ENOENT
         retry
      end
   end

   #######################################################################
   # Grab the last 'max' lines (default is 10).  This method was created
   # for two reasons.  First, even a "tail -f" reads the last 10 lines.
   # Second, it's separated from the tail() method in the event the
   # programmer just wants a "plain" tail.
   #######################################################################
   def get_lines(max)
      
      @fh.seek(0,IO::SEEK_END)
      newline_count = 0
      while newline_count < max 

         begin
            @fh.pos -= 2
         rescue Errno::EINVAL
            break
         end

         break if @fh.eof?

         if @fh.getc.chr == "\n"
            newline_count += 1
         end
      end

      @fh.readlines
   end
end