From: Massimiliano Mirra Date: 2002-07-09T22:41:24+09:00 Subject: Re: SV: SV: [ANN] Archive 0.2 On Mon, Jul 08, 2002 at 08:41:41PM +0900, Thomas S�ndergaard wrote: > > Do you think it would be possible to add a set of proxies that adapt > > rubyzip interface to Archive's? After all, the whole Archive thing is > > just a matter of convenience (learn to deal with archives once, apply > > the knowledge on all formats). > > I don't see why not, and I'd even like to do it. Are the interfaces > that rubyzip would have to implement apparent from the archive > module code? If not, do you have some documentation. Here is the skeleton of Archive::(Reader|Writer|Modifier|Entry)::Ar. As you can see, most of the work is done in Entry::Ar. module Archive module Modifier class Ar < Generic # nothing to do here, taken care in Generic end end module Reader class Ar < Generic def initialize(io) # mostly nothing to do here end end end module Writer class Ar < Generic # nothing to do here, taken care in Generic end end module Entry class Ar < Generic def initialize(io) # creates two parts and extracts an # entry from the io stream super(io, :header, :data) parse end def parse @parts[:header] = EntryPart.new(Header) do start = @io.pos raw = @io.read(Header::LEN) [start...@io.pos, raw] end @parts[:data] = EntryPart.new(String) do start = @io.pos raw = @io.read(@parts[:header].parsed.size) [start...@io.pos, raw] end # ... end def update @parts[:header].parsed.size = @parts[:data].raw.length end def to_arc_format # ... update dump = header.parsed.to_arc_format + data.raw return dump end class Header # various constants such as header # length defined here def initialize(header_raw) # takes raw header and parses it # to initialize itself end def to_arc_format # ... end end end end end Basically, you need an Archive::Entry::Zip < Archive::Entry::Generic that, given a io stream passed to initialize, reads and parses an archive entry, and leaves the io cursor at the beginning of the next one. If it can also output itself in Zip format again, you will be able to pass entries to Archive::Writer for writing. Each Entry::XYZ has `parts': a Zip entry will most likely have a `data' and a `header' part. Each part, in turn, has a `raw' and a `parsed' attribute: `raw' points to the raw stuff as read from the stream, `parsed' to a structure modifiable from code. You will probably create an Archive::Entry::Zip::Header object that takes care of receiving the Zip raw header, parse it, and initialize itself. The data part will usually remain unparsed. One nice thing of this design is that a mbox Entry can, for example, implement a to_zip method. Then you could do something like this: in = File.open("/var/mail/joe") out = File.open("/home/joe/mails.zip") mbox = Archive::Reader::Mbox.new(in) zip = Archive::Writer::Zip.new(out) mbox.scan do |entry| zip.add(entry) end The `add' method from Archive::Writer will see that we're trying to write on a zip and that we have a Mbox::Entry#to_zip method, so will use that, and we'll have converted from Mbox to Zip on the fly. (This is not in Archive::Writer::Generic yet, because I have written no to_xyz methods so far.) If you have any questions, just ask. Massimiliano p.s.: Sorry to ask, isn't there some way to have your mail client set correct References: or at least not modify the subject?