Upgrade Vendored rubyzip to Version 0.9.3

This commit is contained in:
Jacques Distler 2009-12-23 02:19:16 -06:00
parent 7c51accaab
commit 1d32d45944
34 changed files with 247 additions and 36 deletions

165
vendor/plugins/rubyzip/lib/zip/ioextras.rb vendored Executable file
View file

@ -0,0 +1,165 @@
module IOExtras #:nodoc:
CHUNK_SIZE = 131072
RANGE_ALL = 0..-1
def self.copy_stream(ostream, istream)
s = ''
ostream.write(istream.read(CHUNK_SIZE, s)) until istream.eof?
end
def self.copy_stream_n(ostream, istream, nbytes)
s = ''
toread = nbytes
while (toread > 0 && ! istream.eof?)
tr = toread > CHUNK_SIZE ? CHUNK_SIZE : toread
ostream.write(istream.read(tr, s))
toread -= tr
end
end
# Implements kind_of? in order to pretend to be an IO object
module FakeIO
def kind_of?(object)
object == IO || super
end
end
# Implements many of the convenience methods of IO
# such as gets, getc, readline and readlines
# depends on: input_finished?, produce_input and read
module AbstractInputStream
include Enumerable
include FakeIO
def initialize
super
@lineno = 0
@outputBuffer = ""
end
attr_accessor :lineno
def read(numberOfBytes = nil, buf = nil)
tbuf = nil
if @outputBuffer.length > 0
if numberOfBytes <= @outputBuffer.length
tbuf = @outputBuffer.slice!(0, numberOfBytes)
else
numberOfBytes -= @outputBuffer.length if (numberOfBytes)
rbuf = sysread(numberOfBytes, buf)
tbuf = @outputBuffer
tbuf << rbuf if (rbuf)
@outputBuffer = ""
end
else
tbuf = sysread(numberOfBytes, buf)
end
return nil unless (tbuf)
if buf
buf.replace(tbuf)
else
buf = tbuf
end
buf
end
def readlines(aSepString = $/)
retVal = []
each_line(aSepString) { |line| retVal << line }
return retVal
end
def gets(aSepString=$/)
@lineno = @lineno.next
return read if aSepString == nil
aSepString="#{$/}#{$/}" if aSepString == ""
bufferIndex=0
while ((matchIndex = @outputBuffer.index(aSepString, bufferIndex)) == nil)
bufferIndex=@outputBuffer.length
if input_finished?
return @outputBuffer.empty? ? nil : flush
end
@outputBuffer << produce_input
end
sepIndex=matchIndex + aSepString.length
return @outputBuffer.slice!(0...sepIndex)
end
def flush
retVal=@outputBuffer
@outputBuffer=""
return retVal
end
def readline(aSepString = $/)
retVal = gets(aSepString)
raise EOFError if retVal == nil
return retVal
end
def each_line(aSepString = $/)
while true
yield readline(aSepString)
end
rescue EOFError
end
alias_method :each, :each_line
end
# Implements many of the output convenience methods of IO.
# relies on <<
module AbstractOutputStream
include FakeIO
def write(data)
self << data
data.to_s.length
end
def print(*params)
self << params.to_s << $\.to_s
end
def printf(aFormatString, *params)
self << sprintf(aFormatString, *params)
end
def putc(anObject)
self << case anObject
when Fixnum then anObject.chr
when String then anObject
else raise TypeError, "putc: Only Fixnum and String supported"
end
anObject
end
def puts(*params)
params << "\n" if params.empty?
params.flatten.each {
|element|
val = element.to_s
self << val
self << "\n" unless val[-1,1] == "\n"
}
end
end
end # IOExtras namespace module
# Copyright (C) 2002-2004 Thomas Sondergaard
# rubyzip is free software; you can redistribute it and/or
# modify it under the terms of the ruby license.

111
vendor/plugins/rubyzip/lib/zip/stdrubyext.rb vendored Executable file
View file

