Ara.T.Howard wrote:
> On Thu, 20 May 2004, Simon Strandgaard wrote:
> 
> > I want to clone a filedescriptor, but no matter
> > what I try I becomes ugly. The nice solution doesn't
> > seems to work.
[snip] 
> doesn't this do it?
> 
[snip]
>   f2 = f1.dup
[snip]


Hmmm bad proof of concept.. Therefore I will have to
tell the full story: Im writing a file-iterator which both can go 
forward and backwards. #dup doesn't work here, only
the long ugly expression I showed you in the first mail.

By using #dup then my clone test fails. I have absolutely
no idea why #dup is yielding nil here.... maybe bug?

server> ruby test_file.rb 
Loaded suite XTestFile
Started
..F.
Finished in 0.042698 seconds.

  1) Failure:
test_clone1(XTestFile) [test_file.rb:106]:
<101> expected but was
<nil>.

4 tests, 5 assertions, 1 failures, 0 errors
server>


By using @file.clone.reopen(@file), then it works, but I
am not confident that it really works (because its 
really ugly).

server> ruby test_file.rb
Loaded suite XTestFile
Started
....
Finished in 0.006764 seconds.

4 tests, 6 assertions, 0 failures, 0 errors
server>


The testcase looks like

def test_clone1
  @i.next(2)
  assert_equal("c"[0], @i.current)
  i2 = @i.clone
  begin
    i2.next(2)
    assert_equal("e"[0], i2.current)
    # check that clone were harmless
    assert_equal("c"[0], @i.current)
  ensure
    i2.close
  end
end  


I have attached the source code for. In order to run it
you will need to fetch my 'iterator' package.
http://raa.ruby-lang.org/list.rhtml?name=iterator

require 'test/unit'
require 'iterator'

module Iterator

class File < Base
  def initialize(file)
    @file = file
  end
  attr_reader :file
  def clone
    #cfd = IO.new(@file.fileno, 'r')
    #cfd = @file.clone
    #cfd = @file.dup
    cfd = @file.clone.reopen(@file)                    # BOOM BOOM BOOM...  this clone is ugly
    #puts "FD=#{@file.fileno} CLONE=#{cfd.fileno}"
    self.class.new(cfd)
  end
  def close
    @file.close
  end
  def first
    @file.rewind
    self
  end
  def last
    @file.seek(0, IO::SEEK_END)
    self
  end
  def has_next?
    not @file.eof?
  end
  def next1
    @file.seek(1, IO::SEEK_CUR)
  end
  def current
    byte = @file.getc
    @file.seek(-1, IO::SEEK_CUR)
    byte
  end
  def has_prev?
    (@file.pos > 0)
  end
  def prev1
    @file.seek(-1, IO::SEEK_CUR)
  end
  def current_prev
    @file.seek(-1, IO::SEEK_CUR)
    @file.getc
  end
end

end # module Iterator

class XTestFile < Test::Unit::TestCase
  def setup
    @data = "abcdefg"
    #@i = @data.create_iterator   # yields integers between 0..255
    @filename = "____filedata"
    File.open(@filename, "w+") do |f|
      f.write(@data)
    end
    @file = File.open(@filename, "r")
    @i = Iterator::File.new(@file)
  end
  def teardown
    @i.close
    raise "@file not closed" unless @file.closed?
  end
  def test_forward1
    result = []
    while @i.has_next?
      result << @i.current
      @i.next
    end
    assert_equal("abcdefg", result.map{|byte| byte.chr}.join)
  end
  def test_backward1
    @i.last
    result = []
    while @i.has_prev?
      result << @i.current_prev
      @i.prev
    end
    result.reverse!
    assert_equal("abcdefg", result.map{|byte| byte.chr}.join)
  end
  def test_backward2
    rev = @i.last.reverse
    result = []
    while rev.has_next?
      result << rev.current
      rev.next
    end
    result.reverse!
    assert_equal("abcdefg", result.map{|byte| byte.chr}.join)
  ensure
    rev.close
  end
  def test_clone1
    @i.next(2)
    assert_equal("c"[0], @i.current)
    i2 = @i.clone
    begin
      i2.next(2)
      assert_equal("e"[0], i2.current)
      # check that clone were harmless
      assert_equal("c"[0], @i.current)
    ensure
      i2.close
    end
  end
end

if $0 == __FILE__
  require 'test/unit/ui/console/testrunner'
  Test::Unit::UI::Console::TestRunner.run(XTestFile)
end


BTW: I am using CVS-head version of Ruby.
server> ruby -v
ruby 1.9.0 (2004-05-17) [i386-freebsd5.1]
server>

-- 
Simon Strandgaard