README.rdoc 12.5 KB
Newer Older
Christopher Huhn's avatar
Christopher Huhn committed
1
2
3
= rubyXL
{<img src="https://badge.fury.io/rb/rubyXL.svg" alt="Gem Version" />}[http://badge.fury.io/rb/rubyXL]
{<img src="https://codeclimate.com/github/weshatheleopard/rubyXL.png" alt="Code Climate" />}[https://codeclimate.com/github/weshatheleopard/rubyXL]
Christopher Huhn's avatar
Christopher Huhn committed
4
{<img src="https://circleci.com/gh/weshatheleopard/rubyXL.svg?style=svg" alt="CircleCI" />}[https://circleci.com/gh/weshatheleopard/rubyXL]
Christopher Huhn's avatar
Christopher Huhn committed
5
6
7
8
9
10

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.

Christopher Huhn's avatar
Christopher Huhn committed
11
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.
Christopher Huhn's avatar
Christopher Huhn committed
12
13
14
15
16
17
18

== To Install:
  gem install rubyXL

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

Christopher Huhn's avatar
Christopher Huhn committed
19
20
21
22
23
24
25
26
27
28
29
30
=== 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'

Christopher Huhn's avatar
Christopher Huhn committed
31
32
33
34
35
36
37
38
39
40
41
=== 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
Christopher Huhn's avatar
Christopher Huhn committed
42
  workbook['Sheet1']     # Finds and returns worksheet titled "Sheet1". Note that sheet names in Excel are limited to 31 character.
Christopher Huhn's avatar
Christopher Huhn committed
43
44

==== Accessing a Row (Array of Cells)
Christopher Huhn's avatar
Christopher Huhn committed
45
46
Please note that worksheet is a _sparse_ array of rows. Your code *must* expect that any row it plucks from the array may be <tt>nil</tt>.

Christopher Huhn's avatar
Christopher Huhn committed
47
48
49
50
51
  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
Christopher Huhn's avatar
Christopher Huhn committed
52
53
Please note that row is a _sparse_ array of cells. Your code *must* expect that any cell it plucks from the array may be <tt>nil</tt>.

Christopher Huhn's avatar
Christopher Huhn committed
54
55
56
57
  worksheet = workbook[0]
  worksheet.sheet_data[0][0] # Returns cell A1 in the worksheet
  worksheet[0][0]            # Returns cell A1 in the worksheet

Christopher Huhn's avatar
Christopher Huhn committed
58
59
60
61
62
63
64
65
  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')

Christopher Huhn's avatar
Christopher Huhn committed
66
67
68
69
70
71
72
73
74
==== 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
Christopher Huhn's avatar
Christopher Huhn committed
75
76
77
  cell.get_border(:top)
  cell.get_border_color(:top)
  cell.text_rotation
Christopher Huhn's avatar
Christopher Huhn committed
78
79
80
81
82
83
84
85
86
87

==== 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)
Christopher Huhn's avatar
Christopher Huhn committed
88
89
90
91
  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)
Christopher Huhn's avatar
Christopher Huhn committed
92
93
94
95
96
97
98
99
100
101

==== 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)
Christopher Huhn's avatar
Christopher Huhn committed
102
103
104
105
  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)
Christopher Huhn's avatar
Christopher Huhn committed
106
107
108
109
110
111
112

=== Modifying

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

==== Renaming Worksheets
Christopher Huhn's avatar
Christopher Huhn committed
113
  worksheet.sheet_name = 'Cool New Name' # Note that sheet name is limited to 31 characters by Excel.
Christopher Huhn's avatar
Christopher Huhn committed
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

==== 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

Christopher Huhn's avatar
Christopher Huhn committed
139
140
141
142
  # 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

Christopher Huhn's avatar
Christopher Huhn committed
143
144
==== Changing Alignment
===== Horizontal
Christopher Huhn's avatar
Christopher Huhn committed
145
  # Possible alignments: center, distributed, justify, left, right
Christopher Huhn's avatar
Christopher Huhn committed
146
147
148
149
150
  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
Christopher Huhn's avatar
Christopher Huhn committed
151
  # Possible alignments: bottom, center, distributed, top
Christopher Huhn's avatar
Christopher Huhn committed
152
153
154
  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
Christopher Huhn's avatar
Christopher Huhn committed
155
156
157
158
159
160
161
162
  
===== 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
Christopher Huhn's avatar
Christopher Huhn committed
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212

==== 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

Christopher Huhn's avatar
Christopher Huhn committed
213
214
215
216
217
218
219
220
221
222
223
224
==== 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')


Christopher Huhn's avatar
Christopher Huhn committed
225
226
== I/O

Christopher Huhn's avatar
Christopher Huhn committed
227
228
229
By default, the gem operates with files on the local filesystem:

  workbook = RubyXL::Parser.parse("path/to/Excel/file.xlsx")
Christopher Huhn's avatar
Christopher Huhn committed
230
231
  workbook.write("path/to/desired/Excel/file.xlsx")

Christopher Huhn's avatar
Christopher Huhn committed
232
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.
Christopher Huhn's avatar
Christopher Huhn committed
233

Christopher Huhn's avatar
Christopher Huhn committed
234
  workbook = RubyXL::Parser.parse_buffer(buffer)
Christopher Huhn's avatar
Christopher Huhn committed
235
236
237
  workbook.stream

== Miscellaneous
Christopher Huhn's avatar
Christopher Huhn committed
238
239
240
241
242
243
244
245
246
247
  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" ])
Christopher Huhn's avatar
Christopher Huhn committed
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263

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

== Contributing to rubyXL
 
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
* Fork the project
* Start a feature/bugfix branch
* Commit and push until you are happy with your contribution
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.

== Copyright

Christopher Huhn's avatar
Christopher Huhn committed
264
Copyright (c) 2011 Vivek Bhagwat, 2013-2022 Wesha.
Christopher Huhn's avatar
Christopher Huhn committed
265
See LICENSE.txt for further details.