[Awesome Ruby Gem] Use spreadsheet to read and write Spreadsheet Documents
spreadsheet
spreadsheet
is a Library is designed to read and write Spreadsheet Documents. As of version 0.6.0, only Microsoft Excel compatible spreadsheets are supported. Spreadsheet is a combination/complete rewrite of the Spreadsheet::Excel
Library by Daniel J. Berger and the ParseExcel Library by Hannes Wyss. Spreadsheet can read, write and modify Spreadsheet Documents.
Installation
You can install it as a gem:
1 | gem install spreadsheet |
or add it into a Gemfile (Bundler):
1 | # Gemfile |
Then, run bundle install
.
1 | bundle install |
Usages
Before you can do anything, you first need to make sure all that code is loaded:
1 | require 'spreadsheet' |
Encoding
Worksheets come in various encodings. You need to tell Spreadsheet which encoding you want to deal with. The default is UTF-8
1 | Spreadsheet.client_encoding = 'UTF-8' |
Workbook
Let’s open a workbook:
1 | book = Spreadsheet.open '/path/to/an/excel-file.xls' |
We can either access all the worksheets in a workbook…
1 | book.worksheets |
…or access them by index or name (encoded in your client_encoding).
1 | sheet1 = book.worksheet 0 |
Row
Now you can either iterate over all rows that contain some data. A call to Worksheet.each
without arguments will omit empty rows at the beginning of the worksheet:
1 | sheet1.each do |row| |
You can either iterate over all rows that contain some data and index (0-based):
1 | sheet2.each_with_index do |row, index| |
Or you can tell a worksheet how many rows should be omitted at the beginning. The following starts at the 3rd row, regardless of whether or not it or the preceding rows contain any data:
1 | sheet2.each 2 do |row| |
Or you can access rows directly, by their index (0-based):
1 | row = sheet1.row(3) |
To access the values stored in a row, treat the row like an array.
1 | row[0] |
This will return a String
, a Float
, an Integer
, a Formula
, a Link
or a Date
or DateTime
object - or nil
if the cell is empty.
More information about the formatting of a cell can be found in the format with the equivalent index:
1 | row.format 2 |
Writing is easy
As before, make sure you have Spreadsheet required and the client_encoding set. Then make a new Workbook:
1 | book = Spreadsheet::Workbook.new |
Add a Worksheet and you’re good to go:
1 | sheet1 = book.create_worksheet |
This will create a Worksheet with the Name “Worksheet1”. If you prefer another name, you may do either of the following:
1 | sheet2 = book.create_worksheet :name => 'My Second Worksheet' |
Now, add data to the Worksheet, using either Worksheet#[]=
, Worksheet#update_row
, or work directly on Row using any of the Array-Methods that modify an Array in place:
1 | sheet1.row(0).concat %w{Name Country Acknowlegement} |
Add some Formatting for flavour:
1 | sheet1.row(0).height = 18 |
And finally, write the Excel File:
1 | book.write '/path/to/output/excel-file.xls' |
Modifying an existing Document
Spreadsheet has some limited support for modifying an existing Document. This is done by copying verbatim those parts of an Excel-document which Spreadsheet can’t modify (yet), recalculating relevant offsets, and writing the data that can be changed. Here’s what should work:
-
Adding, changing and deleting cells.
-
You should be able to fill in Data to be evaluated by predefined Formulas
Limitations:
-
Spreadsheet can only write BIFF8 (Excel97 and higher). The results of modifying an earlier version of Excel are undefined.
-
Spreadsheet does not modify Formatting at present. That means in particular that if you set the Value of a Cell to a Date, it can only be read as a Date if its Format was set correctly prior to the change.
-
Although it is theoretically possible, it is not recommended to write the resulting Document back to the same File/IO that it was read from.
And here’s how it works:
1 | book = Spreadsheet.open '/path/to/an/excel-file.xls' |
Or you can directly access the cell that you want and add your text on it:
1 | sheet.rows[2][1] = "X" |
Date and DateTime
Excel does not know a separate Datatype for Dates. Instead it encodes Dates into standard floating-point numbers and recognizes a Date-Cell by its formatting-string:
1 | row.format(3).number_format |
Whenever a Cell’s Format describes a Date or Time, Spreadsheet will give you the decoded Date or DateTime value. Should you need to access the underlying Float, you may do the following:
1 | row.at(3) |
If for some reason the Date-recognition fails, you may force Date-decoding:
1 | row.date(3) |
When you set the value of a Cell to a Date, Time or DateTime, Spreadsheet will try to set the cell’s number-format to a corresponding value (one of Excel’s builtin formats). If you have already defined a Date- or DateTime-format, Spreadsheet will use that instead. If a format has already been applied to a particular Cell, Spreadsheet will leave it untouched:
1 | row[4] = Date.new 1975, 8, 21 |
Outline (Grouping) and Hiding
Spreadsheet supports outline (grouping) and hiding functions from version 0.6.5. In order to hide rows or columns, you can use ‘hidden’ property. As for outline, ‘outline_level’ property is also available. You can use both ‘hidden’ and ‘outline_level’ at the same time.
You can create a new file with outline and hiding rows and columns as follows:
1 | require 'spreadsheet' |
Also you can read an existing file and change the hidden and outline properties. Here is the example below:
1 | require 'spreadsheet' |
Page setup (for printing)
1 | sheet.pagesetup[:orientation] = :landscape # or :portrait (default) |
References
[2] spreadsheet | RubyGems.org | your community gem host - https://rubygems.org/gems/spreadsheet/
[3] The Ruby Spreadsheet | Writing and Reading Spreadsheets with Ruby - https://spreadsheet.ch/