@ -0,0 +1,111 @@
unless Enumerable.method_defined?(:inject)
module Enumerable #:nodoc:all
def inject(n = 0)
each { |value| n = yield(n, value) }
n
end
end
end
module Enumerable #:nodoc:all
# returns a new array of all the return values not equal to nil
# This implementation could be faster
def select_map(&aProc)
map(&aProc).reject { |e| e.nil? }
end
end
unless Object.method_defined?(:object_id)
class Object #:nodoc:all
# Using object_id which is the new thing, so we need
# to make that work in versions prior to 1.8.0
alias object_id id
end
end
unless File.respond_to?(:read)
class File # :nodoc:all
# singleton method read does not exist in 1.6.x
def self.read(fileName)
open(fileName) { |f| f.read }
end
end
end
class String #:nodoc:all
def starts_with(aString)
rindex(aString, 0) == 0
end
def ends_with(aString)
index(aString, -aString.size)
end
def ensure_end(aString)
ends_with(aString) ? self : self + aString
end
def lchop
slice(1, length)
end
end
class Time #:nodoc:all
#MS-DOS File Date and Time format as used in Interrupt 21H Function 57H:
#
# Register CX, the Time:
# Bits 0-4 2 second increments (0-29)
# Bits 5-10 minutes (0-59)
# bits 11-15 hours (0-24)
#
# Register DX, the Date:
# Bits 0-4 day (1-31)
# bits 5-8 month (1-12)
# bits 9-15 year (four digit year minus 1980)
def to_binary_dos_time
(sec/2) +
(min << 5) +
(hour << 11)
end
def to_binary_dos_date
(day) +
(month << 5) +
((year - 1980) << 9)
end
# Dos time is only stored with two seconds accuracy
def dos_equals(other)
to_i/2 == other.to_i/2
end
def self.parse_binary_dos_format(binaryDosDate, binaryDosTime)
second = 2 * ( 0b11111 & binaryDosTime)
minute = ( 0b11111100000 & binaryDosTime) >> 5
hour = (0b1111100000000000 & binaryDosTime) >> 11
day = ( 0b11111 & binaryDosDate)
month = ( 0b111100000 & binaryDosDate) >> 5
year = ((0b1111111000000000 & binaryDosDate) >> 9) + 1980
begin
return Time.local(year, month, day, hour, minute, second)
end
end
end
class Module #:nodoc:all
def forward_message(forwarder, *messagesToForward)
methodDefs = messagesToForward.map {
|msg|
"def #{msg}; #{forwarder}(:#{msg}); end"
}
module_eval(methodDefs.join("\n"))
end
end
# Copyright (C) 2002, 2003 Thomas Sondergaard
# rubyzip is free software; you can redistribute it and/or
# modify it under the terms of the ruby license.

View file

