Skip to content

Commit

Permalink
Added FileUtils module
Browse files Browse the repository at this point in the history
This commit serves three purposes.

1. Helps prepare Roo for the new interface mentioned in #240.
2. Helps clean up Roo::Base, which is doing too much.
3. Marked unnecessary public functions for future deprecation
  • Loading branch information
stevendaniels committed Oct 31, 2015
1 parent 6d8e0b0 commit 3af0b02
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 73 deletions.
83 changes: 10 additions & 73 deletions lib/roo/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
require 'stringio'
require 'nokogiri'
require 'roo/utils'
require 'roo/file_utils'

# Base class for all other types of spreadsheets
class Roo::Base
include Enumerable
include Roo::FileUtils

TEMP_PREFIX = 'roo_'.freeze
MAX_ROW_COL = 999_999.freeze
Expand Down Expand Up @@ -429,30 +431,29 @@ def file_type_check(filename, exts, name, warning_level, packed = nil)
end
end

# konvertiert einen Key in der Form "12,45" (=row,column) in
# ein Array mit numerischen Werten ([12,45])
# Diese Methode ist eine temp. Loesung, um zu erforschen, ob der
# Zugriff mit numerischen Keys schneller ist.
# Public: Converts keys in the form "12,45" (=row,column) into an Array of
# numeric values.
#
# This method is a temporary solution to explore whether access with
# numeric keys is faster.
# TODO: Deprecate
def key_to_num(str)
r, c = str.split(',')
[r.to_i, c.to_i]
end

# see: key_to_num
# TODO: Deprecate
def key_to_string(arr)
"#{arr[0]},#{arr[1]}"
end

# TODO: Deprecate.
def is_stream?(filename_or_stream)
filename_or_stream.respond_to?(:seek)
end

private

def track_tmpdir!(tmpdir)
(@tmpdirs ||= []) << tmpdir
end

def clean_sheet_if_need(options)
return unless options[:clean]
options.delete(:clean)
Expand All @@ -472,16 +473,6 @@ def search_or_set_header(options)
end
end

def local_filename(filename, tmpdir, packed)
return if is_stream?(filename)
filename = download_uri(filename, tmpdir) if uri?(filename)
filename = unzip(filename, tmpdir) if packed == :zip

fail IOError, "file #{filename} does not exist" unless File.file?(filename)

filename
end

def file_type_warning_message(filename, exts)
*rest, last_ext = exts
ext_list = rest.any? ? "#{rest.join(', ')} or #{last_ext}" : last_ext
Expand Down Expand Up @@ -535,14 +526,6 @@ def reinitialize
initialize(@filename)
end

def make_tmpdir(prefix = nil, root = nil, &block)
prefix = "#{TEMP_PREFIX}#{prefix}"

::Dir.mktmpdir(prefix, root || ENV['ROO_TMP'], &block).tap do |result|
block_given? || track_tmpdir!(result)
end
end

def clean_sheet(sheet)
read_cells(sheet)
@cell[sheet].each_pair do |coord, value|
Expand Down Expand Up @@ -591,27 +574,6 @@ def normalize(row, col)
[row, col]
end

def uri?(filename)
filename.start_with?('http://', 'https://')
rescue
false
end

def download_uri(uri, tmpdir)
require 'open-uri'
tempfilename = File.join(tmpdir, File.basename(uri))
begin
File.open(tempfilename, 'wb') do |file|
open(uri, 'User-Agent' => "Ruby/#{RUBY_VERSION}") do |net|
file.write(net.read)
end
end
rescue OpenURI::HTTPError
raise "could not open #{uri}"
end
tempfilename
end

def open_from_stream(stream, tmpdir)
tempfilename = File.join(tmpdir, 'spreadsheet')
File.open(tempfilename, 'wb') do |file|
Expand All @@ -620,14 +582,6 @@ def open_from_stream(stream, tmpdir)
File.join(tmpdir, 'spreadsheet')
end

def unzip(filename, tmpdir)
require 'zip/filesystem'

