summaryrefslogtreecommitdiffstats
path: root/lib/roo/excelx/sheet.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/roo/excelx/sheet.rb')
-rw-r--r--lib/roo/excelx/sheet.rb112
1 files changed, 112 insertions, 0 deletions
diff --git a/lib/roo/excelx/sheet.rb b/lib/roo/excelx/sheet.rb
new file mode 100644
index 0000000..add92f0
--- /dev/null
+++ b/lib/roo/excelx/sheet.rb
@@ -0,0 +1,112 @@
+require 'forwardable'
+module Roo
+ class Excelx
+ class Sheet
+ extend Forwardable
+
+ delegate [:styles, :workbook, :shared_strings, :rels_files, :sheet_files, :comments_files] => :@shared
+
+ def initialize(name, shared, sheet_index, options = {})
+ @name = name
+ @shared = shared
+ @rels = Relationships.new(rels_files[sheet_index])
+ @comments = Comments.new(comments_files[sheet_index])
+ @sheet = SheetDoc.new(sheet_files[sheet_index], @rels, shared, options)
+ end
+
+ def cells
+ @cells ||= @sheet.cells(@rels)
+ end
+
+ def present_cells
+ @present_cells ||= cells.select { |_, cell| cell && !cell.empty? }
+ end
+
+ # Yield each row as array of Excelx::Cell objects
+ # accepts options max_rows (int) (offset by 1 for header),
+ # pad_cells (boolean) and offset (int)
+ def each_row(options = {}, &block)
+ row_count = 0
+ options[:offset] ||= 0
+ @sheet.each_row_streaming do |row|
+ break if options[:max_rows] && row_count == options[:max_rows] + options[:offset] + 1
+ if block_given? && !(options[:offset] && row_count < options[:offset])
+ block.call(cells_for_row_element(row, options))
+ end
+ row_count += 1
+ end
+ end
+
+ def row(row_number)
+ first_column.upto(last_column).map do |col|
+ cells[[row_number, col]]
+ end.map { |cell| cell && cell.value }
+ end
+
+ def column(col_number)
+ first_row.upto(last_row).map do |row|
+ cells[[row, col_number]]
+ end.map { |cell| cell && cell.value }
+ end
+
+ # returns the number of the first non-empty row
+ def first_row
+ @first_row ||= present_cells.keys.map { |row, _| row }.min
+ end
+
+ def last_row
+ @last_row ||= present_cells.keys.map { |row, _| row }.max
+ end
+
+ # returns the number of the first non-empty column
+ def first_column
+ @first_column ||= present_cells.keys.map { |_, col| col }.min
+ end
+
+ # returns the number of the last non-empty column
+ def last_column
+ @last_column ||= present_cells.keys.map { |_, col| col }.max
+ end
+
+ def excelx_format(key)
+ cell = cells[key]
+ styles.style_format(cell.style).to_s if cell
+ end
+
+ def hyperlinks
+ @hyperlinks ||= @sheet.hyperlinks(@rels)
+ end
+
+ def comments
+ @comments.comments
+ end
+
+ def dimensions
+ @sheet.dimensions
+ end
+
+ private
+
+ # Take an xml row and return an array of Excelx::Cell objects
+ # optionally pad array to header width(assumed 1st row).
+ # takes option pad_cells (boolean) defaults false
+ def cells_for_row_element(row_element, options = {})
+ return [] unless row_element
+ cell_col = 0
+ cells = []
+ @sheet.each_cell(row_element) do |cell|
+ cells.concat(pad_cells(cell, cell_col)) if options[:pad_cells]
+ cells << cell
+ cell_col = cell.coordinate.column
+ end
+ cells
+ end
+
+ def pad_cells(cell, last_column)
+ pad = []
+ (cell.coordinate.column - 1 - last_column).times { pad << nil }
+ pad
+ end
+ end
+ end
+end