@ -0,0 +1,195 @@
#
# tempfile - manipulates temporary files
#
# $Id: tempfile_bugfixed.rb,v 1.2 2005/02/19 20:30:33 thomas Exp $
#
require 'delegate'
require 'tmpdir'
module BugFix #:nodoc:all
# A class for managing temporary files. This library is written to be
# thread safe.
class Tempfile < DelegateClass(File)
MAX_TRY = 10
@@cleanlist = []
# Creates a temporary file of mode 0600 in the temporary directory
# whose name is basename.pid.n and opens with mode "w+". A Tempfile
# object works just like a File object.
#
# If tmpdir is omitted, the temporary directory is determined by
# Dir::tmpdir provided by 'tmpdir.rb'.
# When $SAFE > 0 and the given tmpdir is tainted, it uses
# /tmp. (Note that ENV values are tainted by default)
def initialize(basename, tmpdir=Dir::tmpdir)
if $SAFE > 0 and tmpdir.tainted?
tmpdir = '/tmp'
end
lock = nil
n = failure = 0
begin
Thread.critical = true
begin
tmpname = sprintf('%s/%s%d.%d', tmpdir, basename, $$, n)
lock = tmpname + '.lock'
n += 1
end while @@cleanlist.include?(tmpname) or
File.exist?(lock) or File.exist?(tmpname)
Dir.mkdir(lock)
rescue
failure += 1
retry if failure < MAX_TRY
raise "cannot generate tempfile `%s'" % tmpname
ensure
Thread.critical = false
end
@data = [tmpname]
@clean_proc = Tempfile.callback(@data)
ObjectSpace.define_finalizer(self, @clean_proc)
@tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
@tmpname = tmpname
@@cleanlist << @tmpname
@data[1] = @tmpfile
@data[2] = @@cleanlist
super(@tmpfile)
# Now we have all the File/IO methods defined, you must not
# carelessly put bare puts(), etc. after this.
Dir.rmdir(lock)
end
# Opens or reopens the file with mode "r+".
def open
@tmpfile.close if @tmpfile
@tmpfile = File.open(@tmpname, 'r+')
@data[1] = @tmpfile
__setobj__(@tmpfile)
end
def _close # :nodoc:
@tmpfile.close if @tmpfile
@data[1] = @tmpfile = nil
end
protected :_close
# Closes the file. If the optional flag is true, unlinks the file
# after closing.
#
# If you don't explicitly unlink the temporary file, the removal
# will be delayed until the object is finalized.
def close(unlink_now=false)
if unlink_now
close!
else
_close
end
end
# Closes and unlinks the file.
def close!
_close
@clean_proc.call
ObjectSpace.undefine_finalizer(self)
end
# Unlinks the file. On UNIX-like systems, it is often a good idea
# to unlink a temporary file immediately after creating and opening
# it, because it leaves other programs zero chance to access the
# file.
def unlink
# keep this order for thread safeness
File.unlink(@tmpname) if File.exist?(@tmpname)
@@cleanlist.delete(@tmpname) if @@cleanlist
end
alias delete unlink
if RUBY_VERSION > '1.8.0'
def __setobj__(obj)
@_dc_obj = obj
end
else
def __setobj__(obj)
@obj = obj
end
end
# Returns the full path name of the temporary file.
def path
@tmpname
end
# Returns the size of the temporary file. As a side effect, the IO
# buffer is flushed before determining the size.
def size
if @tmpfile
@tmpfile.flush
@tmpfile.stat.size
else
0
end
end
alias length size
class << self
def callback(data) # :nodoc:
pid = $$
lambda{
if pid == $$
path, tmpfile, cleanlist = *data
print "removing ", path, "..." if $DEBUG
tmpfile.close if tmpfile
# keep this order for thread safeness
File.unlink(path) if File.exist?(path)
cleanlist.delete(path) if cleanlist
print "done\n" if $DEBUG
end
}
end
# If no block is given, this is a synonym for new().
#
# If a block is given, it will be passed tempfile as an argument,
# and the tempfile will automatically be closed when the block
# terminates. In this case, open() returns nil.
def open(*args)
tempfile = new(*args)
if block_given?
begin
yield(tempfile)
ensure
tempfile.close
end
nil
else
tempfile
end
end
end
end
end # module BugFix
if __FILE__ == $0
# $DEBUG = true
f = Tempfile.new("foo")
f.print("foo\n")
f.close
f.open
p f.gets # => "foo\n"
f.close!
end

