diff --git a/lib/creek/sheet.rb b/lib/creek/sheet.rb index 69d8497..64d3b3f 100644 --- a/lib/creek/sheet.rb +++ b/lib/creek/sheet.rb @@ -100,6 +100,9 @@ def rows_generator(include_meta_data = false, use_simple_rows_format = false) cell = nil cell_type = nil cell_style_idx = nil + last_cell_ref = nil + current_col_index = nil + increment_on_close = false @book.files.file.open(path) do |xml| prefix = '' name_row = 'row' @@ -123,9 +126,11 @@ def rows_generator(include_meta_data = false, use_simple_rows_format = false) row = node.attributes row['cells'] = {} cells = {} + last_cell_ref = nil + current_col_index = 0 y << (include_meta_data ? row : cells) if node.self_closing? elsif node.name == name_row && node.node_type == closer - processed_cells = fill_in_empty_cells(cells, row['r'], cell, use_simple_rows_format) + processed_cells = fill_in_empty_cells(cells, row['r'], last_cell_ref, use_simple_rows_format) @headers = processed_cells if with_headers && row['r'] == HEADERS_ROW_NUMBER if @images_present @@ -142,6 +147,33 @@ def rows_generator(include_meta_data = false, use_simple_rows_format = false) cell_type = node.attributes['t'] cell_style_idx = node.attributes['s'] cell = node.attributes['r'] + if cell.nil? || cell.empty? + row_number = row && row['r'] + if row_number && !current_col_index.nil? + cell = "#{column_index_to_letters(current_col_index)}#{row_number}" + end + else + col_letters = column_from_cell_ref(cell) + current_col_index = column_letters_to_index(col_letters) unless col_letters.nil? + end + last_cell_ref = cell unless cell.nil? + if node.self_closing? + current_col_index += 1 if !current_col_index.nil? + increment_on_close = false + cell = nil + cell_type = nil + cell_style_idx = nil + else + increment_on_close = true + end + elsif node.name == name_c && node.node_type == closer + if increment_on_close && !current_col_index.nil? + current_col_index += 1 + end + increment_on_close = false + cell = nil + cell_type = nil + cell_style_idx = nil elsif (node.name == name_v || node.name == name_t) && node.node_type == opener unless cell.nil? node.read @@ -170,7 +202,7 @@ def converter_options # Empty cells are being padded in using this function def fill_in_empty_cells(cells, row_number, last_col, use_simple_rows_format) new_cells = {} - return new_cells if cells.empty? + return new_cells if cells.empty? || row_number.nil? || last_col.nil? last_col = last_col.gsub(row_number, '') ('A'..last_col).to_a.each do |column| @@ -203,5 +235,27 @@ def cell_id(column, use_simple_rows_format, row_number) (with_headers && headers) ? headers[column] : column end + + def column_from_cell_ref(cell_ref) + cell_ref.to_s.upcase[/[A-Z]+/] + end + + def column_letters_to_index(column_letters) + return nil if column_letters.nil? || column_letters.empty? + + column_letters.chars.reduce(0) { |sum, char| (sum * 26) + (char.ord - 64) } - 1 + end + + def column_index_to_letters(column_index) + return nil if column_index.nil? || column_index.negative? + + result = +'' + index = column_index + while index >= 0 + result.prepend((index % 26 + 65).chr) + index = (index / 26) - 1 + end + result + end end end diff --git a/spec/fixtures/sample-missing-cell-ref.xlsx b/spec/fixtures/sample-missing-cell-ref.xlsx new file mode 100644 index 0000000..ac912a7 Binary files /dev/null and b/spec/fixtures/sample-missing-cell-ref.xlsx differ diff --git a/spec/sheet_spec.rb b/spec/sheet_spec.rb index 6ecee45..dfb5fb9 100644 --- a/spec/sheet_spec.rb +++ b/spec/sheet_spec.rb @@ -102,6 +102,22 @@ def load_cell(rows, cell_name) expect(load_cell(rows, 'A10')).to eq(0.15) end end + + context 'when cell references are missing' do + let(:book_missing_refs) { Creek::Book.new('spec/fixtures/sample-missing-cell-ref.xlsx') } + let(:missing_refs_sheet) { book_missing_refs.sheets[0] } + + after { book_missing_refs.close } + + it 'infers cell references from column order' do + rows = missing_refs_sheet.rows.to_a + + expect(rows[0]['A1']).to eq('Content 1') + expect(rows[0]['C1']).to eq('Content 2') + expect(rows[5]['B6']).to eq('2') + expect(rows[5]['C6']).to eq('3') + end + end end describe '#images_at' do