lib/roo/openoffice.rb in roo-0.7.0 vs lib/roo/openoffice.rb in roo-0.8.0
- old
+ new
@@ -4,16 +4,12 @@
require 'fileutils'
require 'zip/zipfilesystem'
require 'date'
require 'base64'
-# The class Openoffice defines the basic functionality for the access to
-# spreadsheet documents. Other classes like _Excel_ are defined as subclasses
-# of this class.
+class Openoffice < GenericSpreadsheet
-class Openoffice
-
@@nr = 0
# sets the line with attribute names (default: 1)
attr_accessor :header_line
@@ -24,11 +20,11 @@
unless File.exists?(@tmpdir)
FileUtils::mkdir(@tmpdir)
end
filename = open_from_uri(filename) if filename[0,7] == "http://"
filename = unzip(filename) if packed and packed == :zip
- if filename[-4..-1] != ".ods"
+ if File.extname(filename) != ".ods"
warn "are you sure, this is an openoffice file?"
end
#if create and ! File.exists?(filename)
# self.create_openoffice(filename)
#end
@@ -43,11 +39,11 @@
extract_content
file = File.new(File.join(@tmpdir, @file_nr.to_s+"_roo_content.xml"))
@doc = REXML::Document.new file
file.close
#if ENV["roo_local"] != "thomas-p"
- FileUtils::rm_r(@tmpdir)
+ FileUtils::rm_r(@tmpdir)
#end
@default_sheet = nil
# no need to set default_sheet if there is only one sheet in the document
if self.sheets.size == 1
@default_sheet = self.sheets.first
@@ -72,18 +68,10 @@
f = File.open(filename,'wb')
f.print(Base64.decode64(@@empty_spreadsheet))
f.close
end
- # reopens and read a spreadsheet document
- def reload
- ds = @default_sheet
- initialize(@filename)
- self.default_sheet = ds
- #@first_row = @last_row = @first_column = @last_column = nil
- end
-
# Returns the content of a spreadsheet-cell.
# (1,1) is the upper left corner.
# (1,1), (1,'A'), ('A',1), ('a',1) all refers to the
# cell at the first line and first row.
def cell(row, col, sheet=nil)
@@ -97,11 +85,11 @@
@cell[sheet]["#{row},#{col}"]
end
# Returns the formula at (row,col).
# Returns nil if there is no formula.
- # The method Openoffice#formula? checks if there is a formula.
+ # The method #formula? checks if there is a formula.
def formula(row,col,sheet=nil)
sheet = @default_sheet unless sheet
read_cells(sheet) unless @cells_read[sheet]
row,col = normalize(row,col)
if @formula[sheet]["#{row},#{col}"] == nil
@@ -151,18 +139,10 @@
else
@cell_type[sheet]["#{row},#{col}"]
end
end
- # recursively removes the current temporary directory
- # this is only needed if you work with zipped files or files via the web
- def remove_tmp
- if File.exists?(@tmpdir)
- FileUtils::rm_r(@tmpdir)
- end
- end
-
# returns an array of sheet names in the spreadsheet
def sheets
return_sheets = []
oo_document_count = 0
@doc.each_element do |oo_document|
@@ -250,109 +230,10 @@
result << cell(row,columnnumber,sheet)
end
result
end
- # returns the number of the last non-empty row
- def last_row(sheet=nil)
- sheet = @default_sheet unless sheet
- read_cells(sheet) unless @cells_read[sheet]
- if @last_row[sheet]
- return @last_row[sheet]
- end
- impossible_value = 0
- result = impossible_value
- @cell[sheet].each_pair {|key,value|
- y,x = key.split(',')
- y = y.to_i
- result = [result, y].max if value
- }
- result = nil if result == impossible_value
- @last_row[sheet] = result
- result
- end
-
- # returns the number of the last non-empty column
- def last_column(sheet=nil)
- sheet = @default_sheet unless sheet
- read_cells(sheet) unless @cells_read[sheet]
- if @last_column[sheet]
- return @last_column[sheet]
- end
- impossible_value = 0
- result = impossible_value
- @cell[sheet].each_pair {|key,value|
- y,x = key.split(',')
- x = x.to_i
- result = [result, x].max if value
- }
- result = nil if result == impossible_value
- @last_column[sheet] = result
- result
- end
-
- # returns the number of the first non-empty row
- def first_row(sheet=nil)
- if sheet == nil
- sheet = @default_sheet
- end
- read_cells(sheet) unless @cells_read[sheet]
- if @first_row[sheet]
- return @first_row[sheet]
- end
- impossible_value = 999_999 # more than a spreadsheet can hold
- result = impossible_value
- @cell[sheet].each_pair {|key,value|
- y,x = key.split(',')
- y = y.to_i
- result = [result, y].min if value
- }
- result = nil if result == impossible_value
- @first_row[sheet] = result
- result
- end
-
- # returns the number of the first non-empty column
- def first_column(sheet=nil)
- if sheet == nil
- sheet = @default_sheet
- end
- read_cells(sheet) unless @cells_read[sheet]
- if @first_column[sheet]
- return @first_column[sheet]
- end
- impossible_value = 999_999 # more than a spreadsheet can hold
- result = impossible_value
- @cell[sheet].each_pair {|key,value|
- y,x = key.split(',')
- x = x.to_i
- result = [result, x].min if value
- }
- result = nil if result == impossible_value
- @first_column[sheet] = result
- result
- end
-
- # first non-empty column as a letter
- def first_column_as_letter(sheet=nil)
- Openoffice.number_to_letter(first_column(sheet))
- end
-
- # last non-empty column as a letter
- def last_column_as_letter(sheet=nil)
- Openoffice.number_to_letter(last_column(sheet))
- end
-
- # true if cell is empty
- def empty?(row, col, sheet=nil)
- sheet = @default_sheet unless sheet
- read_cells(sheet) unless @cells_read[sheet]
- return true unless cell(row, col, sheet)
- return true if celltype(row, col, sheet) == :string && cell(row, col, sheet).empty?
- false
- end
-
# save spreadsheet
def save #:nodoc:
42
end
@@ -385,34 +266,13 @@
}
}
theformulas
end
- # returns a rectangular area (default: all cells) as yaml-output
- # you can add additional attributes with the prefix parameter like:
- # oo.to_yaml({"file"=>"flightdata_2007-06-26", "sheet" => "1"})
- def to_yaml(prefix={}, from_row=nil, from_column=nil, to_row=nil, to_column=nil,sheet=nil)
- sheet = @default_sheet unless sheet
- result = "--- \n"
- (from_row||first_row(sheet)).upto(to_row||last_row(sheet)) do |row|
- (from_column||first_column(sheet)).upto(to_column||last_column(sheet)) do |col|
- unless empty?(row,col,sheet)
- result << "cell_#{row}_#{col}: \n"
- prefix.each {|k,v|
- result << " #{k}: #{v} \n"
- }
- result << " row: #{row} \n"
- result << " col: #{col} \n"
- result << " celltype: #{self.celltype(row,col,sheet)} \n"
- result << " value: #{self.cell(row,col,sheet)} \n"
- end
- end
- end
- result
- end
-
# write the current spreadsheet to stdout or into a file
+#TODO: refactoring --> GenericSpreadsheet
+
def to_csv(filename=nil,sheet=nil)
sheet = @default_sheet unless sheet
if filename
file = File.open(filename,"w") # do |file|
write_csv_content(file,sheet)
@@ -454,11 +314,11 @@
end
}
tmp[x] = cell(rownum,j)
}
result = [ tmp ] # row(rownum)
- #-- :all
+ #-- :all
elsif args[0] == :all
if args[1].class == Hash
args[1].each {|key,val|
if key == :conditions
column_with = {}
@@ -500,71 +360,22 @@
end
end
result
end
- # Returns information of the spreadsheet document and all sheets within
- # this document.
- def info
- result = "File: #{@filename}\n"+
- "Number of sheets: #{sheets.size}\n"+
- "Sheets: #{sheets.map{|sheet| sheet+", "}.to_s[0..-3]}\n"
- n = 1
- sheets.each {|sheet|
- self.default_sheet = sheet
- result << "Sheet " + n.to_s + ":\n"
- result << " First row: #{first_row}\n"
- result << " Last row: #{last_row}\n"
- result << " First column: #{Openoffice.number_to_letter(first_column)}\n"
- result << " Last column: #{Openoffice.number_to_letter(last_column)}"
- result << "\n" if sheet != sheets.last
- n += 1
- }
- result
- end
+
+ private
-private
-
- def process_zipfile_packed(zip, path='')
- ret=nil
- if zip.file.file? path
- # extract and return filename
- @tmpdir = "oo_"+$$.to_s
- unless File.exists?(@tmpdir)
- FileUtils::mkdir(@tmpdir)
- end
- file = File.open(File.join(@tmpdir, path),"wb")
- file.write(zip.read(path))
- file.close
- return File.join(@tmpdir, path)
- else
- unless path.empty?
- path += '/'
- end
- zip.dir.foreach(path) do |filename|
- ret = process_zipfile_packed(zip, path + filename)
- end
- end
- ret
- end
-
- def unzip(filename)
- ret = nil
- Zip::ZipFile.open(filename) do |zip|
- ret = process_zipfile_packed zip
- end
- ret
- end
-
# read the version of the OO-Version
def oo_version
#sheet_found = false
@doc.each_element do |oo_document|
@officeversion = oo_document.attributes['version']
end
end
+ # helper function to set the internal representation of cells
def set_cell_values(sheet,x,y,i,v,vt,formula,tr,str_v)
key = "#{y},#{x+i}"
@cell_type[sheet] = {} unless @cell_type[sheet]
@cell_type[sheet][key] = Openoffice.oo_type_2_roo_type(vt)
@formula[sheet] = {} unless @formula[sheet]
@@ -719,60 +530,16 @@
process_zipfile(zip, path+filename)
end
end
end
-
def extract_content
Zip::ZipFile.open(@filename) do |zip|
process_zipfile(zip)
end
end
- # converts cell coordinate to numeric values of row,col
- def normalize(row,col)
- if row.class == String
- if col.class == Fixnum
- # ('A',1):
- # ('B', 5) -> (5, 2)
- row, col = col, row
- else
- raise ArgumentError
- end
- end
- if col.class == String
- col = Openoffice.letter_to_number(col)
- end
- return row,col
- end
-
- # convert a number to something like this: 'AB'
- def Openoffice.number_to_letter(n)
- letters=""
- while n > 0
- num = n%26
- letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[num-1,1] + letters
- n = n.div(26)
- end
- letters
- end
-
- # convert letters like 'AB' to a number
- def Openoffice.letter_to_number(letters)
- result = 0
- while letters && letters.length > 0
- character = letters[0,1].upcase
- num = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".index(character)
- raise ArgumentError, "invalid column character '#{letters[0,1]}'" if num == nil
- num += 1
- result = result * 26 + num
- letters = letters[1..-1]
- end
- result
- end
-
-
def set_value(row,col,value,sheet=nil)
sheet = @default_value unless sheet
@cell[sheet]["#{row},#{col}"] = value
end
@@ -790,26 +557,12 @@
def Openoffice.oo_type_2_roo_type(ootype)
return A_ROO_TYPE[ootype]
end
-
- def open_from_uri(uri)
- require 'open-uri' ;
- tempfilename = File.join(@tmpdir, File.basename(uri))
- f = File.open(tempfilename,"wb")
- begin
- open(uri) do |net|
- f.write(net.read)
- end
- rescue
- raise "could not open #{uri}"
- end
- f.close
- File.join(@tmpdir, File.basename(uri))
- end
-
+
+ #TODO: refactoring to GenericSpreadsheet?
def write_csv_content(file=nil,sheet=nil)
file = STDOUT unless file
if first_row # sheet is not empty
first_row(sheet).upto(last_row(sheet)) do |row|
1.upto(last_column(sheet)) do |col|
@@ -821,9 +574,10 @@
file.print("\n")
end # sheet not empty
end
end
+#TODO: refactor to Generic...
def one_cell_output(onecelltype,onecell,empty)
str = ""
if empty
str += ''
else