From e662a7f7262cef0820c014ae533bdf199f0104d6 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Fri, 13 May 2011 12:59:13 -0700 Subject: [PATCH] copy_stream coerces based on #to_path This is to be compatible with IO.copy_stream and also Rack::File since this may be used in web servers. This is NOT compatible with Ruby 1.8 since File.open doesn't coerce with #to_path on the given object. --- io_splice.gemspec | 1 + lib/io/splice.rb | 11 ++++++++--- test/test_rack_file_compat.rb | 31 +++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 test/test_rack_file_compat.rb diff --git a/io_splice.gemspec b/io_splice.gemspec index c098a63..2046d11 100644 --- a/io_splice.gemspec +++ b/io_splice.gemspec @@ -21,6 +21,7 @@ Gem::Specification.new do |s| s.rubyforge_project = %q{qrp} s.test_files = Dir['test/test_*.rb'] s.add_development_dependency('wrongdoc', '~> 1.5') + s.add_development_dependency('rack', '~> 1.2') # s.licenses = %w(LGPL) # accessor not compatible with older RubyGems end diff --git a/lib/io/splice.rb b/lib/io/splice.rb index 574e681..1ff2f6a 100644 --- a/lib/io/splice.rb +++ b/lib/io/splice.rb @@ -25,6 +25,11 @@ module IO::Splice n end + def self.need_open?(obj) # :nodoc: + return false if obj.respond_to?(:to_io) + obj.respond_to?(:to_path) || obj.kind_of?(String) + end + # copies the contents of the IO object given by +src+ to +dst+ # If +len+ is specified, then only +len+ bytes are copied and # +EOFError+ is raised if fewer than +len+ bytes could be copied. @@ -36,10 +41,10 @@ module IO::Splice # objects with no underlying file descriptor (e.g. StringIO). def self.copy_stream(src, dst, len = nil, src_offset = nil) close = [] - src.kind_of?(String) and close << (src = File.open(src)) - dst.kind_of?(String) and close << (dst = File.open(dst, "w")) - src, dst = src.to_io, dst.to_io + need_open?(src) and close << (src = File.open(src)) + need_open?(dst) and close << (dst = File.open(dst, "w")) rv = len + src, dst = src.to_io, dst.to_io if src.stat.pipe? || dst.stat.pipe? if len diff --git a/test/test_rack_file_compat.rb b/test/test_rack_file_compat.rb new file mode 100644 index 0000000..5505262 --- /dev/null +++ b/test/test_rack_file_compat.rb @@ -0,0 +1,31 @@ +# -*- encoding: binary -*- +require "rack" +require "test/unit" +require "socket" +require "io/splice" + +class TestRackFileCompat < Test::Unit::TestCase + def setup + @app = Rack::File.new(File.dirname(__FILE__)) + @req = Rack::MockRequest.new(@app) + @base_file = File.basename(__FILE__) + @r, @w = UNIXSocket.pair + end + + def teardown + [ @r, @w ].each { |io| io.closed? or io.close } + end + + def test_get_rack_file + env = Rack::MockRequest.env_for "http://example.com/#@base_file" + status, headers, body = @app.call(env) + assert_equal 200, status.to_i + headers.each { |k,v| + assert_instance_of String, k.to_str + assert_instance_of String, v.to_str + } + thr = Thread.new { @r.read(File.size(__FILE__)) } + assert_equal File.size(__FILE__), IO::Splice.copy_stream(body, @w) + assert_equal File.read(__FILE__), thr.value + end +end if IO.respond_to?(:copy_stream) -- 2.11.4.GIT