class Crek::Sheet

Attributes

book[R]
index[R]
name[R]
rid[R]
sheetid[R]
state[R]
visible[R]

Public Class Methods

new(book, name, sheetid, state, visible, rid, sheetfile) click to toggle source
# File lib/crek/sheet.rb, line 17
def initialize book, name, sheetid, state, visible, rid, sheetfile
  @book = book
  @name = name
  @sheetid = sheetid
  @visible = visible
  @rid = rid
  @state = state
  @sheetfile = sheetfile
  @images_present = false
end

Public Instance Methods

images_at(cell) click to toggle source

Extracts images for a cell to a temporary folder. Returns array of Pathnames for the cell. Returns nil if images asre not found for the cell or images were not preloaded with with_images.

# File lib/crek/sheet.rb, line 45
def images_at(cell)
  @drawing.images_at(cell) if @images_present
end
rows() click to toggle source

Provides an Enumerator that returns a hash representing each row. The key of the hash is the Cell id and the value is the value of the cell.

# File lib/crek/sheet.rb, line 60
def rows
  rows_generator false, false
end
rows_with_meta_data() click to toggle source

Provides an Enumerator that returns a hash representing each row. The hash contains meta data of the row and a 'cells' embended hash which contains the cell contents.

# File lib/crek/sheet.rb, line 67
def rows_with_meta_data
  rows_generator true, false
end
simple_rows() click to toggle source

Provides an Enumerator that returns a hash representing each row. The key of the hash is the column ID and the value is the value of the cell.

# File lib/crek/sheet.rb, line 53
def simple_rows
  rows_generator false, true
end
simple_rows_with_meta_data() click to toggle source

Provides an Enumerator that returns a hash representing each row. The hash contains meta data of the row and a 'cells' embended hash which contains the cell contents.

# File lib/crek/sheet.rb, line 74
def simple_rows_with_meta_data
  rows_generator true, true
end
with_images() click to toggle source

Preloads images info (coordinates and paths) from related drawing.xml and drawing rels. Must be called before rows method if you want to have images included. Returns self so you can chain the calls (sheet.with_images.rows).

# File lib/crek/sheet.rb, line 32
def with_images
  @drawingfile = extract_drawing_filepath
  if @drawingfile
    @drawing = Crek::Drawing.new(@book, @drawingfile.sub('..', 'xl'))
    @images_present = @drawing.has_images?
  end
  self
end

Private Instance Methods

convert(value, type, style_idx) click to toggle source
# File lib/crek/sheet.rb, line 128
def convert(value, type, style_idx)
  style = @book.style_types[style_idx.to_i]
  Crek::Styles::Converter.call(value, type, style, converter_options)
end
converter_options() click to toggle source
# File lib/crek/sheet.rb, line 133
def converter_options
  @converter_options ||= {
    shared_strings: @book.shared_strings.dictionary,
    base_date: @book.base_date
  }
end
extract_drawing_filepath() click to toggle source

Find drawing filepath for the current sheet. Sheet xml contains drawing relationship ID. Sheet relationships xml contains drawing file's location.

# File lib/crek/sheet.rb, line 162
def extract_drawing_filepath
  # Read drawing relationship ID from the sheet.
  sheet_filepath = "xl/#{@sheetfile}"
  drawing = parse_xml(sheet_filepath).css('drawing').first
  return if drawing.nil?

  drawing_rid = drawing.attributes['id'].value

  # Read sheet rels to find drawing file's location.
  sheet_rels_filepath = expand_to_rels_path(sheet_filepath)
  parse_xml(sheet_rels_filepath).css("Relationship[@Id='#{drawing_rid}']").first.attributes['Target'].value
end
fill_in_empty_cells(cells, row_number, last_col, use_simple_rows_format) click to toggle source

The unzipped XML file does not contain any node for empty cells. Empty cells are being padded in using this function

# File lib/crek/sheet.rb, line 143
def fill_in_empty_cells(cells, row_number, last_col, use_simple_rows_format)
  new_cells = Hash.new

  unless cells.empty?
    last_col = last_col.gsub(row_number, '')

    ("A"..last_col).to_a.each do |column|
      id = use_simple_rows_format ? "#{column}" : "#{column}#{row_number}"
      new_cells[id] = cells[id]
    end
  end

  new_cells
end
rows_generator(include_meta_data=false, use_simple_rows_format=false) click to toggle source

Returns a hash per row that includes the cell ids and values. Empty cells will be also included in the hash with a nil value.

# File lib/crek/sheet.rb, line 83
def rows_generator include_meta_data=false, use_simple_rows_format=false
  path = if @sheetfile.start_with? "/xl/" or @sheetfile.start_with? "xl/" then @sheetfile else "xl/#{@sheetfile}" end
  if @book.files.file.exist?(path)
    # SAX parsing, Each element in the stream comes through as two events:
    # one to open the element and one to close it.
    opener = Nokogiri::XML::Reader::TYPE_ELEMENT
    closer = Nokogiri::XML::Reader::TYPE_END_ELEMENT
    Enumerator.new do |y|
      row, cells, cell = nil, {}, nil
      cell_type  = nil
      cell_style_idx = nil
      @book.files.file.open(path) do |xml|
        Nokogiri::XML::Reader.from_io(xml).each do |node|
          if (node.name.eql? 'row') and (node.node_type.eql? opener)
            row = node.attributes
            row['cells'] = Hash.new
            cells = Hash.new
            y << (include_meta_data ? row : cells) if node.self_closing?
          elsif (node.name.eql? 'row') and (node.node_type.eql? closer)
            processed_cells = fill_in_empty_cells(cells, row['r'], cell, use_simple_rows_format)

            if @images_present
              processed_cells.each do |cell_name, cell_value|
                next unless cell_value.nil?
                processed_cells[cell_name] = images_at(cell_name)
              end
            end

            row['cells'] = processed_cells
            y << (include_meta_data ? row : processed_cells)
          elsif (node.name.eql? 'c') and (node.node_type.eql? opener)
            cell_type      = node.attributes['t']
            cell_style_idx = node.attributes['s']
            cell           = node.attributes['r']
          elsif (['v', 't'].include? node.name) and (node.node_type.eql? opener)
            unless cell.nil?
              cells[(use_simple_rows_format ? cell.tr("0-9", "") : cell)] = convert(node.inner_xml, cell_type, cell_style_idx)
            end
          end
        end
      end
    end
  end
end