rubyexcel 0.0.7 → 0.0.8
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/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
|