roo-rb / roo

Roo provides an interface to spreadsheets of several sorts.
MIT License
2.78k stars 503 forks source link

Roo::Excelx::Cell::Empty#to_s does not return a string #539

Open jackrg opened 4 years ago

jackrg commented 4 years ago

Empty Cell Sample.xlsx

Thanks for filing an issue. Following these instructions will help us solve your problem sooner.

Steps to reproduce

Run the following code (this example in Rails):

xlsx = Roo::Excelx.new("./Empty Cell Sample.xlsx")

xlsx.each_row_streaming(pad_cells: true) do |row|
  puts row.map { |c| c.class.name }
  puts row.map { |c| c.to_s.class.name }
end

Output: irb(main):006:0> load 'EmptyCellExample.rb' Roo::Excelx::Cell::Empty Roo::Excelx::Cell::String Roo::Excelx::Cell::String Roo::Excelx::Cell::String Roo::Excelx::Cell::String Roo::Excelx::Cell::String Roo::Excelx::Cell::String Roo::Excelx::Cell::String Roo::Excelx::Cell::String Roo::Excelx::Cell::Empty Roo::Excelx::Cell::String Roo::Excelx::Cell::Empty NilClass String String String String String String String String NilClass String NilClass => true

Issue

Calling #to_s on a cell that is represented by Roo::Excelx::Cell::Empty produces nil instead of an empty string. Basic to Ruby is the tenet that calling #to_s produces a string. Workaround is to call #to_s twice (e.g. "cell.to_s.to_s")

System configuration

Roo version: 2.5.1

Ruby version: 2.0.0.p576 Empty Cell Sample.xlsx

jackrg commented 4 years ago

I'm going to leave this open as the basis for a strategic/tactical discussion, while I recognize that the library works as documented. The principle of "least surprise" applies here, as you would expect #each_row_streaming to return the same sort of values as #each.

jackrg commented 4 years ago

Just discovered another "gotcha". It looks like if the entire first column is blank (that is, it would have been eliminated if not for "pad_cells: true" in the call), each row contains a nil instead of Roo::Excelx::Cell::Empty. This means that I can't just map each cell using #value, i have to surround it with a #try (e.g. row.map! {|c| c.try(:value) } instead of row.map!(&:value).

plusor commented 2 years ago

I was confused when occurred this error.