rubyexcel 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/README.md +8 -7
- data/lib/rubyexcel.rb +60 -2
- data/lib/rubyexcel/address.rb +26 -2
- data/lib/rubyexcel/data.rb +35 -2
- data/lib/rubyexcel/element.rb +6 -2
- data/lib/rubyexcel/section.rb +1 -1
- metadata +2 -2
data/lib/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
RubyExcel
|
2
2
|
=========
|
3
3
|
|
4
|
-
Designed for Windows with MS Excel
|
4
|
+
Designed for Ruby on Windows with MS Excel
|
5
5
|
|
6
|
-
|
6
|
+
Please feel free to log any bugs you find at [GitHub](https://github.com/VirtuosoJoel/RubyExcel/issues "Bug Tracker")
|
7
7
|
|
8
8
|
Introduction
|
9
9
|
------------
|
@@ -97,6 +97,7 @@ Reference a cell's value
|
|
97
97
|
|
98
98
|
```ruby
|
99
99
|
s['A7']
|
100
|
+
s.A7
|
100
101
|
s.cell(7,1).value
|
101
102
|
s.range('A7').value
|
102
103
|
s.row(7)['A']
|
@@ -111,6 +112,8 @@ Reference a group of cells
|
|
111
112
|
```ruby
|
112
113
|
s['A1:B3'] #=> Array
|
113
114
|
s.range( 'A1:B3' ) #=> Element
|
115
|
+
s.range( 'A:A' ) #=> Element (Column)
|
116
|
+
s.range( '1:2' ) #=> Element (Rows)
|
114
117
|
s.range( 'A1', 'B3' ) #=> Element
|
115
118
|
s.range( s.cell( 1, 1 ), s.cell( 3, 2 ) ) #=> Element
|
116
119
|
s.row( 1 ) #=> Row
|
@@ -118,9 +121,11 @@ s.column( 'A' ) #=> Column
|
|
118
121
|
s.column( 1 ) #=> Column
|
119
122
|
```
|
120
123
|
|
121
|
-
|
124
|
+
Some Examples
|
122
125
|
========
|
123
126
|
|
127
|
+
This list may be removed in favour of the gem's documentation on rubydoc.
|
128
|
+
|
124
129
|
Workbook
|
125
130
|
--------
|
126
131
|
|
@@ -561,10 +566,6 @@ s.parent.save_excel( 'Output.xlsx' )
|
|
561
566
|
Todo List
|
562
567
|
=========
|
563
568
|
|
564
|
-
- Allow argument overloading for methods like filter to avoid repetition and increase efficiency.
|
565
|
-
|
566
|
-
- Add support for Range notations like "A:A" and "A:B"
|
567
|
-
|
568
569
|
- Write TestCases (after learning how to do it)
|
569
570
|
|
570
571
|
- Find bugs and extirpate them.
|
data/lib/rubyexcel.rb
CHANGED
@@ -300,6 +300,32 @@ module RubyExcel
|
|
300
300
|
self
|
301
301
|
end
|
302
302
|
|
303
|
+
# {Sheet#advanced_filter!}
|
304
|
+
|
305
|
+
def advanced_filter( *args )
|
306
|
+
dup.advanced_filter!( *args )
|
307
|
+
end
|
308
|
+
|
309
|
+
# @overload advanced_filter!( header, comparison_operator, search_criteria, ... )
|
310
|
+
# Filter on multiple criteria
|
311
|
+
#
|
312
|
+
# @example Filter to 'Part': 'Type1' and 'Type3', with Qty greater than 1
|
313
|
+
# s.advanced_filter!( 'Part', :=~, /Type[13]/, 'Qty', :>, 1 )
|
314
|
+
#
|
315
|
+
# @example Filter to 'Part': 'Type1', with 'Ref2' containing 'X'
|
316
|
+
# s.advanced_filter!( 'Part', :==, 'Type1', 'Ref2', :include?, 'X' )
|
317
|
+
#
|
318
|
+
# @param [String] header a header to search under
|
319
|
+
# @param [Symbol] comparison_operator the operator to compare with
|
320
|
+
# @param [Object] search_criteria the value to filter by
|
321
|
+
# @raise [ArgumentError] 'Number of arguments must be a multiple of 3'
|
322
|
+
# @raise [ArgumentError] 'Operator must be a symbol'
|
323
|
+
#
|
324
|
+
|
325
|
+
def advanced_filter!( *args )
|
326
|
+
data.advanced_filter!( *args ); self
|
327
|
+
end
|
328
|
+
|
303
329
|
#
|
304
330
|
# Access an Element by indices.
|
305
331
|
#
|
@@ -432,6 +458,7 @@ module RubyExcel
|
|
432
458
|
# @yield [Object] the value at the intersection of Column and Row
|
433
459
|
# @return [self]
|
434
460
|
#
|
461
|
+
|
435
462
|
def filter!( header, &block )
|
436
463
|
data.filter!( header, &block ); self
|
437
464
|
end
|
@@ -528,6 +555,35 @@ module RubyExcel
|
|
528
555
|
end
|
529
556
|
alias maxcolumn maxcol
|
530
557
|
|
558
|
+
#
|
559
|
+
# Allow shorthand range references
|
560
|
+
#
|
561
|
+
|
562
|
+
def method_missing(m, *args, &block)
|
563
|
+
method_name = m.to_s.upcase.strip
|
564
|
+
if method_name =~ /\A[A-Z]{1,3}\d+=?\z/
|
565
|
+
if method_name[-1] == '='
|
566
|
+
range( method_name.chop ).value = ( args.length == 1 ? args.first : args )
|
567
|
+
else
|
568
|
+
range( method_name ).value
|
569
|
+
end
|
570
|
+
else
|
571
|
+
super
|
572
|
+
end
|
573
|
+
end
|
574
|
+
|
575
|
+
#
|
576
|
+
# Allow for certain method_missing calls
|
577
|
+
#
|
578
|
+
|
579
|
+
def respond_to?(meth)
|
580
|
+
if meth.to_s.upcase.strip =~ /\A[A-Z]{1,3}\d+=?\z/
|
581
|
+
true
|
582
|
+
else
|
583
|
+
super
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
531
587
|
#
|
532
588
|
# Split the Sheet into two Sheets by evaluating each value in a column
|
533
589
|
#
|
@@ -549,6 +605,8 @@ module RubyExcel
|
|
549
605
|
# @note These are all valid arguments:
|
550
606
|
# ('A1')
|
551
607
|
# ('A1:B2')
|
608
|
+
# ('A:A')
|
609
|
+
# ('1:1')
|
552
610
|
# ('A1', 'B2')
|
553
611
|
# (cell1)
|
554
612
|
# (cell1, cell2)
|
@@ -563,7 +621,7 @@ module RubyExcel
|
|
563
621
|
#
|
564
622
|
|
565
623
|
def reverse_columns!
|
566
|
-
data.reverse_columns
|
624
|
+
data.reverse_columns!; self
|
567
625
|
end
|
568
626
|
|
569
627
|
#
|
@@ -571,7 +629,7 @@ module RubyExcel
|
|
571
629
|
#
|
572
630
|
|
573
631
|
def reverse_rows!
|
574
|
-
data.reverse_rows
|
632
|
+
data.reverse_rows!; self
|
575
633
|
end
|
576
634
|
|
577
635
|
#
|
data/lib/rubyexcel/address.rb
CHANGED
@@ -75,9 +75,33 @@ module RubyExcel
|
|
75
75
|
|
76
76
|
def expand( address )
|
77
77
|
return [[address]] unless address.include? ':'
|
78
|
-
|
79
|
-
|
78
|
+
|
79
|
+
#Extract the relevant boundaries
|
80
|
+
case address
|
81
|
+
|
82
|
+
# Row
|
83
|
+
when /\A(\d+):(\d+)\z/
|
84
|
+
|
85
|
+
start_col, end_col, start_row, end_row = [ 'A', col_letter( sheet.maxcol ) ] + [ $1.to_i, $2.to_i ].sort
|
86
|
+
|
87
|
+
# Column
|
88
|
+
when /\A([A-Z]+):([A-Z]+)\z/
|
89
|
+
|
90
|
+
start_col, end_col, start_row, end_row = [ $1, $2 ].sort + [ 1, sheet.maxrow ]
|
91
|
+
|
92
|
+
# Range
|
93
|
+
when /([A-Z]+)(\d+):([A-Z]+)(\d+)/
|
94
|
+
|
95
|
+
start_col, end_col, start_row, end_row = [ $1, $3 ].sort + [ $2.to_i, $4.to_i ].sort
|
96
|
+
|
97
|
+
# Invalid
|
98
|
+
else
|
99
|
+
fail ArgumentError, 'Invalid address: ' + address
|
100
|
+
end
|
101
|
+
|
102
|
+
# Return the array of addresses
|
80
103
|
( start_row..end_row ).map { |r| ( start_col..end_col ).map { |c| c + r.to_s } }
|
104
|
+
|
81
105
|
end
|
82
106
|
|
83
107
|
#
|
data/lib/rubyexcel/data.rb
CHANGED
@@ -34,6 +34,40 @@ require_relative 'address.rb'
|
|
34
34
|
calc_dimensions
|
35
35
|
end
|
36
36
|
|
37
|
+
# @overload advanced_filter!( header, comparison_operator, search_criteria, ... )
|
38
|
+
# Filter on multiple criteria
|
39
|
+
#
|
40
|
+
# @example Filter to 'Part': 'Type1' and 'Type3', with 'Qty' greater than 1
|
41
|
+
# s.advanced_filter!( 'Part', :=~, /Type[13]/, 'Qty', :>, 1 )
|
42
|
+
#
|
43
|
+
# @example Filter to 'Part': 'Type1', with 'Ref1' containing 'X'
|
44
|
+
# s.advanced_filter!( 'Part', :==, 'Type1', 'Ref1', :include?, 'X' )
|
45
|
+
#
|
46
|
+
# @param [String] header a header to search under
|
47
|
+
# @param [Symbol] comparison_operator the operator to compare with
|
48
|
+
# @param [Object] search_criteria the value to filter by
|
49
|
+
# @raise [ArgumentError] 'Number of arguments must be a multiple of 3'
|
50
|
+
# @raise [ArgumentError] 'Operator must be a symbol'
|
51
|
+
#
|
52
|
+
|
53
|
+
def advanced_filter!( *args )
|
54
|
+
hrows = sheet.header_rows
|
55
|
+
args.length % 3 == 0 or fail ArgumentError, 'Number of arguments must be a multiple of 3'
|
56
|
+
1.step( args.length - 2, 3 ) { |i| args[i].is_a?( Symbol ) or fail ArgumentError, 'Operator must be a symbol: ' + args[i].to_s }
|
57
|
+
0.step( args.length - 3, 3 ) { |i| index_by_header( args[i] ) }
|
58
|
+
|
59
|
+
@data = @data.select.with_index do |row, i|
|
60
|
+
if hrows > i
|
61
|
+
true
|
62
|
+
else
|
63
|
+
args.each_slice(3).map do |h, op, crit|
|
64
|
+
row[ index_by_header( h ) - 1 ].send( op, crit )
|
65
|
+
end.all?
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
37
71
|
#
|
38
72
|
# Returns a copy of the data
|
39
73
|
#
|
@@ -185,12 +219,11 @@ require_relative 'address.rb'
|
|
185
219
|
# @return [self]
|
186
220
|
#
|
187
221
|
|
188
|
-
def filter
|
222
|
+
def filter( header )
|
189
223
|
hrows = sheet.header_rows
|
190
224
|
idx = index_by_header( header )
|
191
225
|
@data = @data.select.with_index { |row, i| hrows > i || yield( row[ idx -1 ] ) }
|
192
226
|
calc_dimensions
|
193
|
-
self
|
194
227
|
end
|
195
228
|
|
196
229
|
#
|
data/lib/rubyexcel/element.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
module RubyExcel
|
2
2
|
|
3
|
+
#
|
4
|
+
# A Range or Cell in a Sheet
|
5
|
+
#
|
6
|
+
|
3
7
|
class Element
|
4
8
|
include Address
|
5
9
|
include Enumerable
|
@@ -28,7 +32,7 @@ module RubyExcel
|
|
28
32
|
#
|
29
33
|
|
30
34
|
def initialize( sheet, addr )
|
31
|
-
fail ArgumentError, "Invalid range: #{ addr }" unless addr =~ /\A[A-Z]
|
35
|
+
fail ArgumentError, "Invalid range: #{ addr }" unless addr =~ /\A[A-Z]{1,3}\d+:[A-Z]{1,3}\d+\z|\A[A-Z]{1,3}\d+\z|\A[A-Z]{1,3}:[A-Z]{1,3}\z|\A\d+:\d+\z/
|
32
36
|
@sheet = sheet
|
33
37
|
@data = sheet.data
|
34
38
|
@address = addr
|
@@ -41,7 +45,7 @@ module RubyExcel
|
|
41
45
|
#
|
42
46
|
|
43
47
|
def delete
|
44
|
-
data.delete( self )
|
48
|
+
data.delete( self ); self
|
45
49
|
end
|
46
50
|
|
47
51
|
#
|
data/lib/rubyexcel/section.rb
CHANGED
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.0.
|
4
|
+
version: 0.0.8
|
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-04-
|
12
|
+
date: 2013-04-30 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: A tabular data structure, mixing Ruby with some of Excel's API style.
|
15
15
|
email: VirtuosoJoel@gmail.com
|