Files ugly clone

S

Simon Strandgaard

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?
 
A

Ara.T.Howard

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?

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
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| ADDRESS :: E/GC2 325 Broadway, Boulder, CO 80305-3328
| URL :: http://www.ngdc.noaa.gov/stp/
| "640K ought to be enough for anybody." - Bill Gates, 1981
===============================================================================
 
S

Simon Strandgaard

Ara.T.Howard said:
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>
 
S

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 ?

server> ruby a.rb
5
199 # <<<<< GARBAGE when using #dup
10
5
server> 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
server>


maybe I should make an RCR about this issue ?
 
R

Robert Klemme

Simon Strandgaard said:
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
 
S

Simon Strandgaard

Robert said:
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 ???
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,145
Messages
2,570,826
Members
47,373
Latest member
Desiree036

Latest Threads

Top