Skip to content

Commit

Permalink
Implements Zlib::GzipWriter using System.IO.Compression.GZipStream.
Browse files Browse the repository at this point in the history
- GzipWriter.new ignores the level and strategy arguments for now.
- The arguments are not marked with DefaultProtocol as it does not look like you can pass an arbitrary object responding to to_s
- Most of the work was for the Ruby library API. We can change the details of the compression later if we want to.
Removed Zlib::GZipReader.Create overloads which took RubyIO since they would not handle the case of File being monkey-patched. This also allowed some code to be factored out into the base GZipFile class.
Implemented Zlib::GzipFile.wrap and added tests for it
Changed App.config to only include valid paths to the Ruby libs that are included in GIT
  • Loading branch information
unknown committed Mar 9, 2009
1 parent 45599d7 commit 7ca7403
Show file tree
Hide file tree
Showing 12 changed files with 507 additions and 43 deletions.
@@ -0,0 +1 @@
fails:Zlib::GzipWriter.wrap can be called without a block with a non-writable object
Expand Up @@ -85,6 +85,35 @@ def self.example_class_method
class L; end

class M < L; end

class StubWriter
def write s
return s.size if s
0
end
end

class StubWriterWithClose < StubWriter
def close *args
end
end

class StubReader
def initialize s
@s = s
end

def read size=2048
s = @s
@s = nil
s
end
end

class StubReaderWithClose < StubReader
def close *args
end
end
end

class Class
Expand Down
@@ -0,0 +1,5 @@
module GzipReaderSpecs
UncompressedContents = "Ipsum is simply dummy text of the printing and typesetting industry. \nLorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. \nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. \nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."

GzippedContents = "\037\213\b\000\325\374\262I\000\vM\221AN\0031\fE\367\234\302\a@\250,@b\311\262\022H\\\301\223q;Q\023'\212\235\016s{\376\244 \272\213e\373\377\347\237c\265\236)\032Y\3145m4\367\2347r\371v*'\362E\250\266\250\036\365L\2543\371V\305\304G\035u\356\346m{\242\207\217\322$\323qh-l4\211\350X\376\233\201\276c\237\333|\357 Wi0\326 c\370\371\345p\260GZ\027,\263R\327\213\226Uo\000\030\364R.\304t\346\224d\et\200\031T\026\032\347)\311L\3211F\231/h\334\372V%\304\f\305\t\353@=\372 \264\336\256\361\212\r-\270Tq\371\t%\005Q\357-\n0\246\356\304\311\312@K\302\025\307@[\222\004oEc\270\017\343\221\020\000G\335s\0213\250D`n\270!,\254g\231o\316+\234k\251=q\213\266\343\336Rz~{=\030\255\321\227Q6x\260\311~\342\207x\303\323\311\026\0217\nE\375\327\346>\363\312f|\336\251\36782:\020\331o\001\302\220\235\305.^*\325>\245h\313\276o\345\344+c2E\244\365\236\360Q\364\005\221O\204\327@\026R\237\3679\374\221\305\2426p\376=\237~\000\003\357\321!:\002\000\000"
end
@@ -0,0 +1,58 @@
require "zlib"
require File.dirname(__FILE__) + '/../../../spec_helper'
require File.dirname(__FILE__) + '/../../../fixtures/class'
require File.dirname(__FILE__) + '/fixtures/classes'

describe "Zlib::GzipReader.wrap" do
before :each do
@io = ClassSpecs::StubReaderWithClose.new GzipReaderSpecs::GzippedContents
end

it "can be called without a block" do
Zlib::GzipReader.wrap(@io).should be_kind_of(Zlib::GzipReader)
end

it "raises NoMethodError if argument does not have a write method" do
lambda { Zlib::GzipReader.wrap(nil) { } }.should raise_error(NoMethodError)
lambda { Zlib::GzipReader.wrap(mock("dummy")) { } }.should raise_error(NoMethodError)
end

it "invokes the block with an instance of GzipReader" do
Zlib::GzipReader.wrap(@io) do |gz|
ScratchPad.record gz
end
ScratchPad.recorded.should be_kind_of(Zlib::GzipReader)
end

it "returns the instance of GzipReader" do
ret = Zlib::GzipReader.wrap(@io) do |gz|
ScratchPad.record gz
end
ret.should equal(ScratchPad.recorded)
end

it "allows the GzipReader instance to be closed in the block" do
ScratchPad.clear
ret = Zlib::GzipReader.wrap(@io) do |gz|
gz.close
ScratchPad.record :after_close
end
ScratchPad.recorded.should == :after_close
end

it "calls io#close once for a trivial block" do
@io.should_receive(:close)
Zlib::GzipReader.wrap(@io) { }
end

it "allows IO objects without a close method" do
io = mock("io")
io.should_receive(:read).any_number_of_times.and_return(GzipReaderSpecs::GzippedContents, nil)
Zlib::GzipReader.wrap(io) { |gz| gz.read }
end

