Skip to content

Commit d74667c

Browse files
committed
[GR-18163] Fix IO.copy_stream with a Tempfile destination
PullRequest: truffleruby/4024 (cherry picked from commit 5178af3)
1 parent 2381252 commit d74667c

File tree

3 files changed

+39
-21
lines changed

3 files changed

+39
-21
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
Bug fixes:
44

55
* Fix `rb_enc_left_char_head()` so it is not always `ArgumentError` (#3267, @eregon).
6+
* Fix `IO.copy_stream` with a `Tempfile` destination (#3280, @eregon).
67

78
# 23.1.0
89

spec/ruby/core/io/copy_stream_spec.rb

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,12 @@
6969
end
7070

7171
it "raises an IOError if the destination IO is not open for writing" do
72-
@to_io.close
73-
@to_io = new_io @to_name, "r"
74-
-> { IO.copy_stream @object.from, @to_io }.should raise_error(IOError)
72+
to_io = new_io __FILE__, "r"
73+
begin
74+
-> { IO.copy_stream @object.from, to_io }.should raise_error(IOError)
75+
ensure
76+
to_io.close
77+
end
7578
end
7679

7780
it "does not close the destination IO" do
@@ -109,7 +112,8 @@
109112
end
110113

111114
after :each do
112-
rm_r @to_name, @from_bigfile
115+
rm_r @to_name if @to_name
116+
rm_r @from_bigfile
113117
end
114118

115119
describe "from an IO" do
@@ -164,6 +168,25 @@
164168
it_behaves_like :io_copy_stream_to_io, nil, IOSpecs::CopyStream
165169
it_behaves_like :io_copy_stream_to_io_with_offset, nil, IOSpecs::CopyStream
166170
end
171+
172+
describe "to a Tempfile" do
173+
before :all do
174+
require 'tempfile'
175+
end
176+
177+
before :each do
178+
@to_io = Tempfile.new("rubyspec_copy_stream", encoding: Encoding::BINARY, mode: File::RDONLY)
179+
@to_name = @to_io.path
180+
end
181+
182+
after :each do
183+
@to_io.close!
184+
@to_name = nil # do not rm_r it, already done by Tempfile#close!
185+
end
186+
187+
it_behaves_like :io_copy_stream_to_io, nil, IOSpecs::CopyStream
188+
it_behaves_like :io_copy_stream_to_io_with_offset, nil, IOSpecs::CopyStream
189+
end
167190
end
168191

169192
describe "from a file name" do
@@ -277,10 +300,8 @@
277300
@io.should_not_receive(:pos)
278301
IO.copy_stream(@io, @to_name)
279302
end
280-
281303
end
282304

283-
284305
describe "with a destination that does partial reads" do
285306
before do
286307
@from_out, @from_in = IO.pipe

src/main/ruby/truffleruby/core/io.rb

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -356,24 +356,20 @@ def initialize(from, to, length, offset)
356356
@method = read_method @from
357357
end
358358

359+
# From copy_stream_body in io.c in CRuby
360+
# The first element is true if obj can be used as an IO directly
359361
def to_io(obj, mode)
360-
if Primitive.is_a?(obj, IO)
361-
flag = true
362-
io = obj
363-
else
364-
flag = false
365-
366-
if Primitive.is_a?(obj, String)
367-
io = File.open obj, mode
368-
elsif obj.respond_to? :to_path
369-
path = Truffle::Type.coerce_to obj, String, :to_path
370-
io = File.open path, mode
371-
else
372-
io = obj
373-
end
362+
unless Primitive.is_a?(obj, IO) || Primitive.is_a?(obj, String) || obj.respond_to?(:to_path)
363+
return [false, obj]
374364
end
375365

376-
[flag, io]
366+
if io = IO.try_convert(obj)
367+
[true, io]
368+
else
369+
path = Truffle::Type.coerce_to obj, String, :to_path
370+
io = File.open path, mode
371+
[false, io]
372+
end
377373
end
378374

379375
def read_method(obj)

0 commit comments

Comments
 (0)