1870
vendor/plugins/rubyzip/lib/zip/zip.rb vendored Executable file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,610 @@
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 # :nodoc:
mappedZip = ZipFileNameMapper.new(self)
@zipFsDir = ZipFsDir.new(mappedZip)
@zipFsFile = ZipFsFile.new(mappedZip)
@zipFsDir.file = @zipFsFile
@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
# protected :dir
class ZipFsStat
def initialize(zipFsFile, entryName)
@zipFsFile = zipFsFile
@entryName = entryName
end
def forward_invoke(msg)
@zipFsFile.send(msg, @entryName)
end
def kind_of?(t)
super || t == ::File::Stat
end
forward_message :forward_invoke, :file?, :directory?, :pipe?, :chardev?
forward_message :forward_invoke, :symlink?, :socket?, :blockdev?
forward_message :forward_invoke, :readable?, :readable_real?
forward_message :forward_invoke, :writable?, :writable_real?
forward_message :forward_invoke, :executable?, :executable_real?
forward_message :forward_invoke, :sticky?, :owned?, :grpowned?
forward_message :forward_invoke, :setuid?, :setgid?
forward_message :forward_invoke, :zero?
forward_message :forward_invoke, :size, :size?
forward_message :forward_invoke, :mtime, :atime, :ctime
def blocks; nil; end
def get_entry
@zipFsFile.__send__(:get_entry, @entryName)
end
private :get_entry
def gid
e = get_entry
if e.extra.member? "IUnix"
e.extra["IUnix"].gid || 0
else
0
end
end
def uid
e = get_entry
if e.extra.member? "IUnix"
e.extra["IUnix"].uid || 0
else
0
end
end
def ino; 0; end
def dev; 0; end
def rdev; 0; end
def rdev_major; 0; end
def rdev_minor; 0; end
def ftype
if file?
return "file"
elsif directory?
return "directory"
else
raise StandardError, "Unknown file type"
end
end
def nlink; 1; end
def blksize; nil; end
def mode
e = get_entry
if e.fstype == 3
e.externalFileAttributes >> 16
else
33206 # 33206 is equivalent to -rw-rw-rw-
end
end
end
def initialize(mappedZip)
@mappedZip = mappedZip
end
def get_entry(fileName)
if ! exists?(fileName)
raise Errno::ENOENT, "No such file or directory - #{fileName}"
end
@mappedZip.find_entry(fileName)
end
private :get_entry
def unix_mode_cmp(fileName, mode)
begin
e = get_entry(fileName)
e.fstype == 3 && ((e.externalFileAttributes >> 16) & mode ) != 0
rescue Errno::ENOENT
false
end
end
private :unix_mode_cmp
def exists?(fileName)
expand_path(fileName) == "/" || @mappedZip.find_entry(fileName) != nil
end
alias :exist? :exists?
# Permissions not implemented, so if the file exists it is accessible
alias owned? exists?
alias grpowned? exists?
def readable?(fileName)
unix_mode_cmp(fileName, 0444)
end
alias readable_real? readable?
def writable?(fileName)
unix_mode_cmp(fileName, 0222)
end
alias writable_real? writable?
def executable?(fileName)
unix_mode_cmp(fileName, 0111)
end
alias executable_real? executable?
def setuid?(fileName)
unix_mode_cmp(fileName, 04000)
end
def setgid?(fileName)
unix_mode_cmp(fileName, 02000)
end
def sticky?(fileName)
unix_mode_cmp(fileName, 01000)
end
def umask(*args)
::File.umask(*args)
end
def truncate(fileName, len)
raise StandardError, "truncate not supported"
end
def directory?(fileName)
entry = @mappedZip.find_entry(fileName)
expand_path(fileName) == "/" || (entry != nil && entry.directory?)
end
def open(fileName, openMode = "r", &block)
openMode.gsub!("b", "") # ignore b option
case openMode
when "r"
@mappedZip.get_input_stream(fileName, &block)
when "w"
@mappedZip.get_output_stream(fileName, &block)
else
raise StandardError, "openmode '#{openMode} not supported" unless openMode == "r"
end
end
def new(fileName, openMode = "r")
open(fileName, openMode)
end
def size(fileName)
@mappedZip.get_entry(fileName).size
end
# 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
end
def chown(ownerInt, groupInt, *filenames)
filenames.each { |fileName|
e = get_entry(fileName)
unless e.extra.member?("IUnix")
e.extra.create("IUnix")
end
e.extra["IUnix"].uid = ownerInt
e.extra["IUnix"].gid = groupInt
}
filenames.size
end
def chmod (modeInt, *filenames)
filenames.each { |fileName|
e = get_entry(fileName)
e.fstype = 3 # force convertion filesystem type to unix
e.externalFileAttributes = modeInt << 16
}
filenames.size
end
def zero?(fileName)
sz = size(fileName)
sz == nil || sz == 0
rescue Errno::ENOENT
false
end
def file?(fileName)
entry = @mappedZip.find_entry(fileName)
entry != nil && entry.file?
end
def dirname(fileName)
::File.dirname(fileName)
end
def basename(fileName)
::File.basename(fileName)
end
def split(fileName)
::File.split(fileName)
end
def join(*fragments)
::File.join(*fragments)
end
def utime(modifiedTime, *fileNames)
fileNames.each { |fileName|
get_entry(fileName).time = modifiedTime
}
end
def mtime(fileName)
@mappedZip.get_entry(fileName).mtime
end
def atime(fileName)
e = get_entry(fileName)
if e.extra.member? "UniversalTime"
e.extra["UniversalTime"].atime
else
nil
end
end
def ctime(fileName)
e = get_entry(fileName)
if e.extra.member? "UniversalTime"
e.extra["UniversalTime"].ctime
else
nil
end
end
def pipe?(filename)
false
end
def blockdev?(filename)
false
end
def chardev?(filename)
false
end
def symlink?(fileName)
false
end
def socket?(fileName)
false
end
def ftype(fileName)
@mappedZip.get_entry(fileName).directory? ? "directory" : "file"
end
def readlink(fileName)
raise NotImplementedError, "The readlink() function is not implemented"
end
def symlink(fileName, symlinkName)
raise NotImplementedError, "The symlink() function is not implemented"
end
def link(fileName, symlinkName)
raise NotImplementedError, "The link() function is not implemented"
end
def pipe
raise NotImplementedError, "The pipe() function is not implemented"
end
def stat(fileName)
if ! exists?(fileName)
raise Errno::ENOENT, fileName
end
ZipFsStat.new(self, fileName)
end
alias lstat stat
def readlines(fileName)
open(fileName) { |is| is.readlines }
end
def read(fileName)
@mappedZip.read(fileName)
end
def popen(*args, &aProc)
File.popen(*args, &aProc)
end
def foreach(fileName, aSep = $/, &aProc)
open(fileName) { |is| is.each_line(aSep, &aProc) }
end
def delete(*args)
args.each {
|fileName|
if directory?(fileName)
raise Errno::EISDIR, "Is a directory - \"#{fileName}\""
end
@mappedZip.remove(fileName)
}
end
def rename(fileToRename, newName)
@mappedZip.rename(fileToRename, newName) { true }
end
alias :unlink :delete
def expand_path(aPath)
@mappedZip.expand_path(aPath)
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)
@mappedZip = mappedZip
end
attr_writer :file
def new(aDirectoryName)
ZipFsDirIterator.new(entries(aDirectoryName))
end
def open(aDirectoryName)
dirIt = new(aDirectoryName)
if block_given?
begin
yield(dirIt)
return nil
ensure
dirIt.close
end
end
dirIt
end
def pwd; @mappedZip.pwd; end
alias getwd pwd
def chdir(aDirectoryName)
unless @file.stat(aDirectoryName).directory?
raise Errno::EINVAL, "Invalid argument - #{aDirectoryName}"
end
@mappedZip.pwd = @file.expand_path(aDirectoryName)
end
def entries(aDirectoryName)
entries = []
foreach(aDirectoryName) { |e| entries << e }
entries
end
def foreach(aDirectoryName)
unless @file.stat(aDirectoryName).directory?
raise Errno::ENOTDIR, aDirectoryName
end
path = @file.expand_path(aDirectoryName).ensure_end("/")
subDirEntriesRegex = Regexp.new("^#{path}([^/]+)$")
@mappedZip.each {
|fileName|
match = subDirEntriesRegex.match(fileName)
yield(match[1]) unless match == nil
}
end
def delete(entryName)
unless @file.stat(entryName).directory?
raise Errno::EINVAL, "Invalid argument - #{entryName}"
end
@mappedZip.remove(entryName)
end
alias rmdir delete
alias unlink delete
def mkdir(entryName, permissionInt = 0755)
@mappedZip.mkdir(entryName, permissionInt)
end
def chroot(*args)
raise NotImplementedError, "The chroot() function is not implemented"
end
end
class ZipFsDirIterator # :nodoc:all
include Enumerable
def initialize(arrayOfFileNames)
@fileNames = arrayOfFileNames
@index = 0
end
def close
@fileNames = nil
end
def each(&aProc)
raise IOError, "closed directory" if @fileNames == nil
@fileNames.each(&aProc)
end
def read
raise IOError, "closed directory" if @fileNames == nil
@fileNames[(@index+=1)-1]
end
def rewind
raise IOError, "closed directory" if @fileNames == nil
@index = 0
end
def seek(anIntegerPosition)
raise IOError, "closed directory" if @fileNames == nil
@index = anIntegerPosition
end
def tell
raise IOError, "closed directory" if @fileNames == nil
@index
end
end
# All access to ZipFile from ZipFsFile and ZipFsDir goes through a
# ZipFileNameMapper, which has one responsibility: ensure
class ZipFileNameMapper # :nodoc:all
include Enumerable
def initialize(zipFile)
@zipFile = zipFile
@pwd = "/"
end
attr_accessor :pwd
def find_entry(fileName)
@zipFile.find_entry(expand_to_entry(fileName))
end
def get_entry(fileName)
@zipFile.get_entry(expand_to_entry(fileName))
end
def get_input_stream(fileName, &aProc)
@zipFile.get_input_stream(expand_to_entry(fileName), &aProc)
end
def get_output_stream(fileName, &aProc)
@zipFile.get_output_stream(expand_to_entry(fileName), &aProc)
end
def read(fileName)
@zipFile.read(expand_to_entry(fileName))
end
def remove(fileName)
@zipFile.remove(expand_to_entry(fileName))
end
def rename(fileName, newName, &continueOnExistsProc)
@zipFile.rename(expand_to_entry(fileName), expand_to_entry(newName),
&continueOnExistsProc)
end
def mkdir(fileName, permissionInt = 0755)
@zipFile.mkdir(expand_to_entry(fileName), permissionInt)
end
# Turns entries into strings and adds leading /
# and removes trailing slash on directories
def each
@zipFile.each {
|e|
yield("/"+e.to_s.chomp("/"))
}
end
def expand_path(aPath)
expanded = aPath.starts_with("/") ? aPath : @pwd.ensure_end("/") + aPath
expanded.gsub!(/\/\.(\/|$)/, "")
expanded.gsub!(/[^\/]+\/\.\.(\/|$)/, "")
expanded.empty? ? "/" : expanded
end
private
def expand_to_entry(aPath)
expand_path(aPath).lchop
end
end
end
class ZipFile
include ZipFileSystem
end
end
# Copyright (C) 2002, 2003 Thomas Sondergaard
# rubyzip is free software; you can redistribute it and/or
# modify it under the terms of the ruby license.

