Files ugly clone

I want to clone a filedescriptor, but no matter
what I try I becomes ugly. The nice solution doesn’t
seems to work.

f1 = File.open(FILE, ‘r’)
f1.seek(5)
p f1.pos # -> 5
f2 = f1.clone.reopen(f1) # this is nasty… but works
f2.seek(10)
p f2.pos # -> 10

check harmless

p f1.pos # -> 5

how can I make a nice clone?

···


Simon Strandgaard

doesn’t this do it?

~ > cat a.rb
f1 = File.open(FILE, ‘r’)
f1.seek(5)
p f1.pos # → 5

#f2 = f1.clone.reopen(f1) # this is nasty… but works
f2 = f1.dup

f2.seek(10)
p f2.pos # → 10

check harmless

p f1.pos # → 5

~ > ruby a.rb
5
10
5

-a

···

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.

f1 = File.open(FILE, ‘r’)
f1.seek(5)
p f1.pos # → 5
f2 = f1.clone.reopen(f1) # this is nasty… but works
f2.seek(10)
p f2.pos # → 10

check harmless

p f1.pos # → 5

how can I make a nice clone?

EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
PHONE :: 303.497.6469
ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
URL :: Solar-Terrestrial Physics Data | NCEI
“640K ought to be enough for anybody.” - Bill Gates, 1981
===============================================================================

Ara.T.Howard 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?

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
    .

4 tests, 5 assertions, 1 failures, 0 errors

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

ruby test_file.rb
Loaded suite XTestFile
Started

Finished in 0.006764 seconds.

4 tests, 6 assertions, 0 failures, 0 errors

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.

ruby -v
ruby 1.9.0 (2004-05-17) [i386-freebsd5.1]

···

On Thu, 20 May 2004, Simon Strandgaard wrote:


Simon Strandgaard

Solved, just discovered that #dup clones, but without
cloning the position. Shouldn’t #dup clone the file position,
rather than leaving it as garbage ?

ruby a.rb
5
199 # <<<<< GARBAGE when using #dup
10
5
cat a.rb
f1 = File.open(FILE, ‘r’)
f1.seek(5)
p f1.pos # → 5
#f2 = f1.clone.reopen(f1)
f2 = f1.dup
p f2.pos # ugly → 5, dup → garbage
f2.seek(10)
p f2.pos # → 10

check harmless

p f1.pos # → 5

maybe I should make an RCR about this issue ?

···


Simon Strandgaard

“Simon Strandgaard” neoneye@adslhome.dk schrieb im Newsbeitrag
news:20040520180647.57559b82.neoneye@adslhome.dk…

Solved, just discovered that #dup clones, but without
cloning the position. Shouldn’t #dup clone the file position,
rather than leaving it as garbage ?

Probably. OTOH hand I view file positions as tentative: you have to re-seek
anyway if you want to change from reading to writing or vice versa and in
some other situations I believe.

robert
···

ruby a.rb
5
199 # <<<<< GARBAGE when using #dup
10
5
cat a.rb
f1 = File.open(FILE, ‘r’)
f1.seek(5)
p f1.pos # → 5
#f2 = f1.clone.reopen(f1)
f2 = f1.dup
p f2.pos # ugly → 5, dup → garbage
f2.seek(10)
p f2.pos # → 10

check harmless

p f1.pos # → 5

maybe I should make an RCR about this issue ?


Simon Strandgaard

Robert Klemme wrote:

“Simon Strandgaard” neoneye@adslhome.dk schrieb im Newsbeitrag
news:20040520180647.57559b82.neoneye@adslhome.dk…

Solved, just discovered that #dup clones, but without
cloning the position. Shouldn’t #dup clone the file position,
rather than leaving it as garbage ?

Probably. OTOH hand I view file positions as tentative: you have to re-seek
anyway if you want to change from reading to writing or vice versa and in
some other situations I believe.

Yes the file concept is in general old… it has some oddities.
Accessing files as iterators are a more modern approach.
But thats another story.

What really took me long time today was that I thought File#dup was broken
and didn’t performed clone… then it took me half another hour to come
up with the other idea f1.clone.reopen(f1), which just were ugly.
Finally I discovered that all this confusion were caused because #dup
did not copy the file-position and that I have to re-seek afterwards.

What would be nice if make #dup would copy the file-position.

Otherwise add a few pages to RI about File#dup, that you have to
do the seek manually afterwards.

Am I the only one which is frustrated about this ???

···


Simon Strandgaard