lib/roo/excelx.rb in roo-2.1.1 vs lib/roo/excelx.rb in roo-2.2.0

- old
+ new

@@ -1,82 +1,28 @@ require 'nokogiri' require 'zip/filesystem' require 'roo/link' require 'roo/utils' +require 'forwardable' module Roo class Excelx < Roo::Base + extend Forwardable + + require 'roo/excelx/shared' require 'roo/excelx/workbook' require 'roo/excelx/shared_strings' require 'roo/excelx/styles' require 'roo/excelx/cell' require 'roo/excelx/sheet' require 'roo/excelx/relationships' require 'roo/excelx/comments' require 'roo/excelx/sheet_doc' - - module Format - EXCEPTIONAL_FORMATS = { - 'h:mm am/pm' => :date, - 'h:mm:ss am/pm' => :date - } + require 'roo/excelx/coordinate' + require 'roo/excelx/format' - STANDARD_FORMATS = { - 0 => 'General'.freeze, - 1 => '0'.freeze, - 2 => '0.00'.freeze, - 3 => '#,##0'.freeze, - 4 => '#,##0.00'.freeze, - 9 => '0%'.freeze, - 10 => '0.00%'.freeze, - 11 => '0.00E+00'.freeze, - 12 => '# ?/?'.freeze, - 13 => '# ??/??'.freeze, - 14 => 'mm-dd-yy'.freeze, - 15 => 'd-mmm-yy'.freeze, - 16 => 'd-mmm'.freeze, - 17 => 'mmm-yy'.freeze, - 18 => 'h:mm AM/PM'.freeze, - 19 => 'h:mm:ss AM/PM'.freeze, - 20 => 'h:mm'.freeze, - 21 => 'h:mm:ss'.freeze, - 22 => 'm/d/yy h:mm'.freeze, - 37 => '#,##0 ;(#,##0)'.freeze, - 38 => '#,##0 ;[Red](#,##0)'.freeze, - 39 => '#,##0.00;(#,##0.00)'.freeze, - 40 => '#,##0.00;[Red](#,##0.00)'.freeze, - 45 => 'mm:ss'.freeze, - 46 => '[h]:mm:ss'.freeze, - 47 => 'mmss.0'.freeze, - 48 => '##0.0E+0'.freeze, - 49 => '@'.freeze - } - - def to_type(format) - format = format.to_s.downcase - if (type = EXCEPTIONAL_FORMATS[format]) - type - elsif format.include?('#') - :float - elsif !format.match(/d+(?![\]])/).nil? || format.include?('y') - if format.include?('h') || format.include?('s') - :datetime - else - :date - end - elsif format.include?('h') || format.include?('s') - :time - elsif format.include?('%') - :percentage - else - :float - end - end - - module_function :to_type - end - + delegate [:styles, :workbook, :shared_strings, :rels_files, :sheet_files, :comments_files] => :@shared ExceedsMaxError = Class.new(StandardError) # initialization and opening of a spreadsheet file # values for packed: :zip # optional cell_max (int) parameter for early aborting attempts to parse @@ -92,23 +38,22 @@ file_type_check(filename_or_stream, %w[.xlsx .xlsm], 'an Excel 2007', file_warning, packed) basename = File.basename(filename_or_stream) end @tmpdir = make_tmpdir(basename, options[:tmpdir_root]) + @shared = Shared.new(@tmpdir) @filename = local_filename(filename_or_stream, @tmpdir, packed) - @comments_files = [] - @rels_files = [] process_zipfile(@filename || filename_or_stream) @sheet_names = workbook.sheets.map do |sheet| unless options[:only_visible_sheets] && sheet['state'] == 'hidden' sheet['name'] end end.compact @sheets = [] @sheets_by_name = Hash[@sheet_names.map.with_index do |sheet_name, n| - @sheets[n] = Sheet.new(sheet_name, @rels_files[n], @sheet_files[n], @comments_files[n], styles, shared_strings, workbook, sheet_options) + @sheets[n] = Sheet.new(sheet_name, @shared, n, sheet_options) [sheet_name, @sheets[n]] end] if cell_max cell_count = ::Roo::Utils.num_cells_in_range(sheet_for(options.delete(:sheet)).dimensions) @@ -185,11 +130,11 @@ # set a cell to a certain value # (this will not be saved back to the spreadsheet file!) def set(row, col, value, sheet = nil) #:nodoc: key = normalize(row, col) cell_type = cell_type_by_value(value) - sheet_for(sheet).cells[key] = Cell.new(value, cell_type, nil, cell_type, value, nil, nil, nil, Cell::Coordinate.new(row, col)) + sheet_for(sheet).cells[key] = Cell.new(value, cell_type, nil, cell_type, value, nil, nil, nil, Coordinate.new(row, col)) end # Returns the formula at (row,col). # Returns nil if there is no formula. # The method #formula? checks if there is a formula. @@ -237,18 +182,18 @@ # * :numeric_or_formula # * :string # Note: this is only available within the Excelx class def excelx_type(row, col, sheet = nil) key = normalize(row, col) - safe_send(sheet_for(sheet).cells[key], :excelx_type) + safe_send(sheet_for(sheet).cells[key], :cell_type) end # returns the internal value of an excelx cell # Note: this is only available within the Excelx class def excelx_value(row, col, sheet = nil) key = normalize(row, col) - safe_send(sheet_for(sheet).cells[key], :excelx_value) + safe_send(sheet_for(sheet).cells[key], :cell_value) end # returns the internal format of an excel cell def excelx_format(row, col, sheet = nil) key = normalize(row, col) @@ -257,12 +202,12 @@ def empty?(row, col, sheet = nil) sheet = sheet_for(sheet) key = normalize(row, col) cell = sheet.cells[key] - !cell || !cell.value || (cell.type == :string && cell.value.empty?) \ - || (row < sheet.first_row || row > sheet.last_row || col < sheet.first_column || col > sheet.last_column) + !cell || cell.empty? || (cell.type == :string && cell.value.empty?) || + (row < sheet.first_row || row > sheet.last_row || col < sheet.first_column || col > sheet.last_column) end # shows the internal representation of all cells # for debugging purposes def to_s(sheet = nil) @@ -402,10 +347,11 @@ def extract_sheets_in_order(entries, sheet_ids, sheets, tmpdir) sheet_ids.each_with_index do |id, i| name = sheets[id] entry = entries.find { |e| e.name =~ /#{name}$/ } path = "#{tmpdir}/roo_sheet#{i + 1}" + sheet_files << path @sheet_files << path entry.extract(path) end end @@ -455,22 +401,24 @@ # the sheet order, i.e. sheet1.xml's comments are in comments1.xml. # In some situations, this isn't true. The true location of a # sheet's comment file is in the sheet1.xml.rels file. SEE # ECMA-376 12.3.3 in "Ecma Office Open XML Part 1". nr = Regexp.last_match[1].to_i - @comments_files[nr - 1] = "#{@tmpdir}/roo_comments#{nr}" + comments_files[nr - 1] = "#{@tmpdir}/roo_comments#{nr}" when /sheet([0-9]+).xml.rels$/ # FIXME: Roo seems to use sheet[\d].xml.rels for hyperlinks only, but # it also stores the location for sharedStrings, comments, # drawings, etc. nr = Regexp.last_match[1].to_i - @rels_files[nr - 1] = "#{@tmpdir}/roo_rels#{nr}" + rels_files[nr - 1] = "#{@tmpdir}/roo_rels#{nr}" end entry.extract(path) if path end end + # NOTE: To reduce memory, styles, shared_strings, workbook can be class + # variables in a Shared module. def styles @styles ||= Styles.new(File.join(@tmpdir, 'roo_styles.xml')) end def shared_strings