rubyexcel 0.1.4 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/rubyexcel/section.rb +13 -1
- data/lib/rubyexcel/sheet.rb +1 -1
- data/lib/rubyexcel.rb +24 -7
- metadata +2 -3
- data/lib/README.md +0 -630
data/lib/rubyexcel/section.rb
CHANGED
|
@@ -252,7 +252,7 @@ module RubyExcel
|
|
|
252
252
|
#
|
|
253
253
|
# Find a value in this Row by its header
|
|
254
254
|
#
|
|
255
|
-
# @param [String]header the header to search for
|
|
255
|
+
# @param [String] header the header to search for
|
|
256
256
|
# @return [Object] the value at the address
|
|
257
257
|
#
|
|
258
258
|
|
|
@@ -260,6 +260,18 @@ module RubyExcel
|
|
|
260
260
|
self[ getref( header ) ]
|
|
261
261
|
end
|
|
262
262
|
alias val value_by_header
|
|
263
|
+
|
|
264
|
+
#
|
|
265
|
+
# Set a value in this Row by its header
|
|
266
|
+
#
|
|
267
|
+
# @param [String] header the header to search for
|
|
268
|
+
# @param [Object] val the value to write
|
|
269
|
+
#
|
|
270
|
+
|
|
271
|
+
def set_value_by_header( header, val )
|
|
272
|
+
self[ getref( header ) ] = val
|
|
273
|
+
end
|
|
274
|
+
alias set_val set_value_by_header
|
|
263
275
|
|
|
264
276
|
private
|
|
265
277
|
|
data/lib/rubyexcel/sheet.rb
CHANGED
|
@@ -534,7 +534,7 @@ module RubyExcel
|
|
|
534
534
|
#
|
|
535
535
|
|
|
536
536
|
def to_html
|
|
537
|
-
|
|
537
|
+
%Q|<table border=1>\n<caption>#@name</caption>\n| + data.map { |row| '<tr>' + row.map { |v| '<td>' + CGI.escapeHTML(v.to_s) }.join }.join("\n") + "\n</table>"
|
|
538
538
|
end
|
|
539
539
|
|
|
540
540
|
#
|
data/lib/rubyexcel.rb
CHANGED
|
@@ -113,6 +113,15 @@ module RubyExcel
|
|
|
113
113
|
wb
|
|
114
114
|
end
|
|
115
115
|
|
|
116
|
+
#
|
|
117
|
+
# Yields each Sheet.
|
|
118
|
+
#
|
|
119
|
+
|
|
120
|
+
def each
|
|
121
|
+
return to_enum( :each ) unless block_given?
|
|
122
|
+
@sheets.each { |s| yield s }
|
|
123
|
+
end
|
|
124
|
+
|
|
116
125
|
#
|
|
117
126
|
# Check whether the workbook has Sheets
|
|
118
127
|
#
|
|
@@ -136,14 +145,23 @@ module RubyExcel
|
|
|
136
145
|
#
|
|
137
146
|
# Select a Sheet or iterate through them
|
|
138
147
|
#
|
|
139
|
-
# @param [Fixnum, String, nil] ref the reference to select a Sheet by
|
|
148
|
+
# @param [Fixnum, String, Regexp, nil] ref the reference to select a Sheet by
|
|
140
149
|
# @return [RubyExcel::Sheet] if a search term was given
|
|
141
150
|
# @return [Enumerator] if nil or no argument given
|
|
151
|
+
# @yield [RubyExcel::Sheet] yields each sheet, if there is no argument and a block is given
|
|
142
152
|
#
|
|
143
153
|
|
|
144
154
|
def sheets( ref=nil )
|
|
145
|
-
|
|
146
|
-
|
|
155
|
+
if ref.nil?
|
|
156
|
+
return to_enum (:each) unless block_given?
|
|
157
|
+
each { |s| yield s }
|
|
158
|
+
else
|
|
159
|
+
case ref
|
|
160
|
+
when Fixnum ; @sheets[ ref - 1 ]
|
|
161
|
+
when String ; @sheets.find { |s| s.name =~ /^#{ ref }$/i }
|
|
162
|
+
when Regexp ; @sheets.find { |s| s.name =~ ref }
|
|
163
|
+
end
|
|
164
|
+
end
|
|
147
165
|
end
|
|
148
166
|
|
|
149
167
|
# {Workbook#sort!}
|
|
@@ -175,12 +193,11 @@ module RubyExcel
|
|
|
175
193
|
end
|
|
176
194
|
|
|
177
195
|
#
|
|
178
|
-
#
|
|
196
|
+
# The Workbook as a group of HTML Tables
|
|
179
197
|
#
|
|
180
198
|
|
|
181
|
-
def
|
|
182
|
-
|
|
183
|
-
@sheets.each { |s| yield s }
|
|
199
|
+
def to_html
|
|
200
|
+
map(&:to_html).join('</br>')
|
|
184
201
|
end
|
|
185
202
|
|
|
186
203
|
end # Workbook
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubyexcel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.5
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2013-05-
|
|
12
|
+
date: 2013-05-10 00:00:00.000000000 Z
|
|
13
13
|
dependencies: []
|
|
14
14
|
description: A tabular data structure in Ruby, with header-based helper methods and
|
|
15
15
|
some of Excel's API style. Designed for Windows + Excel.
|
|
@@ -26,7 +26,6 @@ files:
|
|
|
26
26
|
- lib/rubyexcel/section.rb
|
|
27
27
|
- lib/rubyexcel/sheet.rb
|
|
28
28
|
- lib/rubyexcel.rb
|
|
29
|
-
- lib/README.md
|
|
30
29
|
homepage: https://github.com/VirtuosoJoel
|
|
31
30
|
licenses: []
|
|
32
31
|
post_install_message:
|
data/lib/README.md
DELETED
|
@@ -1,630 +0,0 @@
|
|
|
1
|
-
RubyExcel
|
|
2
|
-
=========
|
|
3
|
-
|
|
4
|
-
Designed for Ruby on Windows with MS Excel
|
|
5
|
-
|
|
6
|
-
Introduction
|
|
7
|
-
------------
|
|
8
|
-
|
|
9
|
-
A Data-analysis tool for Ruby, with an Excel-style API.
|
|
10
|
-
|
|
11
|
-
You can find the gem [here](https://rubygems.org/gems/rubyexcel "Rubygems").
|
|
12
|
-
|
|
13
|
-
Main documentation is [here](http://rubydoc.info/gems/rubyexcel "Rubydoc")
|
|
14
|
-
|
|
15
|
-
For any requests, comments, etc. I keep an eye on [this forum](http://www.ruby-forum.com/forum/ruby "Ruby Mailing List").
|
|
16
|
-
If you put "RubyExcel" in the subject title I should see it.
|
|
17
|
-
|
|
18
|
-
Please feel free to log any bugs you find [here](https://github.com/VirtuosoJoel/RubyExcel/issues "Bug Tracker").
|
|
19
|
-
|
|
20
|
-
Details
|
|
21
|
-
-----
|
|
22
|
-
|
|
23
|
-
Key design features taken from Excel:
|
|
24
|
-
|
|
25
|
-
* 1-based indexing.
|
|
26
|
-
* Referencing objects like Excel's API ( Workbook, Sheet, Row, Column, Cell, Range ).
|
|
27
|
-
* Useful data-handling functions ( e.g. Filter, Match, Sumif, Vlookup ).
|
|
28
|
-
|
|
29
|
-
Typical usage:
|
|
30
|
-
|
|
31
|
-
1. Extract a HTML Table or CSV File into 2D Array ( normally with Nokogiri / Mechanize ).
|
|
32
|
-
2. Organise and interpret data with RubyExcel.
|
|
33
|
-
3. Output results into a file.
|
|
34
|
-
|
|
35
|
-
About
|
|
36
|
-
-----
|
|
37
|
-
|
|
38
|
-
This gem is designed as a way to conveniently edit table data before outputting it to Excel (XLSX) or TSV format (which Excel can interpret).
|
|
39
|
-
It attempts to take as much as possible from Excel's API while providing some of the best bits of Ruby ( e.g. Enumerators, Blocks, Regexp ).
|
|
40
|
-
An important feature is allowing reference to Columns via their Headers for convenience and enhanced code readability.
|
|
41
|
-
As this works directly on the data, processing is faster than using Excel itself.
|
|
42
|
-
|
|
43
|
-
This was written out of the frustration of editing tabular data using Ruby's multidimensional arrays,
|
|
44
|
-
without affecting headers and while maintaining code readability.
|
|
45
|
-
Its API is designed to simplify moving code across from VBA into Ruby format when processing spreadsheet data.
|
|
46
|
-
The combination of Ruby, WIN32OLE Excel, and analysing table data is probably quite rare; but I thought I'd share what I came up with.
|
|
47
|
-
|
|
48
|
-
Examples
|
|
49
|
-
========
|
|
50
|
-
|
|
51
|
-
Expected Data Layout (2D Array)
|
|
52
|
-
--------
|
|
53
|
-
|
|
54
|
-
```ruby
|
|
55
|
-
data = [
|
|
56
|
-
[ 'Part', 'Ref1', 'Ref2', 'Qty', 'Cost' ],
|
|
57
|
-
[ 'Type1', 'QT1', '231', 1, 35.15 ],
|
|
58
|
-
[ 'Type2', 'QT3', '123', 1, 40 ],
|
|
59
|
-
[ 'Type3', 'XT1', '321', 3, 0.1 ],
|
|
60
|
-
[ 'Type1', 'XY2', '132', 1, 30.00 ],
|
|
61
|
-
[ 'Type4', 'XT3', '312', 2, 3 ],
|
|
62
|
-
[ 'Type2', 'QY2', '213', 1, 99.99 ],
|
|
63
|
-
[ 'Type1', 'QT4', '123', 2, 104 ]
|
|
64
|
-
]
|
|
65
|
-
```
|
|
66
|
-
The number of header rows defaults to 1
|
|
67
|
-
|
|
68
|
-
Loading the data into a Sheet
|
|
69
|
-
--------
|
|
70
|
-
|
|
71
|
-
```ruby
|
|
72
|
-
require 'rubyexcel'
|
|
73
|
-
|
|
74
|
-
wb = RubyExcel::Workbook.new
|
|
75
|
-
s = wb.add( 'Sheet1' )
|
|
76
|
-
s.load( data )
|
|
77
|
-
|
|
78
|
-
Or:
|
|
79
|
-
|
|
80
|
-
wb = RubyExcel::Workbook.new
|
|
81
|
-
s = wb.add( 'Sheet1' )
|
|
82
|
-
s.load( RubyExcel.sample_data )
|
|
83
|
-
|
|
84
|
-
Or:
|
|
85
|
-
|
|
86
|
-
wb = RubyExcel::Workbook.new
|
|
87
|
-
s = wb.load( RubyExcel.sample_data )
|
|
88
|
-
|
|
89
|
-
Or:
|
|
90
|
-
|
|
91
|
-
s = RubyExcel.sample_sheet
|
|
92
|
-
wb = s.parent
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
Using the Mechanize gem to get data
|
|
96
|
-
--------
|
|
97
|
-
|
|
98
|
-
This example is for context, there are many potential data sources
|
|
99
|
-
|
|
100
|
-
```ruby
|
|
101
|
-
s = RubyExcel::Workbook.new.load( CSV.parse( Mechanize.new.get('http://example.com/myfile.csv').content ) )
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
Reference a cell's value
|
|
105
|
-
--------
|
|
106
|
-
|
|
107
|
-
```ruby
|
|
108
|
-
s['A7']
|
|
109
|
-
s.A7
|
|
110
|
-
s.cell(7,1).value
|
|
111
|
-
s.range('A7').value
|
|
112
|
-
s.row(7)['A']
|
|
113
|
-
s.row(7)[1]
|
|
114
|
-
s.column('A')[7]
|
|
115
|
-
s.column('A')['7']
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Reference a group of cells
|
|
119
|
-
--------
|
|
120
|
-
|
|
121
|
-
```ruby
|
|
122
|
-
s['A1:B3'] #=> Array
|
|
123
|
-
s.range( 'A1:B3' ) #=> Element
|
|
124
|
-
s.range( 'A:A' ) #=> Element (Column)
|
|
125
|
-
s.range( '1:2' ) #=> Element (Rows)
|
|
126
|
-
s.range( 'A1', 'B3' ) #=> Element
|
|
127
|
-
s.range( s.cell( 1, 1 ), s.cell( 3, 2 ) ) #=> Element
|
|
128
|
-
s.row( 1 ) #=> Row
|
|
129
|
-
s.column( 'A' ) #=> Column
|
|
130
|
-
s.column( 1 ) #=> Column
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
Common Operations
|
|
134
|
-
--------
|
|
135
|
-
|
|
136
|
-
```ruby
|
|
137
|
-
#Some data to play with
|
|
138
|
-
s = RubyExcel.sample_sheet
|
|
139
|
-
|
|
140
|
-
#Have a look at the data
|
|
141
|
-
puts s
|
|
142
|
-
|
|
143
|
-
#Append a Column by adding a header
|
|
144
|
-
s << 'Number'
|
|
145
|
-
|
|
146
|
-
#Iterate through the rest of the rows while appending data
|
|
147
|
-
x = 1
|
|
148
|
-
s.rows(2) { |row| row << x; x+=1 }
|
|
149
|
-
|
|
150
|
-
#Filter to specific part numbers
|
|
151
|
-
s.filter!( 'Part', &/Type[1-3]/ )
|
|
152
|
-
|
|
153
|
-
#Sort by Part Number
|
|
154
|
-
s.sort_by!( 'Part' )
|
|
155
|
-
|
|
156
|
-
#Add the Number to the Cost in each row.
|
|
157
|
-
s.rows(2) { |row| row.cell_h('Cost').value += row.cell_h('Number').value }
|
|
158
|
-
|
|
159
|
-
#Split the data into multiple sheets by part number
|
|
160
|
-
wb = s.split( 'Part' )
|
|
161
|
-
|
|
162
|
-
#Open a sheet in an Excel Workbook
|
|
163
|
-
#Output a sheet as a TSV file
|
|
164
|
-
File.write( 'Output.txt', wb.sheets(1).to_s )
|
|
165
|
-
|
|
166
|
-
#Output a sheet as an HTML page
|
|
167
|
-
File.write( 'Output.htm', wb.sheets(2).to_html )
|
|
168
|
-
|
|
169
|
-
#Open a sheet in an Excel Workbook
|
|
170
|
-
wb.sheets( 'Type3' ).to_excel
|
|
171
|
-
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
Workbook
|
|
175
|
-
--------
|
|
176
|
-
|
|
177
|
-
```ruby
|
|
178
|
-
#Create a workbook
|
|
179
|
-
wb = RubyExcel::Workbook.new
|
|
180
|
-
|
|
181
|
-
#Add sheets to the workbook
|
|
182
|
-
sheet1, sheet2 = wb.add('Sheet1'), wb.add
|
|
183
|
-
|
|
184
|
-
#Delete all sheets from a workbook
|
|
185
|
-
wb.clear_all
|
|
186
|
-
|
|
187
|
-
#Delete a specific sheet
|
|
188
|
-
wb.delete( 1 )
|
|
189
|
-
wb.delete( 'Sheet1' )
|
|
190
|
-
wb.delete( sheet1 )
|
|
191
|
-
wb.delete( /sheet1/i )
|
|
192
|
-
|
|
193
|
-
#Shortcut to create a sheet with a default name and fill it with data
|
|
194
|
-
wb.load( data )
|
|
195
|
-
|
|
196
|
-
#Select a sheet
|
|
197
|
-
wb.sheets(1) #=> RubyExcel::Sheet
|
|
198
|
-
wb.sheets('Sheet1') #=> RubyExcel::Sheet
|
|
199
|
-
|
|
200
|
-
#Iterate through all sheets
|
|
201
|
-
wb.sheets #=> Enumerator
|
|
202
|
-
wb.each #=> Enumerator
|
|
203
|
-
|
|
204
|
-
#Sort the sheets
|
|
205
|
-
wb.sort! { |x,y| x.name <=> y.name }
|
|
206
|
-
wb.sort_by! &:name
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
Sheet
|
|
210
|
-
--------
|
|
211
|
-
|
|
212
|
-
```ruby
|
|
213
|
-
#Create a sheet
|
|
214
|
-
s = wb.add #Name defaults to 'Sheet' + total number of sheets
|
|
215
|
-
s = wb.add( 'Sheet1' )
|
|
216
|
-
|
|
217
|
-
#Access the sheet name
|
|
218
|
-
s.name #=> 'Sheet1'
|
|
219
|
-
s.name = 'Sheet1'
|
|
220
|
-
|
|
221
|
-
#Access the parent workbook
|
|
222
|
-
s.workbook
|
|
223
|
-
s.parent
|
|
224
|
-
|
|
225
|
-
#Access the headers
|
|
226
|
-
s.header_rows #=> 1
|
|
227
|
-
s.headers #=> 1
|
|
228
|
-
s.headers = 1
|
|
229
|
-
s.header_rows = 1
|
|
230
|
-
|
|
231
|
-
#Specify the number of header rows when loading data
|
|
232
|
-
s.load( data, 1 )
|
|
233
|
-
|
|
234
|
-
#Append data (at the bottom of the sheet)
|
|
235
|
-
s << data
|
|
236
|
-
s << s
|
|
237
|
-
s += data
|
|
238
|
-
s += s
|
|
239
|
-
|
|
240
|
-
#Remove identical rows in another data set (skipping any headers)
|
|
241
|
-
s -= data
|
|
242
|
-
s -= s
|
|
243
|
-
|
|
244
|
-
#Select a column by its header
|
|
245
|
-
s.column_by_header( 'Part' )
|
|
246
|
-
s.ch( 'Part' )
|
|
247
|
-
#=> Column
|
|
248
|
-
|
|
249
|
-
#Iterate through rows or columns
|
|
250
|
-
s.rows { |r| puts r } #All rows
|
|
251
|
-
s.rows( 2 ) { |r| puts r } #From the 2nd to the last row
|
|
252
|
-
s.rows( 1, 3 ) { |r| puts r } #Rows 1 to 3
|
|
253
|
-
s.columns { |c| puts c } #All columns
|
|
254
|
-
s.columns( 'B' ) { |c| puts c } #From the 2nd to the last column
|
|
255
|
-
s.columns( 2 ) { |c| puts c } #From the 2nd to the last column
|
|
256
|
-
s.columns( 'B', 'D' ) { |c| puts c } #Columns 2 to 4
|
|
257
|
-
s.columns( 2, 4 ) { |c| puts c } #Columns 2 to 4
|
|
258
|
-
|
|
259
|
-
#Remove all empty rows & columns
|
|
260
|
-
s.compact!
|
|
261
|
-
|
|
262
|
-
#Delete the current sheet from the workbook
|
|
263
|
-
s.delete
|
|
264
|
-
|
|
265
|
-
#Delete rows or columns "if( condition )" (iterates in reverse to preserve references during loop)
|
|
266
|
-
s.delete_rows_if { |r| r.empty? }
|
|
267
|
-
s.delete_columns_if { |c| c.empty? }
|
|
268
|
-
|
|
269
|
-
#Filter the data given a column and a block to test values against.
|
|
270
|
-
#Note: Returns a copy of the sheet when used without "!".
|
|
271
|
-
#Note: This gem carries a Regexp to_proc method for Regex shorthand (shown below).
|
|
272
|
-
s.filter!( 'Part' ) { |value| value =~ /Type[13]/ }
|
|
273
|
-
s.filter!( 'Part', &/Type[13]/ )
|
|
274
|
-
|
|
275
|
-
#Filter the data to a specific set of columns by their headers.
|
|
276
|
-
#Note: Returns a copy of the sheet when used without "!".
|
|
277
|
-
s.get_columns!( 'Cost', 'Part', 'Qty' )
|
|
278
|
-
s.gc!( 'Cost', 'Part', 'Qty' )
|
|
279
|
-
|
|
280
|
-
#Insert blank rows or columns ( before, number to insert )
|
|
281
|
-
s.insert_rows( 2, 2 ) #Inserts 2 empty rows before row 2
|
|
282
|
-
s.insert_columns( 'B', 1 ) #Inserts 2 empty columns before column 2
|
|
283
|
-
s.insert_columns( 2, 1 ) #Inserts 2 empty columns before column 2
|
|
284
|
-
|
|
285
|
-
#Find the first row which matches a value within a column (selected by header)
|
|
286
|
-
#Note: Can now accept a Column object in place of a header.
|
|
287
|
-
s.match( 'Qty' ) { |value| value == 1 } #=> 2
|
|
288
|
-
s.match( 'Part', &/Type2/ ) #=> 3
|
|
289
|
-
|
|
290
|
-
#Find the current end of the data range
|
|
291
|
-
s.maxrow #=> 8
|
|
292
|
-
s.rows.count #=> 8
|
|
293
|
-
s.maxcol #=> 5
|
|
294
|
-
s.columns.count #=> 5
|
|
295
|
-
|
|
296
|
-
#Partition the sheet into two, given a header and a block (like Filter)
|
|
297
|
-
#Note: this keeps the headers intact in both output sheets
|
|
298
|
-
type_1_and_3, other = s.partition( 'Part' ) { |value| value =~ /Type[13]/ }
|
|
299
|
-
type_1_and_3, other = s.partition( 'Part', &/Type[13]/ )
|
|
300
|
-
|
|
301
|
-
#Reverse the data by rows or columns (ignores headers)
|
|
302
|
-
s.reverse_rows!
|
|
303
|
-
s.reverse_columns!
|
|
304
|
-
|
|
305
|
-
#Sort the rows by header(s) (ignores header rows)
|
|
306
|
-
s.sort_by!( 'Part' )
|
|
307
|
-
s.sort_by!( 'Qty', 'Part' )
|
|
308
|
-
|
|
309
|
-
#Split a Sheet into a Workbook of Sheets by a column (selected by header)
|
|
310
|
-
wb = s.split( 'Part' )
|
|
311
|
-
#=> <Workbook: [Sheet:Type1, Sheet:Type2, Sheet:Type3, Sheet:Type4]>
|
|
312
|
-
|
|
313
|
-
#Sum all elements in a column by criteria in another column (selected by header)
|
|
314
|
-
#Parameters: Header to pass to the block, Header to sum, Block.
|
|
315
|
-
#Note: Now also accepts Column objects in place of headers.
|
|
316
|
-
s.sumif( 'Part', 'Cost' ) { |part| part == 'Type1' } #=> 169.15
|
|
317
|
-
s.sumif( 'Part', 'Cost', &/Type1/ ) #=> 169.15
|
|
318
|
-
|
|
319
|
-
#Summarise a column by header into a Hash.
|
|
320
|
-
s.summarise( 'Part' )
|
|
321
|
-
#=> {"Type1"=>3, "Type2"=>2, "Type3"=>1, "Type4"=>1}
|
|
322
|
-
|
|
323
|
-
#Convert the data into various formats:
|
|
324
|
-
s.to_a #=> 2D Array
|
|
325
|
-
s.to_excel #=> WIN32OLE Excel Workbook (Contains only the current sheet)
|
|
326
|
-
s.to_html #=> String (HTML table)
|
|
327
|
-
s.to_s #=> String (TSV)
|
|
328
|
-
|
|
329
|
-
#Remove all rows with duplicate values in the given column (selected by header or Column object)
|
|
330
|
-
s.uniq! 'Part'
|
|
331
|
-
|
|
332
|
-
#Find a value in one column by searching another one (selected by headers or Column objects)
|
|
333
|
-
s.vlookup( 'Part', 'Ref1', &/Type4/ ) #=> "XT3"
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
Row / Column (Section)
|
|
337
|
-
--------
|
|
338
|
-
|
|
339
|
-
```ruby
|
|
340
|
-
#Reference a Row or Column
|
|
341
|
-
row = s.row(2)
|
|
342
|
-
col = s.column('B')
|
|
343
|
-
|
|
344
|
-
=begin
|
|
345
|
-
Append a value
|
|
346
|
-
Note: Only extends the data boundaries when at the first row or column.
|
|
347
|
-
This allows looping through an entire row or column to append single values,
|
|
348
|
-
without worrying about using the correct index.
|
|
349
|
-
=end
|
|
350
|
-
s.row(1) << 'New'
|
|
351
|
-
s.rows(2) { |r| r << 'Column' }
|
|
352
|
-
s.column(1) << 'New'
|
|
353
|
-
s.columns(2) { |c| c << 'Row' }
|
|
354
|
-
|
|
355
|
-
#Access a cell by column header (Row only)
|
|
356
|
-
s.row(2).cell_by_header( 'Part' ) #=> Element A2
|
|
357
|
-
s.row(2).cell_h( 'Cost' ) #=> Element E2
|
|
358
|
-
|
|
359
|
-
#Delete the data referenced by self.
|
|
360
|
-
row.delete
|
|
361
|
-
col.delete
|
|
362
|
-
|
|
363
|
-
#Find the address of a cell matching a block
|
|
364
|
-
row.find { |value| value == 'QT1' }
|
|
365
|
-
row.find &/QT1/
|
|
366
|
-
col.find { |value| value == 'QT1' }
|
|
367
|
-
col.find &/QT1/
|
|
368
|
-
|
|
369
|
-
#Summarise the current row or column into a Hash.
|
|
370
|
-
s.column(1).summarise
|
|
371
|
-
#=> {"Type1"=>3, "Type2"=>2, "Type3"=>1, "Type4"=>1}
|
|
372
|
-
|
|
373
|
-
#Loop through all values
|
|
374
|
-
row.each { |val| puts val }
|
|
375
|
-
col.each { |val| puts val }
|
|
376
|
-
|
|
377
|
-
#Loop through all values without including headers
|
|
378
|
-
col.each_without_headers { |val| puts val }
|
|
379
|
-
col.each_wh { |val| puts val }
|
|
380
|
-
|
|
381
|
-
#Loop through each cell
|
|
382
|
-
row.each_cell { |ce| puts "#{ ce.address }: #{ ce.value }" }
|
|
383
|
-
col.each_cell { |ce| puts "#{ ce.address }: #{ ce.value }" }
|
|
384
|
-
|
|
385
|
-
#Loop through each cell without including headers
|
|
386
|
-
col.each_cell_without_headers { |ce| puts "#{ ce.address }: #{ ce.value }" }
|
|
387
|
-
col.each_cell_wh { |ce| puts "#{ ce.address }: #{ ce.value }" }
|
|
388
|
-
|
|
389
|
-
#Overwrite each value based on its current value
|
|
390
|
-
row.map! { |val| val.to_s + 'a' }
|
|
391
|
-
col.map! { |val| val.to_s + 'a' }
|
|
392
|
-
|
|
393
|
-
#Get the value of a cell in the current row by its header
|
|
394
|
-
row.value_by_header( 'Part' ) #=> 'Type1'
|
|
395
|
-
row.val( 'Part' ) #=> 'Type1'
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
Cell / Range (Element)
|
|
399
|
-
--------
|
|
400
|
-
|
|
401
|
-
```ruby
|
|
402
|
-
#Reference a Cell or Range
|
|
403
|
-
cell = s.cell( 2, 2 )
|
|
404
|
-
range = s.range('B2:C3')
|
|
405
|
-
|
|
406
|
-
#Get the address and indices of the Element (Indices return that of the first cell for multi-cell Ranges)
|
|
407
|
-
cell.address
|
|
408
|
-
cell.row
|
|
409
|
-
cell.column
|
|
410
|
-
range.address
|
|
411
|
-
range.row
|
|
412
|
-
range.column
|
|
413
|
-
|
|
414
|
-
#Get and set the value(s)
|
|
415
|
-
cell.value #=> "QT1"
|
|
416
|
-
cell.value = 'QT1'
|
|
417
|
-
range.value #=> [["QT1", "231"], ["QT3", "123"]]
|
|
418
|
-
range.value = "a"
|
|
419
|
-
range.value #=> [["a", "a"], ["a", "a"]]
|
|
420
|
-
range.value = [["QT1", "231"], ["QT3", "123"]]
|
|
421
|
-
range.value #=> [["QT1", "231"], ["QT3", "123"]]
|
|
422
|
-
|
|
423
|
-
#Loop through a range
|
|
424
|
-
range.each { |val| puts val }
|
|
425
|
-
|
|
426
|
-
#Loop through each cell within a range
|
|
427
|
-
range.each_cell { |ce| puts "#{ ce.address }: #{ ce.value }" }
|
|
428
|
-
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
Address Tools (Included in Sheet, Section, and Element)
|
|
432
|
-
--------
|
|
433
|
-
|
|
434
|
-
```ruby
|
|
435
|
-
#Get the column index from an address string
|
|
436
|
-
s.address_to_col_index( 'A2' ) #=> 1
|
|
437
|
-
|
|
438
|
-
#Translate an address to indices
|
|
439
|
-
s.address_to_indices( 'A2' ) #=> [ 2, 1 ]
|
|
440
|
-
|
|
441
|
-
#Translate letter(s) to a column index
|
|
442
|
-
s.col_index( 'A' ) #=> 1
|
|
443
|
-
|
|
444
|
-
#Translate a number to column letter(s)
|
|
445
|
-
s.col_letter( 1 ) #=> "A"
|
|
446
|
-
|
|
447
|
-
#Extract the column letter(s) or row number from an address
|
|
448
|
-
s.column_id( 'A2' ) #=> "A"
|
|
449
|
-
s.row_id( 'A2' ) #=> 2
|
|
450
|
-
|
|
451
|
-
#Expand a Range address
|
|
452
|
-
s.expand( 'A1:B2' ) #=> [["A1", "B1"], ["A2","B2"]]
|
|
453
|
-
s.expand( 'A1' ) #=> [["A1"]]
|
|
454
|
-
|
|
455
|
-
#Translate indices to an address
|
|
456
|
-
s.indices_to_address( 2, 1 ) #=> "A2"
|
|
457
|
-
|
|
458
|
-
#Offset an address by rows and columns
|
|
459
|
-
s.offset( 'A2', 1, 2 ) #=> "C3"
|
|
460
|
-
s.offset( 'A2', 2, 0 ) #=> "A4"
|
|
461
|
-
s.offset( 'A2', -1, 0 ) #=> "A1"
|
|
462
|
-
|
|
463
|
-
```
|
|
464
|
-
|
|
465
|
-
Importing a Hash
|
|
466
|
-
--------
|
|
467
|
-
|
|
468
|
-
```ruby
|
|
469
|
-
#Import a nested Hash (useful if you're summarising data before handing it to RubyExcel)
|
|
470
|
-
|
|
471
|
-
#Here's an example Hash (built into the gem as RubyExcel.sample_hash)
|
|
472
|
-
h = {
|
|
473
|
-
Part1: {
|
|
474
|
-
Type1: {
|
|
475
|
-
SubType1: 1, SubType2: 2, SubType3: 3
|
|
476
|
-
},
|
|
477
|
-
Type2: {
|
|
478
|
-
SubType1: 4, SubType2: 5, SubType3: 6
|
|
479
|
-
}
|
|
480
|
-
},
|
|
481
|
-
Part2: {
|
|
482
|
-
Type1: {
|
|
483
|
-
SubType1: 1, SubType2: 2, SubType3: 3
|
|
484
|
-
},
|
|
485
|
-
Type2: {
|
|
486
|
-
SubType1: 4, SubType2: 5, SubType3: 6
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
#Import the Hash to a Sheet
|
|
492
|
-
s.load( h )
|
|
493
|
-
#Or append the Hash to a Sheet
|
|
494
|
-
s << h
|
|
495
|
-
|
|
496
|
-
#Convert the symbols to strings (Not essential, but Excel can't handle Symbols in output)
|
|
497
|
-
s.rows { |r| r.map! { |v| v.is_a?(Symbol) ? v.to_s : v } }
|
|
498
|
-
|
|
499
|
-
#Have a look at the results
|
|
500
|
-
require 'pp'
|
|
501
|
-
pp s.to_a
|
|
502
|
-
[["Part1", "Type1", "SubType1", 1],
|
|
503
|
-
["Part1", "Type1", "SubType2", 2],
|
|
504
|
-
["Part1", "Type1", "SubType3", 3],
|
|
505
|
-
["Part1", "Type2", "SubType1", 4],
|
|
506
|
-
["Part1", "Type2", "SubType2", 5],
|
|
507
|
-
["Part1", "Type2", "SubType3", 6],
|
|
508
|
-
["Part2", "Type1", "SubType1", 1],
|
|
509
|
-
["Part2", "Type1", "SubType2", 2],
|
|
510
|
-
["Part2", "Type1", "SubType3", 3],
|
|
511
|
-
["Part2", "Type2", "SubType1", 4],
|
|
512
|
-
["Part2", "Type2", "SubType2", 5],
|
|
513
|
-
["Part2", "Type2", "SubType3", 6]]
|
|
514
|
-
|
|
515
|
-
```
|
|
516
|
-
|
|
517
|
-
Excel Tools ( requires win32ole and Excel )
|
|
518
|
-
--------
|
|
519
|
-
|
|
520
|
-
Make sure all your data types are compatible with Excel first!
|
|
521
|
-
|
|
522
|
-
```ruby
|
|
523
|
-
#Sample RubyExcel::Workbook to work with
|
|
524
|
-
rubywb = RubyExcel.sample_sheet.parent
|
|
525
|
-
|
|
526
|
-
#Get a new Excel instance
|
|
527
|
-
excel = rubywb.get_excel
|
|
528
|
-
|
|
529
|
-
#Get a new Excel Workbook
|
|
530
|
-
excelwb = rubywb.get_workbook( excel )
|
|
531
|
-
excelwb = rubywb.get_workbook
|
|
532
|
-
|
|
533
|
-
#Drop data into an Excel Sheet
|
|
534
|
-
rubywb.dump_to_sheet( rubywb.sheets(1).to_a )
|
|
535
|
-
rubywb.dump_to_sheet( rubywb.sheets(1).to_a, excelwb.sheets(1) )
|
|
536
|
-
|
|
537
|
-
#Autofit and left-align a WIN32OLE Excel Sheet
|
|
538
|
-
rubywb.make_sheet_pretty( excelwb.sheets(1) )
|
|
539
|
-
|
|
540
|
-
#Output the RubyExcel::Workbook into a new Excel Workbook
|
|
541
|
-
rubywb.to_excel
|
|
542
|
-
|
|
543
|
-
#Output the RubyExcel::Sheet into a new Excel Workbook
|
|
544
|
-
rubywb.sheets(1).to_excel
|
|
545
|
-
|
|
546
|
-
#Output the RubyExcel::Workbook into an Excel Workbook and save the file
|
|
547
|
-
#Note: The default directory is "Documents" or "My Documents" to support Ocra + InnoSetup installs.
|
|
548
|
-
#Note: There is an optional second argument which if set to true doesn't make Excel visible.
|
|
549
|
-
# This is a useful accelerator when running as an automated process.
|
|
550
|
-
# If you set the process to be invisible, don't forget to close Excel after you're finished with it!
|
|
551
|
-
rubywb.save_excel
|
|
552
|
-
rubywb.save_excel( 'Output.xlsx' )
|
|
553
|
-
rubywb.save_excel( 'c:/example/Output.xlsx' )
|
|
554
|
-
|
|
555
|
-
#Add borders to a given Excel Range
|
|
556
|
-
#1st Argument: WIN32OLE Range
|
|
557
|
-
#2nd Argument (default 1), weight of borders (0 to 4)
|
|
558
|
-
#3rd Argument (default false), include inner borders
|
|
559
|
-
RubyExcel.borders( excelwb.sheets(1).usedrange ) #Give used range outer borders
|
|
560
|
-
RubyExcel.borders( excelwb.sheets(1).usedrange, 2, true ) #Give used range inner and outer borders, medium weight
|
|
561
|
-
RubyExcel.borders( excelwb.sheets(1).usedrange, 0, false ) #Clear outer borders from used range
|
|
562
|
-
|
|
563
|
-
#You can even enter formula strings and Excel will evaluate them in the output.
|
|
564
|
-
s = rubywb.sheets(1)
|
|
565
|
-
s.row(1) << 'Formula'
|
|
566
|
-
s.rows(2) { |row| row << "=SUM(D#{ row.idx }:E#{ row.idx })" }
|
|
567
|
-
s.to_excel
|
|
568
|
-
|
|
569
|
-
```
|
|
570
|
-
|
|
571
|
-
Comparison of operations with and without RubyExcel gem
|
|
572
|
-
--------
|
|
573
|
-
|
|
574
|
-
Without RubyExcel (one way to to it):
|
|
575
|
-
|
|
576
|
-
```ruby
|
|
577
|
-
#Filter to only 'Part' of 'Type1' and 'Type3' while keeping the header row
|
|
578
|
-
idx = data[0].index( 'Part' )
|
|
579
|
-
data = [ data[0] ] + data[1..-1].select { |row| row[ idx ] =~ /Type[13]/ }
|
|
580
|
-
|
|
581
|
-
#Keep only the columns 'Cost' and 'Ref2' in that order
|
|
582
|
-
max_size = data.max_by(&:length).length #Standardise the row size to transpose into columns
|
|
583
|
-
data.map! { |row| row.length == max_size ? row : row + Array.new( max_size - row.length, nil) }
|
|
584
|
-
headers = [ 'Cost', 'Ref2' ]
|
|
585
|
-
data = data.transpose.select { |header,_| headers.index(header) }.sort_by { |header,_| headers.index(header) }.transpose
|
|
586
|
-
|
|
587
|
-
#Get the combined 'Cost' of every 'Part' of 'Type1' and 'Type3'
|
|
588
|
-
find_idx, sum_idx = data[0].index('Part'), data[0].index('Cost')
|
|
589
|
-
data[1..-1].inject(0) { |sum, row| row[find_idx] =~ /Type[13]/ ? sum + row[sum_idx] : sum }
|
|
590
|
-
|
|
591
|
-
#Write the data to a TSV file
|
|
592
|
-
output = data.map { |row| row.map { |el| "#{el}".strip.gsub( /\s/, ' ' ) }.join "\t" }.join $/
|
|
593
|
-
File.write( 'output.txt', output )
|
|
594
|
-
|
|
595
|
-
#Drop the data into an Excel sheet ( using Excel and win32ole )
|
|
596
|
-
excel = WIN32OLE::new( 'excel.application' )
|
|
597
|
-
excel.visible = true
|
|
598
|
-
wb = excel.workbooks.add
|
|
599
|
-
sheet = wb.sheets(1)
|
|
600
|
-
sheet.range( sheet.cells( 1, 1 ), sheet.cells( data.length, data[0].length ) ).value = data
|
|
601
|
-
wb.saveas( Dir.pwd.gsub('/','\\') + '\\Output.xlsx' )
|
|
602
|
-
```
|
|
603
|
-
|
|
604
|
-
With RubyExcel:
|
|
605
|
-
|
|
606
|
-
```ruby
|
|
607
|
-
#Filter to only 'Part' of 'Type1' and 'Type3' while keeping the header row
|
|
608
|
-
s.filter!( 'Part', &/Type[13]/ )
|
|
609
|
-
|
|
610
|
-
#Keep only the columns 'Cost' and 'Ref2' in that order
|
|
611
|
-
s.get_columns!( 'Cost', 'Ref2' )
|
|
612
|
-
|
|
613
|
-
#Get the combined 'Cost' of every 'Part' of 'Type1' and 'Type3'
|
|
614
|
-
s.sumif( 'Part', 'Cost', &/Type[13]/ )
|
|
615
|
-
|
|
616
|
-
#Write the data to a TSV file
|
|
617
|
-
File.write( 'output.txt', s.to_s )
|
|
618
|
-
|
|
619
|
-
#Write the data to an XLSX file ( requires Excel and win32ole )
|
|
620
|
-
s.parent.save_excel( 'Output.xlsx' )
|
|
621
|
-
```
|
|
622
|
-
|
|
623
|
-
Todo List
|
|
624
|
-
=========
|
|
625
|
-
|
|
626
|
-
- Write TestCases for most methods (Hopefully that'll stop me releasing broken gem versions)
|
|
627
|
-
|
|
628
|
-
- Find bugs and extirpate them.
|
|
629
|
-
|
|
630
|
-
- Optimise slow operations
|