it "propagates Exceptions thrown from the block after calling io#close" do
@io.should_receive(:close)
lambda { Zlib::GzipReader.wrap(@io) { raise "error from block" } }.should raise_error(RuntimeError, "error from block")
end
end
@@ -0,0 +1,66 @@
require "zlib"
require File.dirname(__FILE__) + '/../../../spec_helper'
require File.dirname(__FILE__) + '/../../../fixtures/class'

describe "Zlib::GzipWriter.wrap" do
before :each do
@io = ClassSpecs::StubWriterWithClose.new
end

it "can be called without a block" do
@io.should_not_receive :write
@io.should_not_receive :close
Zlib::GzipWriter.wrap(@io).should be_kind_of(Zlib::GzipWriter)
end

ruby_bug "Causes segmentation fault", "1.8" do
it "can be called without a block with a non-writable object" do
Zlib::GzipWriter.wrap(nil).should be_kind_of(Zlib::GzipWriter)
end
end

it "raises NoMethodError if argument does not have a write method" do
lambda { Zlib::GzipWriter.wrap(mock("dummy")) { } }.should raise_error(NoMethodError)
end

it "invokes the block with an instance of GzipWriter" do
Zlib::GzipWriter.wrap(@io) do |gz|
ScratchPad.record gz
end
ScratchPad.recorded.should be_kind_of(Zlib::GzipWriter)
end

it "returns the instance of GzipWriter" do
ret = Zlib::GzipWriter.wrap(@io) do |gz|
ScratchPad.record gz
end
ret.should equal(ScratchPad.recorded)
end

it "allows the GzipWriter instance to be closed in the block" do
ScratchPad.clear
@io.should_receive :close
Zlib::GzipWriter.wrap(@io) do |gz|
gz.close
ScratchPad.record :after_gzipwriter_close
end
ScratchPad.recorded.should == :after_gzipwriter_close
end

it "calls io#close once for a trivial block" do
ScratchPad.record []
@io.should_receive :close
Zlib::GzipWriter.wrap(@io) { }
end

it "allows IO objects without a close method" do
io = ClassSpecs::StubWriter.new
io.should_receive(:write).any_number_of_times
Zlib::GzipWriter.wrap(io) { |gz| gz << "Hello" }
end

it "propagates Exceptions thrown from the block after calling close" do
@io.should_receive :close
lambda { Zlib::GzipWriter.wrap(@io) { raise "error from block" } }.should raise_error(RuntimeError, "error from block")
end
end
Expand Up @@ -10,6 +10,14 @@
@io = StringIO.new
end

it "writes some compressed data that can be uncompressed" do
Zlib::GzipWriter.wrap @io do |gzio|
gzio.write @data
end

Zlib::GzipReader.new(StringIO.new(@io.string, "r")).read().should == @data
end

it "writes some compressed data" do
Zlib::GzipWriter.wrap @io do |gzio|
gzio.write @data
Expand Down
2 changes: 1 addition & 1 deletion Merlin/Main/Config/Unsigned/App.config
Expand Up @@ -12,7 +12,7 @@
</languages>

<options>
<set language="Ruby" option="LibraryPaths" value="..\..\Languages\Ruby\libs\;..\..\..\External\Languages\Ruby\ruby-1.8.6\lib\ruby\site_ruby\1.8\;..\..\..\External\Languages\Ruby\ruby-1.8.6\lib\ruby\site_ruby\;..\..\..\External\Languages\Ruby\ruby-1.8.6\lib\ruby\1.8\" />
<set language="Ruby" option="LibraryPaths" value="..\..\Languages\Ruby\libs\;..\..\..\External\Languages\Ruby\redist-libs\ruby\site_ruby\1.8\;..\..\..\External\Languages\Ruby\redist-libs\ruby\1.8\" />
</options>
</microsoft.scripting>
</configuration>
Expand Up @@ -982,7 +982,7 @@ public class RubyIOOps {
public static IOWrapper/*!*/ CreateIOWrapper(RespondToStorage/*!*/ respondToStorage,
RubyContext/*!*/ context, object io, FileAccess access) {

bool canRead, canWrite, canSeek;
bool canRead, canWrite, canSeek, canBeClosed;

if (access == FileAccess.Read || access == FileAccess.ReadWrite) {
canRead = Protocols.RespondTo(respondToStorage, context, io, "read");
Expand All @@ -997,8 +997,9 @@ public class RubyIOOps {
}

canSeek = Protocols.RespondTo(respondToStorage, context, io, "seek") && Protocols.RespondTo(respondToStorage, context, io, "tell");
canBeClosed = Protocols.RespondTo(respondToStorage, context, io, "close");

return new IOWrapper(context, io, canRead, canWrite, canSeek);
return new IOWrapper(context, io, canRead, canWrite, canSeek, canBeClosed);
}
}
}

0 comments on commit 7ca7403

Please sign in to comment.