Zip::File.open(filename) do |zip|
process_zipfile_packed(zip, tmpdir)
end
end

# check if default_sheet was set and exists in sheets-array
def validate_sheet!(sheet)
case sheet
Expand All @@ -646,23 +600,6 @@ def validate_sheet!(sheet)
end
end

def process_zipfile_packed(zip, tmpdir, path = '')
if zip.file.file? path
# extract and return filename
File.open(File.join(tmpdir, path), 'wb') do |file|
file.write(zip.read(path))
end
File.join(tmpdir, path)
else
ret = nil
path += '/' unless path.empty?
zip.dir.foreach(path) do |filename|
ret = process_zipfile_packed(zip, tmpdir, path + filename)
end
ret
end
end

# Write all cells to the csv file. File can be a filename or nil. If the this
# parameter is nil the output goes to STDOUT
def write_csv_content(file = nil, sheet = nil, separator = ',')
Expand Down
90 changes: 90 additions & 0 deletions lib/roo/file_utils.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
module Roo
# Public: methods for opening and closing spreadsheet files.
module FileUtils
TEMPDIR_PREFIX = 'roo_'.freeze

def close
return nil unless @tmpdirs
@tmpdirs.each { |dir| ::FileUtils.remove_entry(dir) }

nil
end

private

def is_stream?(filename_or_stream)
filename_or_stream.respond_to?(:seek)
end

# move random Roo::Base functions to Utils
def make_tmpdir(prefix = nil, root = nil, &block)
prefix ||= TEMPDIR_PREFIX

::Dir.mktmpdir(prefix, root, &block).tap do |result|
block_given? || track_tmpdir!(result)
end
end

def local_filename(filename, tmpdir, packed = nil, stream = false)
# FIXME: Remove nil check if Roo.open_new validates path
fail IOError, 'filename cannot be nil' unless filename
return if stream || is_stream?(filename)

filename = download_uri(filename, tmpdir) if uri?(filename)
filename = unzip(filename, tmpdir) if packed == :zip

fail IOError, "#{filename} does not exist" unless File.exist?(filename)

filename
end

def uri?(filename)
filename.start_with?('http://', 'https://')
end

def download_uri(uri, tmpdir)
require 'open-uri'
tempfilename = File.join(tmpdir, File.basename(uri))
begin
File.open(tempfilename, 'wb') do |file|
open(uri, 'User-Agent' => "Ruby/#{RUBY_VERSION}") do |net|
file.write(net.read)
end
end
rescue OpenURI::HTTPError
raise "could not open #{uri}"
end

tempfilename
end

def track_tmpdir!(tmpdir)
(@tmpdirs ||= []) << tmpdir
end

def unzip(filename, tmpdir)
require 'zip/filesystem'

Zip::File.open(filename) do |zip|
process_zipfile_packed(zip, tmpdir)
end
end

def process_zipfile_packed(zip, tmpdir, path = '')
if zip.file.file? path
# extract and return filename
File.open(File.join(tmpdir, path), 'wb') do |file|
file.write(zip.read(path))
end
File.join(tmpdir, path)
else
ret = nil
path += '/' unless path.empty?
zip.dir.foreach(path) do |filename|
ret = process_zipfile_packed(zip, tmpdir, path + filename)
end
ret
end
end
end
end
9 changes: 9 additions & 0 deletions lib/roo/utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ def num_cells_in_range(str)
(x2 - (x1 - 1)) * (y2 - (y1 - 1))
end

# Public: Compute upper bound for cells in a given cell matrix.
def num_cells_in_matrix(matrix)
fail ArgumentError 'Invalid Matrix: matrix must be an array.' unless matrix.is_a? Array
fail ArgumentError "Invalid Matrix: #{matrix.inspect}." unless matrix.size == 2
x1, y1, x2, y2 = matrix.flatten

(x2 - (x1 - 1)) * (y2 - (y1 - 1))
end

def load_xml(path)
::File.open(path, 'rb') do |file|
::Nokogiri::XML(file)
Expand Down

0 comments on commit 3af0b02

Please sign in to comment.