weshatheleopard / rubyXL

Ruby lib for reading/writing/modifying .xlsx and .xlsm files
MIT License
1.27k stars 253 forks source link

= rubyXL {rdoc-image:https://badge.fury.io/rb/rubyXL.svg}[http://badge.fury.io/rb/rubyXL] {rdoc-image:https://codeclimate.com/github/weshatheleopard/rubyXL.png}[https://codeclimate.com/github/weshatheleopard/rubyXL] {rdoc-image:https://circleci.com/gh/weshatheleopard/rubyXL.svg?style=svg}[https://circleci.com/gh/weshatheleopard/rubyXL]

This gem supports operating on +xlsx+ files (Open XML format). While it is capable of properly parsing the entire OOXML structure, its current main emphasis is on reading files produced by MS Excel, making minor modifications to them and saving them to be opened again, while preserving as much of the structure as possible.

Please note that proprietary binary +xls+ format is not supported by this gem. If you need to parse those files, try {spreadsheet}[https://github.com/zdavatz/spreadsheet] gem.

== To Install: gem install rubyXL

== To Use: require 'rubyXL' # Assuming rubygems is already required

=== Convenience methods

Starting with version 3.4.0, the main data structure has been separated from the convenience methods that provide access to individual features of the +xlsx+ format, in order to decrease the memory footprint. If you intend to use these features, you will need to additionally include the respective files: require 'rubyXL/convenience_methods/cell' require 'rubyXL/convenience_methods/color' require 'rubyXL/convenience_methods/font' require 'rubyXL/convenience_methods/workbook' require 'rubyXL/convenience_methods/worksheet'

If you do not care about your RAM usage, just include them all at once by adding the following line to your code so it can continue operating just as before: require 'rubyXL/convenience_methods'

=== Parsing an existing workbook workbook = RubyXL::Parser.parse("path/to/Excel/file.xlsx")

=== Creating a new Workbook workbook = RubyXL::Workbook.new

=== Accessing

==== Accessing a Worksheet workbook.worksheets[0] # Returns first worksheet workbook[0] # Returns first worksheet workbook['Sheet1'] # Finds and returns worksheet titled "Sheet1". Note that sheet names in Excel are limited to 31 character.

==== Accessing a Row (Array of Cells) Please note that worksheet is a sparse array of rows. Your code must expect that any row it plucks from the array may be nil.

worksheet = workbook[0] worksheet.sheet_data[0] # Returns first row of the worksheet worksheet[0] # Returns first row of the worksheet

==== Accessing a Cell object Please note that row is a sparse array of cells. Your code must expect that any cell it plucks from the array may be nil.

worksheet = workbook[0] worksheet.sheet_data[0][0] # Returns cell A1 in the worksheet worksheet[0][0] # Returns cell A1 in the worksheet

cell = worksheet[0][0] cell.value # Returns a properly converted value in the cell (if the file claims that the cell

is holding a number, returns a respective Integer or Float, and so on).

Or, if you prefer Excel-style references (single-cell only!)

cell = worksheet.cell_at('B11')

==== Wrappers for accessing Cell properties cell = workbook[0][0][0] cell.is_struckthrough # Returns +true+ if the cell is struckthrough, other boolean properties have same syntax cell.font_name cell.font_size cell.font_color cell.fill_color cell.horizontal_alignment cell.vertical_alignment cell.get_border(:top) cell.get_border_color(:top) cell.text_rotation

==== Wrappers for accessing Row properties Please note: these methods are being phased out in favor of the OOXML object model. worksheet = workbook[0] worksheet.get_row_fill(0) worksheet.get_row_font_name(0) worksheet.get_row_font_size(0) worksheet.get_row_font_color(0) worksheet.is_row_underlined(0) worksheet.get_row_height(0) worksheet.get_row_alignment(0, true) worksheet.get_row_alignment(0, false) worksheet.get_row_border(0, :right) worksheet.get_row_border_color(0, :right)

==== Accessing column properties Please note: these methods are being phased out in favor of the OOXML object model. worksheet = workbook[0] worksheet.get_column_fill(0) worksheet.get_column_font_name(0) worksheet.get_column_font_size(0) worksheet.get_column_font_color(0) worksheet.is_column_underlined(0) worksheet.get_column_width(0) worksheet.get_column_alignment(0, :horizontal) worksheet.get_column_alignment(0, :vertical) worksheet.get_column_border(0, :right) worksheet.get_column_border_color(0, :right)

=== Modifying

==== Adding Worksheets worksheet = workbook.add_worksheet('Sheet2')

==== Renaming Worksheets worksheet.sheet_name = 'Cool New Name' # Note that sheet name is limited to 31 characters by Excel.

==== Adding Cells worksheet.add_cell(0, 0, 'A1') # Sets cell A1 to string "A1" worksheet.add_cell(0, 1, '', 'A1') # Sets formula in the cell B1 to '=A1'

==== Changing Cells worksheet[0][0].change_contents("", worksheet[0][0].formula) # Sets value of cell A1 to empty string, preserves formula

==== Changing Fonts worksheet.sheet_data[0][0].change_font_bold(true) # Makes A1 bold worksheet.change_row_italics(0,true) # Makes first row italicized worksheet.change_column_font_name(0, 'Courier') # Makes first column have font Courier

==== Changing Fills worksheet.sheet_data[0][0].change_fill('0ba53d') # Sets A1 to have fill #0ba53d worksheet.change_row_fill(0, '0ba53d') # Sets first row to have fill #0ba53d worksheet.change_column_fill(0, '0ba53d') # Sets first column to have fill #0ba53d

==== Changing Borders

Possible weights: hairline, thin, medium, thick

Possible "directions": top, bottom, left, right, diagonal

worksheet.sheet_data[0][0].change_border(:top, 'thin') # Sets A1 to have a top, thin border worksheet.change_row_border(0, :left, 'hairline') # Sets first row to have a left, hairline border worksheet.change_column_border(0, :diagonal, 'medium') # Sets first column to have diagonal, medium border

Set the border style first so there's something to color.

worksheet.change_row_border_color(0, :top, '0ba53d') # Sets first row to have a green top border worksheet.change_column_border_color(0, :top, '0ba53d') # Sets first column to have a green top border

==== Changing Alignment ===== Horizontal

Possible alignments: center, distributed, justify, left, right

worksheet.sheet_data[0][0].change_horizontal_alignment('center') # Sets A1 to be centered worksheet.change_row_horizontal_alignment(0, 'justify') # Sets first row to be justified worksheet.change_column_horizontal_alignment(0, 'right') # Sets first column to be right-aligned

===== Vertical

Possible alignments: bottom, center, distributed, top

worksheet.sheet_data[0][0].change_vertical_alignment('bottom') # Sets A1 to be bottom aligned worksheet.change_row_vertical_alignment(0, 'distributed') # Sets first row to be distributed vertically worksheet.change_column_vertical_alignment(0, 'top') # Sets first column to be top aligned

===== Rotation

Possible values:

* 0-90 - degrees counterclockwise, around the bottom LEFT corner of the cell;

* 91-179 - degrees clockwise, around the bottom RIGHT corner of the cell;

* 180-254 - degrees clockwise, around the bottom LEFT corner of the cell, text becomes progressively invisible

* 255 - text is in normal rotation but displayed vertically (one letter under another), line feed starts new line to the right of the previous.

worksheet.sheet_data[0][0].change_text_rotation(90) # Sets A1 to be rotated by 90 degrees

==== Changing Row Height worksheet.change_row_height(0, 30) # Sets first row height to 30

==== Changing Column Width worksheet.change_column_width(0, 30) # Sets first column width to 30

==== Merging Cells worksheet.merge_cells(0, 0, 1, 1) # Merges A1:B2

==== Insert Row This method will insert a row at specified index, pushing all rows below it down. It also copies styles from row above.

WARNING: Use of this method WILL break formulas referencing cells which have been moved, as the formulas do not adapt to the shifted rows worksheet.insert_row(1)

==== Insert Column This method will insert a column at specified index, pushing all columns to the right of it one to the right. It also copies styles from column to the left

WARNING: Use of this method WILL break formulas referencing cells which have been moved, as the formulas do not adapt to the shifted columns worksheet.insert_column(1)

==== Delete Row This method will delete a row at specified index, pushing all rows below it up.

WARNING: Use of this method WILL break formulas referencing cells which have been moved, as the formulas do not adapt to the shifted rows worksheet.delete_row(1)

==== Delete Column This method will delete a column at specified index, pushing all columns to the right of it left.

WARNING: Use of this method WILL break formulas referencing cells which have been moved, as the formulas do not adapt to the shifted columns worksheet.delete_column(1)

==== Insert Cell This method will insert a cell at specified position. It takes a :right or :down option, to shift cells either left or down upon inserting (nil means replacing the cell)

WARNING: Use of this method WILL break formulas referencing cells which have been moved, as the formulas do not adapt to the shifted cells worksheet.insert_cell(0, 0, "blah", formula = nil, :right) # Inserts cell at A1, shifts cells in first row right worksheet.insert_cell(0, 0, "blah", formula = nil, :down) # Inserts cell at A1, shifts cells in first column down worksheet.insert_cell(0, 0, "blah") # Inserts cell at A1, shifts nothing

==== Delete Cell This method will delete a cell at specified position. It takes a :left or :up option, to shift cells either up or left upon deletion (nil means simply deleting the cell contents)

WARNING: Use of this method WILL break formulas referencing cells which have been moved, as the formulas do not adapt to the shifted cells worksheet.delete_cell(0, 0, :left) # Deletes A1, shifts contents of first row left worksheet.delete_cell(0, 0, :up) # Deletes A1, shifts contents of first column up worksheet.delete_cell(0, 0) # Deletes A1, does not shift cells

==== Modifying Cell Format cell = worksheet[0][0] cell.set_number_format '0.0000%' # For formats, see https://support.office.com/en-us/article/5026bbd6-04bc-48cd-bf33-80f18b4eae68 cell.change_text_wrap(true) # Makes the text in the cell to wrap. cell.change_shrink_to_fit(true) # Makes the text in the cell to shrink to fit. cell.change_text_indent(1) # Indents the text in the cell by 1 level

==== Add hyperlink to a Cell cell.add_hyperlink('http://example.com') cell.add_hyperlink('http://example.com', 'Some tooltip text')

== I/O

By default, the gem operates with files on the local filesystem:

workbook = RubyXL::Parser.parse("path/to/Excel/file.xlsx") workbook.write("path/to/desired/Excel/file.xlsx")

It can also operate on +StringIO+ objects, thus eliminating the need to save the +xlsx+ file to disk. This capability comes in handy for web servers.

workbook = RubyXL::Parser.parse_buffer(buffer) workbook.stream

== Miscellaneous RubyXL::Reference.ind2ref(0,0) == 'A1' # Converts row and column index to Excel-style cell reference RubyXL::Reference.ref2ind('A1') == [0, 0] # Converts Excel-style cell reference to row and column index

=== Suppress warnings about malformed input files

RubyXL.class_variable_set(:@@suppress_warnings, true)

== Data validation (colloquially referred to as "dropdown list")

worksheet.add_validation_list("A1", [ "value1", "value2" ])

== For more information Take a look at the files in spec/lib/ for rspecs on most methods

== Contributing to rubyXL

== Copyright

Copyright (c) 2011 Vivek Bhagwat, 2013-2022 Wesha. See LICENSE.txt for further details.