rubyexcel 0.0.5 → 0.0.6
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/address.rb +88 -5
- data/lib/rubyexcel/data.rb +209 -21
- data/lib/rubyexcel/element.rb +67 -6
- data/lib/rubyexcel/excel_tools.rb +62 -3
- data/lib/rubyexcel/rubyexcel_components.rb +8 -0
- data/lib/rubyexcel/section.rb +150 -14
- data/lib/rubyexcel.rb +448 -32
- metadata +2 -2
data/lib/rubyexcel.rb
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
require_relative 'rubyexcel/rubyexcel_components.rb'
|
2
2
|
require_relative 'rubyexcel/excel_tools.rb'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
#
|
6
|
+
# Ruby's standard Regexp class.
|
7
|
+
# Regexp#to_proc is a bit of "syntactic sugar" which allows shorthand Regexp blocks
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# sheet.filter!( 'Part', &/Type[13]/ )
|
11
|
+
#
|
3
12
|
|
4
13
|
class Regexp
|
5
14
|
def to_proc
|
@@ -7,93 +16,205 @@ class Regexp
|
|
7
16
|
end
|
8
17
|
end
|
9
18
|
|
19
|
+
#
|
20
|
+
# Namespace for all RubyExcel Classes and Modules
|
21
|
+
#
|
22
|
+
|
10
23
|
module RubyExcel
|
11
24
|
|
25
|
+
#
|
26
|
+
# A Workbook which can hold multiple Sheets
|
27
|
+
#
|
28
|
+
|
12
29
|
class Workbook
|
30
|
+
include Enumerable
|
13
31
|
|
32
|
+
#
|
33
|
+
# Creates a RubyExcel::Workbook instance.
|
34
|
+
#
|
35
|
+
|
14
36
|
def initialize
|
15
37
|
@sheets = []
|
16
38
|
end
|
17
39
|
|
40
|
+
#
|
41
|
+
# Appends an object to the Workbook
|
42
|
+
#
|
43
|
+
# @param [RubyExcel::Workbook, RubyExcel::Sheet, Array<Array>] other the object to append to the Workbook
|
44
|
+
#
|
45
|
+
|
18
46
|
def <<( other )
|
19
47
|
case other
|
20
48
|
when Workbook ; other.each { |sht| sht.workbook = self; @sheets << sht }
|
21
|
-
when Sheet
|
22
|
-
when Array
|
23
|
-
else
|
49
|
+
when Sheet ; @sheets << other; other.workbook = self
|
50
|
+
when Array ; @sheets << add.load( other )
|
51
|
+
else ; fail TypeError, "Unsupported Type: #{ other.class }"
|
24
52
|
end
|
25
53
|
self
|
26
54
|
end
|
27
55
|
|
56
|
+
#
|
57
|
+
# Adds a Sheet to the Workbook.
|
58
|
+
# If no argument is given, names the Sheet 'Sheet' + total number of Sheets
|
59
|
+
#
|
60
|
+
# @example
|
61
|
+
# sheet = workbook.add
|
62
|
+
# #=> RubyExcel::Sheet:0x2b3a0b8: Sheet1
|
63
|
+
#
|
64
|
+
# @param [nil, RubyExcel::Sheet, String] ref the identifier or Sheet to add
|
65
|
+
# @return [RubyExcel::Sheet] the Sheet which was added
|
66
|
+
|
28
67
|
def add( ref=nil )
|
29
68
|
case ref
|
30
|
-
when nil
|
31
|
-
when Sheet
|
69
|
+
when nil ; s = Sheet.new( 'Sheet' + ( @sheets.count + 1 ).to_s, self )
|
70
|
+
when Sheet ; ( s = ref ).workbook = self
|
32
71
|
when String ; s = Sheet.new( ref, self )
|
33
|
-
else
|
72
|
+
else ; fail TypeError, "Unsupported Type: #{ ref.class }"
|
34
73
|
end
|
35
|
-
@sheets << s
|
74
|
+
@sheets << s
|
75
|
+
s
|
36
76
|
end
|
37
77
|
alias add_sheet add
|
38
78
|
|
79
|
+
#
|
80
|
+
# Removes all Sheets from the Workbook
|
81
|
+
#
|
82
|
+
|
39
83
|
def clear_all
|
40
84
|
@sheets = []; self
|
41
85
|
end
|
86
|
+
alias delete_all clear_all
|
87
|
+
|
88
|
+
#
|
89
|
+
# Removes Sheet(s) from the Workbook
|
90
|
+
#
|
91
|
+
# @param [Fixnum, String, Regexp, RubyExcel::Sheet] ref the reference or object to remove
|
92
|
+
#
|
42
93
|
|
43
94
|
def delete( ref )
|
44
95
|
case ref
|
45
96
|
when Fixnum ; @sheets.delete_at( ref - 1 )
|
46
97
|
when String ; @sheets.reject! { |s| s.name == ref }
|
47
98
|
when Regexp ; @sheets.reject! { |s| s.name =~ ref }
|
48
|
-
when Sheet
|
49
|
-
else
|
50
|
-
end
|
99
|
+
when Sheet ; @sheets.reject! { |s| s == ref }
|
100
|
+
else ; fail ArgumentError, 'Unrecognised Argument Type: ' + ref.class.to_s
|
101
|
+
end
|
102
|
+
self
|
51
103
|
end
|
52
104
|
|
105
|
+
#
|
106
|
+
# Return a copy of self
|
107
|
+
#
|
108
|
+
# @return [RubyExcel::Workbook]
|
109
|
+
#
|
110
|
+
|
53
111
|
def dup
|
54
112
|
wb = Workbook.new
|
55
113
|
self.each { |s| wb.add s.dup }
|
56
114
|
wb
|
57
115
|
end
|
58
116
|
|
117
|
+
#
|
118
|
+
# Check whether the workbook has Sheets
|
119
|
+
#
|
120
|
+
# @return [Boolean] if there are any Sheets in the Workbook
|
121
|
+
#
|
122
|
+
|
59
123
|
def empty?
|
60
124
|
@sheets.empty?
|
61
125
|
end
|
62
126
|
|
127
|
+
# @overload load( input_data, header_rows=1 )
|
128
|
+
# Shortcut to create a Sheet and fill it with data
|
129
|
+
# @param [Array<Array>, Hash<Hash>] input_data the data to fill the Sheet with
|
130
|
+
# @param Fixnum] header_rows the number of Rows to be treated as headers
|
131
|
+
#
|
132
|
+
|
63
133
|
def load( *args )
|
64
134
|
add.load( *args )
|
65
135
|
end
|
136
|
+
|
137
|
+
#
|
138
|
+
# Select a Sheet or iterate through them
|
139
|
+
#
|
140
|
+
# @param [Fixnum, String, nil] ref the reference to select a Sheet by
|
141
|
+
# @return [RubyExcel::Sheet] if a search term was given
|
142
|
+
# @return [Enumerator] if nil or no argument given
|
143
|
+
#
|
66
144
|
|
67
145
|
def sheets( ref=nil )
|
68
146
|
return to_enum (:each) if ref.nil?
|
69
147
|
ref.is_a?( Fixnum ) ? @sheets[ ref - 1 ] : @sheets.find { |s| s.name =~ /^#{ ref }$/i }
|
70
148
|
end
|
71
149
|
|
72
|
-
|
73
|
-
|
150
|
+
# {Workbook#sort!}
|
151
|
+
|
152
|
+
def sort( &block )
|
153
|
+
dup.sort!( &block )
|
74
154
|
end
|
75
155
|
|
156
|
+
#
|
157
|
+
# Sort Sheets according to a block
|
158
|
+
#
|
159
|
+
|
160
|
+
def sort!( &block )
|
161
|
+
@sheets = @sheets.sort( &block )
|
162
|
+
end
|
163
|
+
|
164
|
+
# {Workbook#sort_by!}
|
165
|
+
|
166
|
+
def sort_by( &block )
|
167
|
+
dup.sort_by!( &block )
|
168
|
+
end
|
169
|
+
|
170
|
+
#
|
171
|
+
# Sort Sheets by an attribute given in a block
|
172
|
+
#
|
173
|
+
|
76
174
|
def sort_by!( &block )
|
77
|
-
@sheets = @sheets.sort_by(&block)
|
175
|
+
@sheets = @sheets.sort_by( &block )
|
78
176
|
end
|
79
177
|
|
80
|
-
|
178
|
+
#
|
179
|
+
# Yields each Sheet.
|
180
|
+
#
|
81
181
|
|
82
182
|
def each
|
83
|
-
return to_enum(:each) unless block_given?
|
183
|
+
return to_enum( :each ) unless block_given?
|
84
184
|
@sheets.each { |s| yield s }
|
85
185
|
end
|
86
186
|
|
87
|
-
end
|
187
|
+
end # Workbook
|
188
|
+
|
189
|
+
#
|
190
|
+
# The front-end class for data manipulation and output.
|
191
|
+
#
|
88
192
|
|
89
193
|
class Sheet
|
194
|
+
include Address
|
195
|
+
include Enumerable
|
90
196
|
|
197
|
+
# The Data underlying the Sheet
|
91
198
|
attr_reader :data
|
92
|
-
|
199
|
+
|
200
|
+
# The name of the Sheet
|
201
|
+
attr_accessor :name
|
202
|
+
|
203
|
+
# The number of rows treated as headers
|
204
|
+
attr_accessor :header_rows
|
205
|
+
|
206
|
+
# The Workbook parent of this Sheet
|
207
|
+
attr_accessor :workbook
|
208
|
+
|
93
209
|
alias parent workbook; alias parent= workbook=
|
94
|
-
alias headers header_rows; alias headers= header_rows=
|
210
|
+
alias headers header_rows; alias headers= header_rows=
|
95
211
|
|
96
|
-
|
212
|
+
#
|
213
|
+
# Creates a RubyExcel::Sheet instance
|
214
|
+
#
|
215
|
+
# @param [String] name the name of the Sheet
|
216
|
+
# @param [RubyExcel::Workbook] workbook the Workbook which holds this Sheet
|
217
|
+
#
|
97
218
|
|
98
219
|
def initialize( name, workbook )
|
99
220
|
@workbook = workbook
|
@@ -101,72 +222,182 @@ module RubyExcel
|
|
101
222
|
@header_rows = nil
|
102
223
|
@data = Data.new( self, [[]] )
|
103
224
|
end
|
225
|
+
|
226
|
+
#
|
227
|
+
# Read a value by address
|
228
|
+
#
|
229
|
+
# @example
|
230
|
+
# sheet['A1']
|
231
|
+
# #=> "Part"
|
232
|
+
#
|
233
|
+
# @example
|
234
|
+
# sheet['A1:B2']
|
235
|
+
# #=> [["Part", "Ref1"], ["Type1", "QT1"]]
|
236
|
+
#
|
237
|
+
# @param [String] addr the address to access
|
238
|
+
#
|
104
239
|
|
105
240
|
def[]( addr )
|
106
241
|
range( addr ).value
|
107
242
|
end
|
243
|
+
|
244
|
+
#
|
245
|
+
# Write a value by address
|
246
|
+
#
|
247
|
+
# @example
|
248
|
+
# sheet['A1'] = "Bart"
|
249
|
+
# sheet['A1']
|
250
|
+
# #=> "Bart"
|
251
|
+
#
|
252
|
+
# @param (see #[])
|
253
|
+
# @param [Object] val the value to write into the data
|
254
|
+
#
|
108
255
|
|
109
256
|
def []=( addr, val )
|
110
257
|
range( addr ).value = val
|
111
258
|
end
|
112
259
|
|
260
|
+
#
|
261
|
+
# Add data with the Sheet
|
262
|
+
#
|
263
|
+
# @param [Array<Array>, Hash<Hash>, RubyExcel::Sheet] other the data to add
|
264
|
+
# @return [RubyExcel::Sheet] returns a new Sheet
|
265
|
+
#
|
113
266
|
|
114
267
|
def +( other )
|
115
268
|
dup << other
|
116
269
|
end
|
117
270
|
|
271
|
+
#
|
272
|
+
# Subtract data from the Sheet
|
273
|
+
#
|
274
|
+
# @param [Array<Array>, RubyExcel::Sheet] other the data to subtract
|
275
|
+
# @return [RubyExcel::Sheet] returns a new Sheet
|
276
|
+
#
|
277
|
+
|
118
278
|
def -( other )
|
119
279
|
case other
|
120
280
|
when Array ; Workbook.new.load( data.all - other )
|
121
281
|
when Sheet ; Workbook.new.load( data.all - other.data.no_headers )
|
122
|
-
else
|
282
|
+
else ; fail ArgumentError, "Unsupported class: #{ other.class }"
|
123
283
|
end
|
124
284
|
end
|
125
285
|
|
286
|
+
#
|
287
|
+
# Append data to the Sheet
|
288
|
+
#
|
289
|
+
# @param [Array<Array>, Hash<Hash>, RubyExcel::Sheet] other the data to append
|
290
|
+
# @return [self]
|
291
|
+
#
|
292
|
+
|
126
293
|
def <<( other )
|
127
294
|
case other
|
128
295
|
when Array ; load( data.all + other, header_rows )
|
129
|
-
when Hash
|
296
|
+
when Hash ; load( data.all + _convert_hash( other ) )
|
130
297
|
when Sheet ; load( data.all + other.data.no_headers, header_rows )
|
131
|
-
else
|
298
|
+
else ; fail ArgumentError, "Unsupported class: #{ other.class }"
|
132
299
|
end
|
300
|
+
self
|
133
301
|
end
|
134
302
|
|
303
|
+
#
|
304
|
+
# Access an Element by indices.
|
305
|
+
#
|
306
|
+
# @param [Fixnum] row the row index
|
307
|
+
# @param [Fixnum] col the column index
|
308
|
+
# @return [RubyExcel::Element]
|
309
|
+
# @note Indexing is 1-based like Excel VBA
|
310
|
+
#
|
311
|
+
|
135
312
|
def cell( row, col )
|
136
313
|
Element.new( self, indices_to_address( row, col ) )
|
137
314
|
end
|
138
315
|
alias cells cell
|
139
316
|
|
317
|
+
#
|
318
|
+
# Access a Column (Section) by its reference.
|
319
|
+
#
|
320
|
+
# @param [String, Fixnum] index the Column reference
|
321
|
+
# @return [RubyExcel::Column]
|
322
|
+
# @note Index 'A' and 1 both select the 1st Column
|
323
|
+
#
|
324
|
+
|
140
325
|
def column( index )
|
141
326
|
Column.new( self, col_letter( index ) )
|
142
327
|
end
|
143
328
|
|
329
|
+
#
|
330
|
+
# Access a Column (Section) by its header.
|
331
|
+
#
|
332
|
+
# @param [String] header the Column header
|
333
|
+
# @return [RubyExcel::Column]
|
334
|
+
#
|
335
|
+
|
144
336
|
def column_by_header( header )
|
145
|
-
Column.new( self, data.colref_by_header( header ) )
|
337
|
+
header.is_a?( Column ) ? header : Column.new( self, data.colref_by_header( header ) )
|
146
338
|
end
|
147
339
|
alias ch column_by_header
|
148
340
|
|
341
|
+
#
|
342
|
+
# Yields each Column to the block
|
343
|
+
#
|
344
|
+
# @param [String, Fixnum] start_column the Column to start looping from
|
345
|
+
# @param [String, Fixnum] end_column the Column to end the loop at
|
346
|
+
# @note Iterates to the last Column in the Sheet unless given a second argument.
|
347
|
+
#
|
348
|
+
|
149
349
|
def columns( start_column = 'A', end_column = data.cols )
|
150
|
-
return to_enum(:columns, start_column, end_column) unless block_given?
|
151
|
-
( col_letter( start_column )..col_letter( end_column ) ).each { |idx| yield column( idx ) }
|
350
|
+
return to_enum( :columns, start_column, end_column ) unless block_given?
|
351
|
+
( col_letter( start_column )..col_letter( end_column ) ).each { |idx| yield column( idx ) }
|
352
|
+
self
|
152
353
|
end
|
153
354
|
|
355
|
+
# {Sheet#compact!}
|
356
|
+
|
357
|
+
def compact
|
358
|
+
dup.compact!
|
359
|
+
end
|
360
|
+
|
361
|
+
#
|
362
|
+
# Removes empty Columns and Rows
|
363
|
+
#
|
364
|
+
|
154
365
|
def compact!
|
155
366
|
data.compact!; self
|
156
367
|
end
|
157
368
|
|
369
|
+
#
|
370
|
+
# Removes Sheet from the parent Workbook
|
371
|
+
#
|
372
|
+
|
158
373
|
def delete
|
159
374
|
workbook.delete self
|
160
375
|
end
|
161
376
|
|
377
|
+
#
|
378
|
+
# Deletes each Row where the block is true
|
379
|
+
#
|
380
|
+
|
162
381
|
def delete_rows_if
|
382
|
+
return to_enum( :delete_rows_if ) unless block_given?
|
163
383
|
rows.reverse_each { |r| r.delete if yield r }; self
|
164
384
|
end
|
165
385
|
|
386
|
+
#
|
387
|
+
# Deletes each Column where the block is true
|
388
|
+
#
|
389
|
+
|
166
390
|
def delete_columns_if
|
391
|
+
return to_enum( :delete_columns_if ) unless block_given?
|
167
392
|
columns.reverse_each { |c| c.delete if yield c }; self
|
168
393
|
end
|
169
394
|
|
395
|
+
#
|
396
|
+
# Return a copy of self
|
397
|
+
#
|
398
|
+
# @return [RubyExcel::Sheet]
|
399
|
+
#
|
400
|
+
|
170
401
|
def dup
|
171
402
|
s = Sheet.new( name, workbook )
|
172
403
|
d = data
|
@@ -178,40 +409,89 @@ module RubyExcel
|
|
178
409
|
s
|
179
410
|
end
|
180
411
|
|
412
|
+
#
|
413
|
+
# Check whether the Sheet contains data
|
414
|
+
#
|
415
|
+
# @return [Boolean] if there is any data
|
416
|
+
#
|
417
|
+
|
181
418
|
def empty?
|
182
419
|
data.empty?
|
183
420
|
end
|
184
421
|
|
185
|
-
|
186
|
-
|
422
|
+
# {Sheet#filter!}
|
423
|
+
|
424
|
+
def filter( header, &block )
|
425
|
+
dup.filter!( header, &block )
|
187
426
|
end
|
188
427
|
|
189
|
-
|
190
|
-
|
428
|
+
#
|
429
|
+
# Removes all Rows (omitting headers) where the block is false
|
430
|
+
#
|
431
|
+
# @param [String] header the header of the Column to pass to the block
|
432
|
+
# @yield [Object] the value at the intersection of Column and Row
|
433
|
+
# @return [self]
|
434
|
+
#
|
435
|
+
def filter!( header, &block )
|
436
|
+
data.filter!( header, &block ); self
|
191
437
|
end
|
192
438
|
|
439
|
+
# {Sheet#get_columns!}
|
440
|
+
|
193
441
|
def get_columns( *headers )
|
194
442
|
dup.get_columns!( *headers )
|
195
443
|
end
|
196
444
|
alias gc get_columns
|
197
445
|
|
446
|
+
#
|
447
|
+
# Select and re-order Columns by a list of headers
|
448
|
+
#
|
449
|
+
# @param [Array<String>] headers the ordered list of headers to keep
|
450
|
+
# @note Invalid headers will be skipped
|
451
|
+
#
|
452
|
+
|
198
453
|
def get_columns!( *headers )
|
199
454
|
data.get_columns!( *headers ); self
|
200
455
|
end
|
201
456
|
alias gc! get_columns!
|
202
457
|
|
458
|
+
# @overload insert_columns( before, number=1 )
|
459
|
+
# Insert blank Columns into the data
|
460
|
+
#
|
461
|
+
# @param [String, Fixnum] before the Column reference to insert before.
|
462
|
+
# @param [Fixnum] number the number of new Columns to insert
|
463
|
+
#
|
464
|
+
|
203
465
|
def insert_columns( *args )
|
204
466
|
data.insert_columns( *args ); self
|
205
467
|
end
|
206
468
|
|
469
|
+
# @overload insert_rows( before, number=1 )
|
470
|
+
# Insert blank Rows into the data
|
471
|
+
#
|
472
|
+
# @param [Fixnum] before the Row index to insert before.
|
473
|
+
# @param [Fixnum] number the number of new Rows to insert
|
474
|
+
#
|
475
|
+
|
207
476
|
def insert_rows( *args )
|
208
477
|
data.insert_rows( *args ); self
|
209
478
|
end
|
210
479
|
|
480
|
+
#
|
481
|
+
# View the object for debugging
|
482
|
+
#
|
483
|
+
|
211
484
|
def inspect
|
212
485
|
"#{ self.class }:0x#{ '%x' % (object_id << 1) }: #{ name }"
|
213
486
|
end
|
214
487
|
|
488
|
+
#
|
489
|
+
# Populate the Sheet with data (overwrite)
|
490
|
+
#
|
491
|
+
# @param [Array<Array>, Hash<Hash>] input_data the data to fill the Sheet with
|
492
|
+
# @param header_rows [Fixnum] the number of Rows to be treated as headers
|
493
|
+
#
|
494
|
+
|
215
495
|
def load( input_data, header_rows=1 )
|
216
496
|
input_data = _convert_hash(input_data) if input_data.is_a?(Hash)
|
217
497
|
input_data.is_a?(Array) or fail ArgumentError, 'Input must be an Array or Hash'
|
@@ -219,70 +499,206 @@ module RubyExcel
|
|
219
499
|
@data = Data.new( self, input_data ); self
|
220
500
|
end
|
221
501
|
|
502
|
+
#
|
503
|
+
# Find the row number by looking up a value in a Column
|
504
|
+
#
|
505
|
+
# @param [String] header the header of the Column to pass to the block
|
506
|
+
# @yield yields each value in the Column to the block
|
507
|
+
# @return [Fixnum, nil] the row number of the first match or nil if nothing is found
|
508
|
+
#
|
509
|
+
|
222
510
|
def match( header, &block )
|
223
511
|
row_id( column_by_header( header ).find( &block ) )
|
224
512
|
end
|
225
513
|
|
514
|
+
#
|
515
|
+
# The highest currently used row number
|
516
|
+
#
|
517
|
+
|
226
518
|
def maxrow
|
227
519
|
data.rows
|
228
520
|
end
|
229
521
|
|
522
|
+
#
|
523
|
+
# The highest currently used column number
|
524
|
+
#
|
525
|
+
|
230
526
|
def maxcol
|
231
527
|
data.cols
|
232
528
|
end
|
233
529
|
alias maxcolumn maxcol
|
234
530
|
|
531
|
+
#
|
532
|
+
# Split the Sheet into two Sheets by evaluating each value in a column
|
533
|
+
#
|
534
|
+
# @param [String] header the header of the Column which contains the yield value
|
535
|
+
# @yield [value] yields the value of each row under the given header
|
536
|
+
# @return [Array<RubyExcel::Sheet, RubyExcel::Sheet>] Two Sheets: true and false. Headers included.
|
537
|
+
#
|
538
|
+
|
539
|
+
def partition( header, &block )
|
540
|
+
data.partition( header, &block ).map { |d| dup.load( d ) }
|
541
|
+
end
|
542
|
+
|
543
|
+
#
|
544
|
+
# Access an Element by address.
|
545
|
+
#
|
546
|
+
# @param [String, Element] first_cell the first Cell or Address in the Range
|
547
|
+
# @param [String, Element] last_cell the last Cell or Address in the Range
|
548
|
+
# @return [RubyExcel::Element]
|
549
|
+
# @note These are all valid arguments:
|
550
|
+
# ('A1')
|
551
|
+
# ('A1:B2')
|
552
|
+
# ('A1', 'B2')
|
553
|
+
# (cell1)
|
554
|
+
# (cell1, cell2)
|
555
|
+
#
|
556
|
+
|
235
557
|
def range( first_cell, last_cell=nil )
|
236
558
|
Element.new( self, to_range_address( first_cell, last_cell ) )
|
237
559
|
end
|
238
560
|
|
561
|
+
#
|
562
|
+
# Reverse the Sheet Columns
|
563
|
+
#
|
564
|
+
|
239
565
|
def reverse_columns!
|
240
566
|
data.reverse_columns!
|
241
567
|
end
|
242
568
|
|
569
|
+
#
|
570
|
+
# Reverse the Sheet Rows (without affecting the headers)
|
571
|
+
#
|
572
|
+
|
243
573
|
def reverse_rows!
|
244
574
|
data.reverse_rows!
|
245
575
|
end
|
576
|
+
|
577
|
+
#
|
578
|
+
# Create a Row from an index
|
579
|
+
#
|
580
|
+
# @param [Fixnum] index the Row index
|
581
|
+
# @return [RubyExcel::Row]
|
582
|
+
#
|
246
583
|
|
247
584
|
def row( index )
|
248
585
|
Row.new( self, index )
|
249
586
|
end
|
250
587
|
|
588
|
+
#
|
589
|
+
# Yields each Row to the block
|
590
|
+
#
|
591
|
+
# @param [Fixnum] start_row the Row to start looping from
|
592
|
+
# @param [Fixnum] end_row the Row to end the loop at
|
593
|
+
# @note Iterates to the last Row in the Sheet unless given a second argument.
|
594
|
+
#
|
595
|
+
|
251
596
|
def rows( start_row = 1, end_row = data.rows )
|
252
597
|
return to_enum(:rows, start_row, end_row) unless block_given?
|
253
598
|
( start_row..end_row ).each { |idx| yield row( idx ) }; self
|
254
599
|
end
|
600
|
+
alias each rows
|
601
|
+
|
602
|
+
# {Sheet#sort!}
|
603
|
+
|
604
|
+
def sort( &block )
|
605
|
+
dup.sort!( &block )
|
606
|
+
end
|
607
|
+
|
608
|
+
#
|
609
|
+
# Sort the data according to a block (avoiding headers)
|
610
|
+
#
|
255
611
|
|
256
612
|
def sort!( &block )
|
257
613
|
data.sort!( &block ); self
|
258
614
|
end
|
259
615
|
|
616
|
+
# {Sheet#sort_by!}
|
617
|
+
|
618
|
+
def sort_by( &block )
|
619
|
+
dup.sort_by!( &block )
|
620
|
+
end
|
621
|
+
|
622
|
+
#
|
623
|
+
# Sort the data by the block value (avoiding headers)
|
624
|
+
#
|
625
|
+
|
260
626
|
def sort_by!( &block )
|
261
627
|
data.sort_by!( &block ); self
|
262
628
|
end
|
263
629
|
|
630
|
+
#
|
631
|
+
# Sum the values in a Column by searching another Column
|
632
|
+
#
|
633
|
+
# @param [String] find_header the header of the Column to yield to the block
|
634
|
+
# @param [String] sum_header the header of the Column to sum
|
635
|
+
# @yield yields the find_header column values to the block
|
636
|
+
#
|
637
|
+
|
264
638
|
def sumif( find_header, sum_header )
|
639
|
+
return to_enum( :sumif ) unless block_given?
|
265
640
|
find_col, sum_col = ch( find_header ), ch( sum_header )
|
266
641
|
find_col.each_cell.inject(0) { |sum,ce| yield( ce.value ) && ce.row > header_rows ? sum + sum_col[ ce.row ] : sum }
|
267
642
|
end
|
268
643
|
|
644
|
+
#
|
645
|
+
# The Sheet as a 2D Array
|
646
|
+
#
|
647
|
+
|
269
648
|
def to_a
|
270
649
|
data.all
|
271
650
|
end
|
272
651
|
|
652
|
+
#
|
653
|
+
# The Sheet as a WIN32OLE Excel Workbook
|
654
|
+
# @note This requires Windows and MS Excel
|
655
|
+
#
|
656
|
+
|
273
657
|
def to_excel
|
274
658
|
workbook.dup.clear_all.add( self.dup ).workbook.to_excel
|
275
659
|
end
|
276
660
|
|
661
|
+
#
|
662
|
+
# The Sheet as a String containing an HTML Table
|
663
|
+
#
|
664
|
+
|
665
|
+
def to_html
|
666
|
+
"<table>\n" + data.map { |row| '<tr>' + row.map { |v| '<td>' + CGI.escapeHTML(v.to_s) }.join() + "\n" }.join() + '</table>'
|
667
|
+
end
|
668
|
+
|
669
|
+
#
|
670
|
+
# The Sheet as a Tab Seperated Value String
|
671
|
+
#
|
672
|
+
|
277
673
|
def to_s
|
278
|
-
data.
|
674
|
+
data.map { |ar| ar.map { |v| v.to_s.gsub(/\t|\n/,' ') }.join "\t" }.join( $/ )
|
279
675
|
end
|
280
676
|
|
677
|
+
# {Sheet#uniq!}
|
678
|
+
|
679
|
+
def uniq( header )
|
680
|
+
dup.uniq!( header )
|
681
|
+
end
|
682
|
+
|
683
|
+
#
|
684
|
+
# Remove any Rows with duplicate values within a Column
|
685
|
+
#
|
686
|
+
# @param [String] header the header of the Column to check for duplicates
|
687
|
+
#
|
688
|
+
|
281
689
|
def uniq!( header )
|
282
690
|
data.uniq!( header ); self
|
283
691
|
end
|
284
692
|
alias unique! uniq!
|
285
693
|
|
694
|
+
#
|
695
|
+
# Find a value within a Column by searching another Column
|
696
|
+
#
|
697
|
+
# @param [String] find_header the header of the Column to search
|
698
|
+
# @param [String] return_header the header of the return value Column
|
699
|
+
# @yield the first matching value
|
700
|
+
#
|
701
|
+
|
286
702
|
def vlookup( find_header, return_header, &block )
|
287
703
|
find_col, return_col = ch( find_header ), ch( return_header )
|
288
704
|
return_col[ row_id( find_col.find( &block ) ) ] rescue nil
|
@@ -298,6 +714,6 @@ module RubyExcel
|
|
298
714
|
_hash_to_a(h).each_slice(2).map { |a1,a2| a1 << a2.last }
|
299
715
|
end
|
300
716
|
|
301
|
-
end
|
717
|
+
end # Sheet
|
302
718
|
|
303
|
-
end
|
719
|
+
end # RubyExcel
|