Added a bunch of documentation
This commit is contained in:
parent
93b7add002
commit
3e1aa6d7e5
31
README
31
README
|
@ -4,29 +4,25 @@ rubyzip is a ruby library for reading and writing zip (pkzip format)
|
|||
files, with the restriction that only uncompressed and deflated zip
|
||||
entries are supported. All this library does is handling of the zip
|
||||
file format. the actual compression/decompression is handled by
|
||||
zlib. zlib is accessible from ruby thanks to ruby/zlib (see below)
|
||||
zlib. zlib is accessible from ruby thanks to ruby/zlib.
|
||||
|
||||
To run the unit tests you need to have rubyunit or test::unit
|
||||
installed.
|
||||
To run the unit tests you need to have test::unit installed.
|
||||
|
||||
= Install
|
||||
|
||||
To install from source run
|
||||
|
||||
ruby install.rb
|
||||
|
||||
If you have Rake installed you can build a rubyzip gem with
|
||||
|
||||
= Prerequisites
|
||||
|
||||
This library requires ruby/zlib version 0.5.0 or newer. ruby/zlib is
|
||||
included in most recent ruby distributions.
|
||||
|
||||
* zlib http://www.gzip.org/zlib/
|
||||
* ruby-zlib: http://www.blue.sky.or.jp/atelier/ruby/
|
||||
rake package
|
||||
|
||||
|
||||
= Documentation
|
||||
|
||||
There is more than one way to access or create a zip archive with
|
||||
rubyzip. The basic API is modelled after the classes in
|
||||
rubyzip. The basic API is modeled after the classes in
|
||||
java.util.zip.* from the Java SDK. This means there are classes such
|
||||
as Zip::ZipInputStream, Zip::ZipOutputStream and
|
||||
Zip::ZipFile. Zip::ZipInputStream provides a basic interface for
|
||||
|
@ -40,9 +36,9 @@ java.util.zip.ZipFile rubyzip's Zip::ZipFile is mutable, which means
|
|||
it can be used to change zip files as well.
|
||||
|
||||
Another way to access a zip archive with rubyzip is to use rubyzip's
|
||||
lib/zip/zipfilesystem.rb API. Using this API files can be read from and written
|
||||
to the archive in much the same manner as ruby's builtin classes
|
||||
allows files to be read from and written to the file system.
|
||||
Zip::ZipFileSystem API. Using this API files can be read from and
|
||||
written to the archive in much the same manner as ruby's builtin
|
||||
classes allows files to be read from and written to the file system.
|
||||
|
||||
The samples/ directory is a good place to start to get a feel for
|
||||
using the library. For details about the specific behaviour of classes
|
||||
|
@ -59,9 +55,12 @@ http://www.ruby-lang.org/en/LICENSE.txt
|
|||
|
||||
http://rubyzip.sourceforge.net
|
||||
|
||||
== Download (tarballs and gems)
|
||||
|
||||
= Author
|
||||
http://sourceforge.net/project/showfiles.php?group_id=43107&package_id=35377
|
||||
|
||||
Thomas Sondergaard (thomas at thomassondergaard.com)
|
||||
= Authors
|
||||
|
||||
Thomas Sondergaard (thomas at sondergaard.cc)
|
||||
|
||||
extra-field support contributed by Tatsuki Sugiura (sugi at nemui.org)
|
||||
|
|
2
Rakefile
2
Rakefile
|
@ -60,7 +60,7 @@ end
|
|||
|
||||
Rake::RDocTask.new do |rd|
|
||||
rd.main = "README"
|
||||
rd.rdoc_files.add %W{ README NEWS TODO lib/** }
|
||||
rd.rdoc_files.add %W{ lib/zip/*.rb README NEWS TODO }
|
||||
rd.options << "--title 'rubyzip documentation' --webcvs http://cvs.sourceforge.net/viewcvs.py/rubyzip/rubyzip/"
|
||||
# rd.options << "--all"
|
||||
end
|
||||
|
|
5
TODO
5
TODO
|
@ -1,9 +1,4 @@
|
|||
|
||||
* Add an extensively documented sample in samples/ that shows most of
|
||||
what rubyzip does
|
||||
* Add doc target to Rakefile that builds rdoc documentation and which
|
||||
turns the samples in the sample directory into html which is included
|
||||
in the output site
|
||||
* Add web target to Rakefile to update rubyzip.sourceforge.net website
|
||||
* Add upload target which uploads dist to sourceforge and gem to where-ever
|
||||
* Release 0.5.7
|
||||
|
|
|
@ -24,7 +24,7 @@ unless Object.method_defined?(:object_id)
|
|||
end
|
||||
|
||||
unless File.respond_to?(:read)
|
||||
class File
|
||||
class File # :nodoc:all
|
||||
# singleton method read does not exist in 1.6.x
|
||||
def self.read(fileName)
|
||||
open(fileName) { |f| f.read }
|
||||
|
|
107
lib/zip/zip.rb
107
lib/zip/zip.rb
|
@ -735,7 +735,7 @@ module Zip
|
|||
end
|
||||
|
||||
|
||||
class ZipCentralDirectory #:nodoc:all
|
||||
class ZipCentralDirectory
|
||||
include Enumerable
|
||||
|
||||
END_OF_CENTRAL_DIRECTORY_SIGNATURE = 0x06054b50
|
||||
|
@ -744,23 +744,24 @@ module Zip
|
|||
|
||||
attr_reader :comment
|
||||
|
||||
# Returns an Enumerable containing the entries.
|
||||
def entries
|
||||
@entrySet.entries
|
||||
end
|
||||
|
||||
def initialize(entries = ZipEntrySet.new, comment = "")
|
||||
def initialize(entries = ZipEntrySet.new, comment = "") #:nodoc:
|
||||
super()
|
||||
@entrySet = entries.kind_of?(ZipEntrySet) ? entries : ZipEntrySet.new(entries)
|
||||
@comment = comment
|
||||
end
|
||||
|
||||
def write_to_stream(io)
|
||||
def write_to_stream(io) #:nodoc:
|
||||
offset = io.tell
|
||||
@entrySet.each { |entry| entry.write_c_dir_entry(io) }
|
||||
write_e_o_c_d(io, offset)
|
||||
end
|
||||
|
||||
def write_e_o_c_d(io, offset)
|
||||
def write_e_o_c_d(io, offset) #:nodoc:
|
||||
io <<
|
||||
[END_OF_CENTRAL_DIRECTORY_SIGNATURE,
|
||||
0 , # @numberOfThisDisk
|
||||
|
@ -774,13 +775,13 @@ module Zip
|
|||
end
|
||||
private :write_e_o_c_d
|
||||
|
||||
def cdir_size
|
||||
def cdir_size #:nodoc:
|
||||
# does not include eocd
|
||||
@entrySet.inject(0) { |value, entry| entry.cdir_header_size + value }
|
||||
end
|
||||
private :cdir_size
|
||||
|
||||
def read_e_o_c_d(io)
|
||||
def read_e_o_c_d(io) #:nodoc:
|
||||
buf = get_e_o_c_d(io)
|
||||
@numberOfThisDisk = ZipEntry::read_zip_short(buf)
|
||||
@numberOfDiskWithStartOfCDir = ZipEntry::read_zip_short(buf)
|
||||
|
@ -793,7 +794,7 @@ module Zip
|
|||
raise ZipError, "Zip consistency problem while reading eocd structure" unless buf.size == 0
|
||||
end
|
||||
|
||||
def read_central_directory_entries(io)
|
||||
def read_central_directory_entries(io) #:nodoc:
|
||||
begin
|
||||
io.seek(@cdirOffset, IO::SEEK_SET)
|
||||
rescue Errno::EINVAL
|
||||
|
@ -805,12 +806,12 @@ module Zip
|
|||
}
|
||||
end
|
||||
|
||||
def read_from_stream(io)
|
||||
def read_from_stream(io) #:nodoc:
|
||||
read_e_o_c_d(io)
|
||||
read_central_directory_entries(io)
|
||||
end
|
||||
|
||||
def get_e_o_c_d(io)
|
||||
def get_e_o_c_d(io) #:nodoc:
|
||||
begin
|
||||
io.seek(-MAX_END_OF_CENTRAL_DIRECTORY_STRUCTURE_SIZE, IO::SEEK_END)
|
||||
rescue Errno::EINVAL
|
||||
|
@ -828,15 +829,18 @@ module Zip
|
|||
return buf
|
||||
end
|
||||
|
||||
# For iterating over the entries.
|
||||
def each(&proc)
|
||||
@entrySet.each(&proc)
|
||||
end
|
||||
|
||||
# Returns the number of entries in the central directory (and
|
||||
# consequently in the zip archive).
|
||||
def size
|
||||
@entrySet.size
|
||||
end
|
||||
|
||||
def ZipCentralDirectory.read_from_stream(io)
|
||||
def ZipCentralDirectory.read_from_stream(io) #:nodoc:
|
||||
cdir = new
|
||||
cdir.read_from_stream(io)
|
||||
return cdir
|
||||
|
@ -844,7 +848,7 @@ module Zip
|
|||
return nil
|
||||
end
|
||||
|
||||
def == (other)
|
||||
def == (other) #:nodoc:
|
||||
return false unless other.kind_of?(ZipCentralDirectory)
|
||||
@entrySet.entries.sort == other.entries.sort && comment == other.comment
|
||||
end
|
||||
|
@ -858,19 +862,64 @@ module Zip
|
|||
class ZipCompressionMethodError < ZipError; end
|
||||
class ZipEntryNameError < ZipError; end
|
||||
|
||||
# ZipFile is modeled after java.util.zip.ZipFile from the Java SDK.
|
||||
# The most important methods are those inherited from
|
||||
# ZipCentralDirectory for accessing information about the entries in
|
||||
# the archive and methods such as get_input_stream and
|
||||
# get_output_stream for reading from and writing entries to the
|
||||
# archive. The class includes a few convenience methods such as
|
||||
# #extract for extracting entries to the filesystem, and #remove,
|
||||
# #replace, #rename and #mkdir for making simple modifications to
|
||||
# the archive.
|
||||
#
|
||||
# Modifications to a zip archive are not committed until #commit or
|
||||
# #close is called. The method #open accepts a block following
|
||||
# the pattern from File.open offering a simple way to
|
||||
# automatically close the archive when the block returns.
|
||||
#
|
||||
# The following example opens zip archive <code>my.zip</code>
|
||||
# (creating it if it doesn't exist) and adds an entry
|
||||
# <code>first.txt</code> and a directory entry <code>a_dir</code>
|
||||
# to it.
|
||||
#
|
||||
# require 'zip/zip'
|
||||
#
|
||||
# Zip::ZipFile.open("my.zip", Zip::ZipFile::CREATE) {
|
||||
# |zipfile|
|
||||
# zipfile.get_output_stream("first.txt") { |f| f.puts "Hello from ZipFile" }
|
||||
# zipfile.mkdir("a_dir")
|
||||
# }
|
||||
#
|
||||
# The next example reopens <code>my.zip</code> writes the contents of
|
||||
# <code>first.txt</code> to standard out and deletes the entry from
|
||||
# the archive.
|
||||
#
|
||||
# require 'zip/zip'
|
||||
#
|
||||
# Zip::ZipFile.open("my.zip", Zip::ZipFile::CREATE) {
|
||||
# |zipfile|
|
||||
# puts zipfile.read("first.txt")
|
||||
# zipfile.remove("first.txt")
|
||||
# }
|
||||
#
|
||||
# ZipFileSystem offers an alternative API that emulates ruby's
|
||||
# interface for accessing the filesystem, ie. the File and Dir classes.
|
||||
|
||||
class ZipFile < ZipCentralDirectory
|
||||
|
||||
CREATE = 1
|
||||
|
||||
attr_reader :name
|
||||
|
||||
# Opens a zip archive. Pass true as the second parameter to create
|
||||
# a new archive if it doesn't exist already.
|
||||
def initialize(fileName, create = nil)
|
||||
super()
|
||||
@name = fileName
|
||||
@comment = ""
|
||||
if (File.exists?(fileName))
|
||||
File.open(name, "rb") { |f| read_from_stream(f) }
|
||||
elsif (create == ZipFile::CREATE)
|
||||
elsif (create)
|
||||
@entrySet = ZipEntrySet.new
|
||||
else
|
||||
raise ZipError, "File #{fileName} not found"
|
||||
|
@ -879,6 +928,9 @@ module Zip
|
|||
@storedEntries = @entrySet.dup
|
||||
end
|
||||
|
||||
# Same as #new. If a block is passed the ZipFile object is passed
|
||||
# to the block and is automatically closed afterwards just as with
|
||||
# ruby's builtin File.open method.
|
||||
def ZipFile.open(fileName, create = nil)
|
||||
zf = ZipFile.new(fileName, create)
|
||||
if block_given?
|
||||
|
@ -892,8 +944,15 @@ module Zip
|
|||
end
|
||||
end
|
||||
|
||||
# Returns the zip files comment, if it has one
|
||||
attr_accessor :comment
|
||||
|
||||
# Iterates over the contents of the ZipFile. This is more efficient
|
||||
# than using a ZipInputStream since this methods simply iterates
|
||||
# through the entries in the central directory structure in the archive
|
||||
# whereas ZipInputStream jumps through the entire archive accessing the
|
||||
# local entry headers (which contain the same information as the
|
||||
# central directory).
|
||||
def ZipFile.foreach(aZipFileName, &block)
|
||||
ZipFile.open(aZipFileName) {
|
||||
|zipFile|
|
||||
|
@ -901,10 +960,16 @@ module Zip
|
|||
}
|
||||
end
|
||||
|
||||
# Returns an input stream to the specified entry. If a block is passed
|
||||
# the stream object is passed to the block and the stream is automatically
|
||||
# closed afterwards just as with ruby's builtin File.open method.
|
||||
def get_input_stream(entry, &aProc)
|
||||
get_entry(entry).get_input_stream(&aProc)
|
||||
end
|
||||
|
||||
# Returns an output stream to the specified entry. If a block is passed
|
||||
# the stream object is passed to the block and the stream is automatically
|
||||
# closed afterwards just as with ruby's builtin File.open method.
|
||||
def get_output_stream(entry, &aProc)
|
||||
newEntry = entry.kind_of?(ZipEntry) ? entry : ZipEntry.new(@name, entry.to_s)
|
||||
if newEntry.directory?
|
||||
|
@ -916,14 +981,17 @@ module Zip
|
|||
zipStreamableEntry.get_output_stream(&aProc)
|
||||
end
|
||||
|
||||
# Returns the name of the zip archive
|
||||
def to_s
|
||||
@name
|
||||
end
|
||||
|
||||
# Returns a string containing the contents of the specified entry
|
||||
def read(entry)
|
||||
get_input_stream(entry) { |is| is.read }
|
||||
end
|
||||
|
||||
# Convenience method for adding the contents of a file to the archive
|
||||
def add(entry, srcPath, &continueOnExistsProc)
|
||||
continueOnExistsProc ||= proc { false }
|
||||
check_entry_exists(entry, continueOnExistsProc, "add")
|
||||
|
@ -935,21 +1003,26 @@ module Zip
|
|||
end
|
||||
end
|
||||
|
||||
# Removes the specified entry.
|
||||
def remove(entry)
|
||||
@entrySet.delete(get_entry(entry))
|
||||
end
|
||||
|
||||
# Renames the specified entry.
|
||||
def rename(entry, newName, &continueOnExistsProc)
|
||||
foundEntry = get_entry(entry)
|
||||
check_entry_exists(newName, continueOnExistsProc, "rename")
|
||||
foundEntry.name=newName
|
||||
end
|
||||
|
||||
# Replaces the specified entry with the contents of srcPath (from
|
||||
# the file system).
|
||||
def replace(entry, srcPath)
|
||||
check_file(srcPath)
|
||||
add(remove(entry), srcPath)
|
||||
end
|
||||
|
||||
# Extracts entry to file destPath.
|
||||
def extract(entry, destPath, &onExistsProc)
|
||||
onExistsProc ||= proc { false }
|
||||
foundEntry = get_entry(entry)
|
||||
|
@ -960,6 +1033,8 @@ module Zip
|
|||
end
|
||||
end
|
||||
|
||||
# Commits changes that has been made since the previous commit to
|
||||
# the zip archive.
|
||||
def commit
|
||||
return if ! commit_required?
|
||||
on_success_replace(name) {
|
||||
|
@ -975,14 +1050,19 @@ module Zip
|
|||
initialize(name)
|
||||
end
|
||||
|
||||
# Closes the zip file committing any changes that has been made.
|
||||
def close
|
||||
commit
|
||||
end
|
||||
|
||||
# Returns true if any changes has been made to this archive since
|
||||
# the previous commit
|
||||
def commit_required?
|
||||
return @entrySet != @storedEntries || @create == ZipFile::CREATE
|
||||
end
|
||||
|
||||
# Searches for entry with the specified name. Returns nil if
|
||||
# no entry is found. See also get_entry
|
||||
def find_entry(entry)
|
||||
@entrySet.detect {
|
||||
|e|
|
||||
|
@ -990,6 +1070,8 @@ module Zip
|
|||
}
|
||||
end
|
||||
|
||||
# Searches for an entry just as find_entry, but throws Errno::ENOENT
|
||||
# if no entry is found.
|
||||
def get_entry(entry)
|
||||
selectedEntry = find_entry(entry)
|
||||
unless selectedEntry
|
||||
|
@ -998,6 +1080,7 @@ module Zip
|
|||
return selectedEntry
|
||||
end
|
||||
|
||||
# Creates a directory
|
||||
def mkdir(entryName, permissionInt = 0) #permissionInt ignored
|
||||
if find_entry(entryName)
|
||||
raise Errno::EEXIST, "File exists - #{entryName}"
|
||||
|
|
|
@ -1,9 +1,42 @@
|
|||
require 'zip/zip'
|
||||
|
||||
module Zip
|
||||
|
||||
# The ZipFileSystem API provides an API for accessing entries in
|
||||
# a zip archive that is similar to ruby's builtin File and Dir
|
||||
# classes.
|
||||
#
|
||||
# Requiring 'zip/zipfilesystem' includes this module in ZipFile
|
||||
# making the methods in this module available on ZipFile objects.
|
||||
#
|
||||
# Using this API the following example creates a new zip file
|
||||
# <code>my.zip</code> containing a normal entry with the name
|
||||
# <code>first.txt</code>, a directory entry named <code>mydir</code>
|
||||
# and finally another normal entry named <code>second.txt</code>
|
||||
#
|
||||
# require 'zip/zipfilesystem'
|
||||
#
|
||||
# Zip::ZipFile.open("my.zip", Zip::ZipFile::CREATE) {
|
||||
# |zipfile|
|
||||
# zipfile.file.open("first.txt", "w") { |f| f.puts "Hello world" }
|
||||
# zipfile.dir.mkdir("mydir")
|
||||
# zipfile.file.open("mydir/second.txt", "w") { |f| f.puts "Hello again" }
|
||||
# }
|
||||
#
|
||||
# Reading is as easy as writing, as the following example shows. The
|
||||
# example writes the contents of <code>first.txt</code> from zip archive
|
||||
# <code>my.zip</code> to standard out.
|
||||
#
|
||||
# require 'zip/zipfilesystem'
|
||||
#
|
||||
# Zip::ZipFile.open("my.zip") {
|
||||
# |zipfile|
|
||||
# puts zipfile.file.read("first.txt")
|
||||
# }
|
||||
|
||||
module ZipFileSystem
|
||||
|
||||
def initialize
|
||||
def initialize # :nodoc:
|
||||
mappedZip = ZipFileNameMapper.new(self)
|
||||
@zipFsDir = ZipFsDir.new(mappedZip)
|
||||
@zipFsFile = ZipFsFile.new(mappedZip)
|
||||
|
@ -11,14 +44,26 @@ module Zip
|
|||
@zipFsFile.dir = @zipFsDir
|
||||
end
|
||||
|
||||
# Returns a ZipFsDir which is much like ruby's builtin Dir (class)
|
||||
# object, except it works on the ZipFile on which this method is
|
||||
# invoked
|
||||
def dir
|
||||
@zipFsDir
|
||||
end
|
||||
|
||||
# Returns a ZipFsFile which is much like ruby's builtin File (class)
|
||||
# object, except it works on the ZipFile on which this method is
|
||||
# invoked
|
||||
def file
|
||||
@zipFsFile
|
||||
end
|
||||
|
||||
# Instances of this class are normally accessed via the accessor
|
||||
# ZipFile::file. An instance of ZipFsFile behaves like ruby's
|
||||
# builtin File (class) object, except it works on ZipFile entries.
|
||||
#
|
||||
# The individual methods are not documented due to their
|
||||
# similarity with the methods in File
|
||||
class ZipFsFile
|
||||
|
||||
attr_writer :dir
|
||||
|
@ -198,7 +243,7 @@ module Zip
|
|||
@mappedZip.get_entry(fileName).size
|
||||
end
|
||||
|
||||
# nil for not found and nil for directories
|
||||
# Returns nil for not found and nil for directories
|
||||
def size?(fileName)
|
||||
entry = @mappedZip.find_entry(fileName)
|
||||
return (entry == nil || entry.directory?) ? nil : entry.size
|
||||
|
@ -367,6 +412,12 @@ module Zip
|
|||
end
|
||||
end
|
||||
|
||||
# Instances of this class are normally accessed via the accessor
|
||||
# ZipFile::dir. An instance of ZipFsDir behaves like ruby's
|
||||
# builtin Dir (class) object, except it works on ZipFile entries.
|
||||
#
|
||||
# The individual methods are not documented due to their
|
||||
# similarity with the methods in Dir
|
||||
class ZipFsDir
|
||||
|
||||
def initialize(mappedZip)
|
||||
|
@ -441,7 +492,7 @@ module Zip
|
|||
|
||||
end
|
||||
|
||||
class ZipFsDirIterator
|
||||
class ZipFsDirIterator # :nodoc:all
|
||||
include Enumerable
|
||||
|
||||
def initialize(arrayOfFileNames)
|
||||
|
@ -481,7 +532,7 @@ module Zip
|
|||
|
||||
# All access to ZipFile from ZipFsFile and ZipFsDir goes through a
|
||||
# ZipFileNameMapper, which has one responsibility: ensure
|
||||
class ZipFileNameMapper
|
||||
class ZipFileNameMapper # :nodoc:all
|
||||
include Enumerable
|
||||
|
||||
def initialize(zipFile)
|
||||
|
|
Loading…
Reference in New Issue