90
vendor/plugins/rubyzip/lib/zip/ziprequire.rb vendored Executable file
View file

@ -0,0 +1,90 @@
# With ziprequire you can load ruby modules from a zip file. This means
# ruby's module include path can include zip-files.
#
# The following example creates a zip file with a single entry
# <code>log/simplelog.rb</code> that contains a single function
# <code>simpleLog</code>:
#
# require 'zip/zipfilesystem'
#
# Zip::ZipFile.open("my.zip", true) {
# |zf|
# zf.file.open("log/simplelog.rb", "w") {
# |f|
# f.puts "def simpleLog(v)"
# f.puts ' Kernel.puts "INFO: #{v}"'
# f.puts "end"
# }
# }
#
# To use the ruby module stored in the zip archive simply require
# <code>zip/ziprequire</code> and include the <code>my.zip</code> zip
# file in the module search path. The following command shows one
# way to do this:
#
# ruby -rzip/ziprequire -Imy.zip -e " require 'log/simplelog'; simpleLog 'Hello world' "
#$: << 'data/rubycode.zip' << 'data/rubycode2.zip'
require 'zip/zip'
class ZipList #:nodoc:all
def initialize(zipFileList)
@zipFileList = zipFileList
end
def get_input_stream(entry, &aProc)
@zipFileList.each {
|zfName|
Zip::ZipFile.open(zfName) {
|zf|
begin
return zf.get_input_stream(entry, &aProc)
rescue Errno::ENOENT
end
}
}
raise Errno::ENOENT,
"No matching entry found in zip files '#{@zipFileList.join(', ')}' "+
" for '#{entry}'"
end
end
module Kernel #:nodoc:all
alias :oldRequire :require
def require(moduleName)
zip_require(moduleName) || oldRequire(moduleName)
end
def zip_require(moduleName)
return false if already_loaded?(moduleName)
get_resource(ensure_rb_extension(moduleName)) {
|zis|
eval(zis.read); $" << moduleName
}
return true
rescue Errno::ENOENT => ex
return false
end
def get_resource(resourceName, &aProc)
zl = ZipList.new($:.grep(/\.zip$/))
zl.get_input_stream(resourceName, &aProc)
end
def already_loaded?(moduleName)
moduleRE = Regexp.new("^"+moduleName+"(\.rb|\.so|\.dll|\.o)?$")
$".detect { |e| e =~ moduleRE } != nil
end
def ensure_rb_extension(aString)
aString.sub(/(\.rb)?$/i, ".rb")
end
end
# Copyright (C) 2002 Thomas Sondergaard
# rubyzip is free software; you can redistribute it and/or
# modify it under the terms of the ruby license.