lib/roo/excel.rb in roo-1.3.5 vs lib/roo/excel.rb in roo-1.3.6

- old
+ new

@@ -4,10 +4,30 @@ true rescue LoadError => e false end +# The Spreadsheet library has a bug in handling Excel +# base dates so if the file is a 1904 base date then +# dates are off by a day. 1900 base dates work fine +module Spreadsheet + module Excel + class Row < Spreadsheet::Row + def _date data # :nodoc: + return data if data.is_a?(Date) + date = @worksheet.date_base + data.to_i + if LEAP_ERROR > @worksheet.date_base + date -= 1 + end + date + end + public :_datetime + end + end +end + + # ruby-spreadsheet has a font object so we're extending it # with our own functionality but still providing full access # to the user for other font information module ExcelFontExtensions def bold?(*args) @@ -53,15 +73,11 @@ @filename = filename unless File.file?(@filename) raise IOError, "file #{@filename} does not exist" end @workbook = Spreadsheet.open(filename) - @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 - end + @default_sheet = self.sheets.first ensure #if ENV["roo_local"] != "thomas-p" FileUtils::rm_r(@tmpdir) #end end @@ -126,42 +142,10 @@ puts "Error in sheet #{sheet}, row #{row}, col #{col}" raise end end - # returns the first non empty column - def first_column(sheet=nil) - sheet = @default_sheet unless sheet - return @first_column[sheet] if @first_column[sheet] - fr, lr, fc, lc = get_firsts_lasts(sheet) - fc - end - - # returns the last non empty column - def last_column(sheet=nil) - sheet = @default_sheet unless sheet - return @last_column[sheet] if @last_column[sheet] - fr, lr, fc, lc = get_firsts_lasts(sheet) - lc - end - - # returns the first non empty row - def first_row(sheet=nil) - sheet = @default_sheet unless sheet - return @first_row[sheet] if @first_row[sheet] - fr, lr, fc, lc = get_firsts_lasts(sheet) - fr - end - - # returns the last non empty row - def last_row(sheet=nil) - sheet = @default_sheet unless sheet - return @last_row[sheet] if @last_row[sheet] - fr, lr, fc, lc = get_firsts_lasts(sheet) - lr - end - # returns NO formula in excel spreadsheets def formula(row,col,sheet=nil) raise EXCEL_NO_FORMULAS end @@ -190,47 +174,11 @@ read_cells(sheet) unless @cells_read[sheet] @cell[sheet].inspect end private - # determine the first and last boundaries - def get_firsts_lasts(sheet=nil) - - # 2008-09-14 BEGINf - fr=lr=fc=lc=nil - sheet = @default_sheet unless sheet - if ! @cells_read[sheet] - read_cells(sheet) - end - if @cell[sheet] # nur wenn ueberhaupt Zellen belegt sind - @cell[sheet].each {|cellitem| - key = cellitem.first - y,x = key - if cellitem[1].class != String or - (cellitem[1].class == String and cellitem[1] != "") - fr = y unless fr - fr = y if y < fr - - lr = y unless lr - lr = y if y > lr - - fc = x unless fc - fc = x if x < fc - - lc = x unless lc - lc = x if x > lc - end - } - end - @first_row[sheet] = fr - @last_row[sheet] = lr - @first_column[sheet] = fc - @last_column[sheet] = lc - return fr, lr, fc, lc - end - # converts name of a sheet to index (0,1,2,..) def sheet_no(name) return name-1 if name.kind_of?(Fixnum) i = 0 @workbook.worksheets.each do |worksheet| @@ -353,11 +301,11 @@ row_index=1 worksheet.each(0) do |row| (0..row.size).each do |cell_index| cell = row.at(cell_index) next if cell.nil? #skip empty cells - next if cell.class == Spreadsheet::Formula + next if cell.class == Spreadsheet::Formula && cell.value.nil? # skip empty formla cells if date_or_time?(row, cell_index) vt, v = read_cell_date_or_time(row, cell_index) else vt, v = read_cell(row, cell_index) end @@ -369,27 +317,36 @@ end #row row_index += 1 end # worksheet @cells_read[sheet] = true end - + + # Get the contents of a cell, accounting for the + # way formula stores the value + def read_cell_content(row, idx) + cell = row.at(idx) + cell = cell.value if cell.class == Spreadsheet::Formula + cell + end + # Test the cell to see if it's a valid date/time. def date_or_time?(row, idx) format = row.format(idx) if format.date_or_time? - cell = row.at(idx) + cell = read_cell_content(row, idx) true if Float(cell) > 0 rescue false else false end end private :date_or_time? # Read the date-time cell and convert to, # the date-time values for Roo def read_cell_date_or_time(row, idx) - cell = row.at(idx).to_s.to_f + cell = read_cell_content(row, idx) + cell = cell.to_s.to_f if cell < 1.0 value_type = :time f = cell*24.0*60.0*60.0 secs = f.round h = (secs / 3600.0).floor @@ -397,29 +354,37 @@ m = (secs / 60.0).floor secs = secs - 60*m s = secs value = h*3600+m*60+s else - datetime = row.datetime(idx) + if row.at(idx).class == Spreadsheet::Formula + datetime = row._datetime(cell) + else + datetime = row.datetime(idx) + end if datetime.hour != 0 or datetime.min != 0 or datetime.sec != 0 value_type = :datetime value = datetime else value_type = :date - value = row.date(idx) + if row.at(idx).class == Spreadsheet::Formula + value = row._date(cell) + else + value = row.date(idx) + end value = sprintf("%04d-%02d-%02d",value.year,value.month,value.day) end end return value_type, value end private :read_cell_date_or_time # Read the cell and based on the class, # return the values for Roo def read_cell(row, idx) - cell = row.at(idx) + cell = read_cell_content(row, idx) case cell when Float, Integer, Fixnum, Bignum value_type = :float value = cell.to_f when String, TrueClass, FalseClass