def extract(destination, options = {})
raise IOError, 'non-readable archive' unless readable?
raise IOError, 'closed archive' if closed?
options[:directories] = true unless options.has_key?(:directories)
options[:symlinks] = false unless options.has_key?(:symlinks)
options[:overwrite] = :all unless options[:overwrite] == :older ||
options[:overwrite] == :never
options[:create] = true unless options.has_key?(:create)
options[:flatten] = false unless options.has_key?(:flatten)
options[:directories] = false if options[:flatten]
directories = []
each do |entry|
file_path = entry.zip_path
file_path = File.basename(file_path) if options[:flatten]
file_path = File.join(destination, file_path)
file_exists = File.exist?(file_path)
file_mtime = File.mtime(file_path) if file_exists
begin
if (! file_exists && ! options[:create]) ||
(file_exists &&
(options[:overwrite] == :never ||
options[:overwrite] == :older && entry.mtime <= file_mtime)) ||
(! options[:exclude].nil? && options[:exclude][entry]) then
next
end
if options[:password].kind_of?(String) then
entry.password = options[:password]
elsif ! options[:password].nil? then
entry.password = options[:password][entry]
end
if entry.directory? then
directories << entry
elsif entry.file? || (entry.symlink? && options[:symlinks]) then
entry.extract(
options.merge(:file_path => file_path)
)
end
rescue StandardError => error
unless options[:on_error].nil? then
case options[:on_error][entry, error]
when :retry
retry
when :skip
else
raise
end
else
raise
end
end
end
if options[:directories] then
directories.sort { |a, b| b.zip_path <=> a.zip_path }.each do |entry|
begin
entry.extract(
options.merge(
:file_path => File.join(destination, entry.zip_path)
)
)
rescue StandardError => error
unless options[:on_error].nil? then
case options[:on_error][entry, error]
when :retry
retry
when :skip
else
raise
end
else
raise
end
end
end
end
nil
end