rubyexcel 0.0.2 → 0.0.3
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 +5 -6
- data/lib/rubyexcel/data.rb +41 -24
- data/lib/rubyexcel/element.rb +5 -5
- data/lib/rubyexcel/excel_tools.rb +59 -44
- data/lib/rubyexcel/rubyexcel_components.rb +10 -1
- data/lib/rubyexcel/section.rb +13 -4
- data/lib/rubyexcel.rb +91 -83
- metadata +9 -9
data/lib/rubyexcel/address.rb
CHANGED
@@ -20,18 +20,18 @@ module RubyExcel
|
|
20
20
|
def col_letter( index )
|
21
21
|
return index if index.is_a? String
|
22
22
|
index > 0 or fail ArgumentError, 'Indexing is 1-based'
|
23
|
-
a = 'A'
|
24
|
-
(index - 1).times{ a.next! }; a
|
23
|
+
a = 'A'; ( index - 1 ).times { a.next! }; a
|
25
24
|
end
|
26
25
|
|
27
26
|
def column_id( address )
|
28
|
-
address[/[A-Z]+/]
|
27
|
+
address[/[A-Z]+/]
|
29
28
|
end
|
30
29
|
|
31
30
|
def expand( address )
|
32
31
|
return [[address]] unless address.include? ':'
|
33
|
-
|
34
|
-
|
32
|
+
address.upcase.match( /([A-Z]+)(\d+):([A-Z]+)(\d+)/i )
|
33
|
+
start_col, end_col, start_row, end_row = [ $1, $3 ].sort + [ $2.to_i, $4.to_i ].sort
|
34
|
+
( start_row..end_row ).map { |r| ( start_col..end_col ).map { |c| c + r.to_s } }
|
35
35
|
end
|
36
36
|
|
37
37
|
def indices_to_address( row_idx, column_idx )
|
@@ -56,7 +56,6 @@ module RubyExcel
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def row_id( address )
|
59
|
-
return nil unless address
|
60
59
|
address[/\d+/].to_i
|
61
60
|
end
|
62
61
|
|
data/lib/rubyexcel/data.rb
CHANGED
@@ -10,8 +10,8 @@ require_relative 'address.rb'
|
|
10
10
|
include Address
|
11
11
|
|
12
12
|
def initialize( sheet, input_data )
|
13
|
-
@sheet = sheet
|
14
13
|
( input_data.kind_of?( Array ) && input_data.all? { |el| el.kind_of?( Array ) } ) or fail ArgumentError, 'Input must be Array of Arrays'
|
14
|
+
@sheet = sheet
|
15
15
|
@data = input_data.dup
|
16
16
|
calc_dimensions
|
17
17
|
end
|
@@ -21,18 +21,13 @@ require_relative 'address.rb'
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def append( multi_array )
|
24
|
-
@data
|
25
|
-
@data += multi_array
|
24
|
+
@data << multi_array
|
26
25
|
calc_dimensions
|
27
26
|
end
|
28
27
|
|
29
28
|
def colref_by_header( header )
|
30
29
|
sheet.header_rows > 0 or fail NoMethodError, 'No header rows present'
|
31
|
-
@data[ 0..sheet.header_rows-1 ].each
|
32
|
-
if ( idx = r.index( header ) )
|
33
|
-
return col_letter( idx+1 )
|
34
|
-
end
|
35
|
-
end
|
30
|
+
@data[ 0..sheet.header_rows-1 ].each { |r| idx = r.index( header ); return col_letter( idx+1 ) if idx }
|
36
31
|
fail IndexError, "#{ header } is not a valid header"
|
37
32
|
end
|
38
33
|
|
@@ -45,13 +40,11 @@ require_relative 'address.rb'
|
|
45
40
|
ensure_shape
|
46
41
|
@data = @data.transpose.delete_if { |ar| ar.all? { |el| el.to_s.empty? } || ar.empty? }.transpose
|
47
42
|
calc_dimensions
|
48
|
-
@data
|
49
43
|
end
|
50
44
|
|
51
45
|
def compact_rows!
|
52
46
|
@data.delete_if { |ar| ar.all? { |el| el.to_s.empty? } || ar.empty? }
|
53
47
|
calc_dimensions
|
54
|
-
@data
|
55
48
|
end
|
56
49
|
|
57
50
|
def delete( object )
|
@@ -69,19 +62,22 @@ require_relative 'address.rb'
|
|
69
62
|
else
|
70
63
|
fail NoMethodError, "#{ object.class } is not supported"
|
71
64
|
end
|
72
|
-
|
65
|
+
calc_dimensions
|
73
66
|
end
|
74
67
|
|
75
68
|
def delete_column( ref )
|
76
69
|
delete( Column.new( sheet, ref ) )
|
70
|
+
calc_dimensions
|
77
71
|
end
|
78
72
|
|
79
73
|
def delete_row( ref )
|
80
74
|
delete( Row.new( sheet, ref ) )
|
75
|
+
calc_dimensions
|
81
76
|
end
|
82
77
|
|
83
78
|
def delete_range( ref )
|
84
79
|
delete( Element.new( sheet, ref ) )
|
80
|
+
calc_dimensions
|
85
81
|
end
|
86
82
|
|
87
83
|
def dup
|
@@ -97,35 +93,31 @@ require_relative 'address.rb'
|
|
97
93
|
idx = col_index( hrows > 0 ? colref_by_header( header ) : header )
|
98
94
|
@data = @data.select.with_index { |row, i| hrows > i || yield( row[ idx -1 ] ) }
|
99
95
|
calc_dimensions
|
100
|
-
self
|
101
96
|
end
|
102
97
|
|
103
98
|
def get_columns!( *headers )
|
99
|
+
headers = headers.flatten
|
104
100
|
hrow = sheet.header_rows - 1
|
105
101
|
ensure_shape
|
106
102
|
@data = @data.transpose.select{ |col| headers.include?( col[hrow] ) }
|
107
|
-
ensure_shape
|
108
103
|
@data = @data.sort_by{ |col| headers.index( col[hrow] ) || col[hrow] }.transpose
|
109
104
|
calc_dimensions
|
110
|
-
self
|
111
105
|
end
|
112
|
-
|
106
|
+
|
113
107
|
def insert_columns( before, number=1 )
|
114
108
|
a = Array.new( number, nil )
|
115
109
|
before = col_index( before ) - 1
|
116
110
|
@data.map! { |row| row.insert( before, *a ) }
|
111
|
+
calc_dimensions
|
117
112
|
end
|
118
113
|
|
119
114
|
def insert_rows( before, number=1 )
|
120
115
|
@data = @data.insert( ( col_index( before ) - 1 ), *Array.new( number, [nil] ) )
|
116
|
+
calc_dimensions
|
121
117
|
end
|
122
118
|
|
123
119
|
def no_headers
|
124
|
-
|
125
|
-
@data[ sheet.header_rows..-1 ].dup
|
126
|
-
else
|
127
|
-
@data[ sheet.header_rows..-1 ].map { |row| row[ sheet.header_cols..-1 ] }
|
128
|
-
end
|
120
|
+
@data[ sheet.header_rows..-1 ]
|
129
121
|
end
|
130
122
|
|
131
123
|
def read( addr )
|
@@ -134,10 +126,27 @@ require_relative 'address.rb'
|
|
134
126
|
end
|
135
127
|
alias [] read
|
136
128
|
|
129
|
+
def reverse_columns!
|
130
|
+
ensure_shape
|
131
|
+
@data = @data.transpose.reverse.transpose
|
132
|
+
end
|
133
|
+
|
134
|
+
def reverse_rows!
|
135
|
+
@data = skip_headers &:reverse
|
136
|
+
end
|
137
|
+
|
138
|
+
def sort!( &block )
|
139
|
+
@data = skip_headers { |d| d.sort( &block ) }; self
|
140
|
+
end
|
141
|
+
|
142
|
+
def sort_by!( &block )
|
143
|
+
@data = skip_headers { |d| d.sort_by( &block ) }
|
144
|
+
end
|
145
|
+
|
137
146
|
def uniq!( header )
|
138
147
|
column = col_index( colref_by_header( header ) )
|
139
148
|
@data = @data.uniq { |row| row[ column - 1 ] }
|
140
|
-
|
149
|
+
calc_dimensions
|
141
150
|
end
|
142
151
|
alias unique! uniq!
|
143
152
|
|
@@ -158,15 +167,23 @@ require_relative 'address.rb'
|
|
158
167
|
private
|
159
168
|
|
160
169
|
def calc_dimensions
|
161
|
-
@rows, @cols = @data.length, @data.max_by
|
170
|
+
@rows, @cols = @data.length, @data.max_by { |row| row.length }.length; self
|
162
171
|
end
|
163
172
|
|
164
173
|
def ensure_shape
|
165
174
|
calc_dimensions
|
166
|
-
@data.map
|
167
|
-
@data
|
175
|
+
@data = @data.map { |ar| ar.length == cols ? ar : ar + Array.new( cols - ar.length, nil) }
|
168
176
|
end
|
169
177
|
|
178
|
+
def skip_headers
|
179
|
+
hr = sheet.header_rows
|
180
|
+
if hr > 0
|
181
|
+
block_given? ? @data[ 0..hr - 1 ] + yield( @data[ hr..-1 ] ) : @data[ hr..-1 ]
|
182
|
+
else
|
183
|
+
block_given? ? yield( @data ) : @data
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
170
187
|
end
|
171
188
|
|
172
189
|
end
|
data/lib/rubyexcel/element.rb
CHANGED
@@ -21,11 +21,7 @@ module RubyExcel
|
|
21
21
|
include Address
|
22
22
|
|
23
23
|
def value
|
24
|
-
|
25
|
-
expand( address ).map { |ar| ar.map { |addr| data[ addr ] } }
|
26
|
-
else
|
27
|
-
data[ address ]
|
28
|
-
end
|
24
|
+
address.include?( ':' ) ? expand( address ).map { |ar| ar.map { |addr| data[ addr ] } } : data[ address ]
|
29
25
|
end
|
30
26
|
|
31
27
|
def value=( val )
|
@@ -58,6 +54,10 @@ module RubyExcel
|
|
58
54
|
def each_cell
|
59
55
|
expand( address ).flatten.each { |addr| yield Element.new( sheet, addr ) }
|
60
56
|
end
|
57
|
+
|
58
|
+
def empty?
|
59
|
+
all? { |v| v.to_s.empty? }
|
60
|
+
end
|
61
61
|
|
62
62
|
def map!
|
63
63
|
expand( address ).flatten.each { |addr| data[ addr ] = yield data[ addr ] }
|
@@ -1,54 +1,69 @@
|
|
1
|
+
require 'win32ole'
|
1
2
|
|
2
|
-
module
|
3
|
+
module ExcelConstants; end
|
3
4
|
|
4
|
-
|
5
|
+
module RubyExcel
|
5
6
|
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
( ( wb.sheets.count.to_i ) - 1 ).times { |time| wb.sheets(2).delete }
|
16
|
-
wb
|
17
|
-
end
|
18
|
-
|
19
|
-
def dump_to_sheet( data, sheet=nil )
|
20
|
-
fail ArgumentError, "Invalid data type: #{ data.class }" unless data.is_a?( Array ) || data.is_a?( RubyExcel )
|
21
|
-
data = data.to_a if data.is_a? RubyExcel
|
22
|
-
sheet ||= get_workbook.sheets(1)
|
23
|
-
sheet.range( sheet.cells( 1, 1 ), sheet.cells( data.length, data[0].length ) ).value = data
|
24
|
-
sheet
|
25
|
-
end
|
26
|
-
|
27
|
-
def make_sheet_pretty( sheet )
|
28
|
-
c = sheet.cells
|
29
|
-
c.EntireColumn.AutoFit
|
30
|
-
c.HorizontalAlignment = -4108
|
31
|
-
c.VerticalAlignment = -4108
|
32
|
-
sheet
|
7
|
+
def self.borders( range, weight=1, inner=false )
|
8
|
+
range.ole_respond_to?( :borders ) or fail ArgumentError, 'First Argument must be WIN32OLE Range'
|
9
|
+
[0,1,2,3].include?( weight ) or fail ArgumentError, "Invalid line weight #{ weight }. Must be from 0 to 3"
|
10
|
+
defined?( ExcelConstants::XlEdgeLeft ) or WIN32OLE.const_load( range.application, ExcelConstants )
|
11
|
+
consts = [ ExcelConstants::XlEdgeLeft, ExcelConstants::XlEdgeTop, ExcelConstants::XlEdgeBottom, ExcelConstants::XlEdgeRight, ExcelConstants::XlInsideVertical, ExcelConstants::XlInsideHorizontal ]
|
12
|
+
inner or consts.pop(2)
|
13
|
+
weight = [ 0, ExcelConstants::XlThin, ExcelConstants::XlMedium, ExcelConstants::XlThick ][ weight ]
|
14
|
+
consts.each { |const| weight.zero? ? range.Borders( const ).linestyle = ExcelConstants::XlNone : range.Borders( const ).weight = weight }
|
15
|
+
range
|
33
16
|
end
|
17
|
+
|
18
|
+
class Workbook
|
34
19
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
20
|
+
def dump_to_sheet( data, sheet=nil )
|
21
|
+
data.is_a?( Array ) or fail ArgumentError, "Invalid data type: #{ data.class }"
|
22
|
+
sheet ||= get_workbook.sheets(1)
|
23
|
+
sheet.range( sheet.cells( 1, 1 ), sheet.cells( data.length, data[0].length ) ).value = data
|
24
|
+
sheet
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_excel
|
28
|
+
excel = WIN32OLE::connect( 'excel.application' ) rescue WIN32OLE::new( 'excel.application' )
|
29
|
+
excel.visible = true
|
30
|
+
excel
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_workbook( excel=nil )
|
34
|
+
excel ||= get_excel
|
35
|
+
wb = excel.workbooks.add
|
36
|
+
( ( wb.sheets.count.to_i ) - 1 ).times { |time| wb.sheets(2).delete }
|
37
|
+
wb
|
44
38
|
end
|
45
|
-
wb.sheets(1).select
|
46
|
-
wb
|
47
|
-
end
|
48
39
|
|
49
|
-
|
50
|
-
|
51
|
-
|
40
|
+
def make_sheet_pretty( sheet )
|
41
|
+
c = sheet.cells
|
42
|
+
c.entireColumn.autoFit
|
43
|
+
c.horizontalAlignment = -4108
|
44
|
+
c.verticalAlignment = -4108
|
45
|
+
sheet
|
46
|
+
end
|
47
|
+
|
48
|
+
def save_excel( filename = 'Output.xlsx' )
|
49
|
+
filename = Dir.pwd.gsub('/','\\') + '\\' + filename unless filename.include?('\\')
|
50
|
+
to_excel.saveas filename
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_excel
|
54
|
+
self.sheets.count == self.sheets.map(&:name).uniq.length or fail NoMethodError, 'Duplicate sheet name'
|
55
|
+
wb = get_workbook
|
56
|
+
wb.parent.displayAlerts = false
|
57
|
+
first_time = true
|
58
|
+
self.each do |s|
|
59
|
+
sht = ( first_time ? wb.sheets(1) : wb.sheets.add( { 'after' => wb.sheets( wb.sheets.count ) } ) ); first_time = false
|
60
|
+
sht.name = s.name
|
61
|
+
make_sheet_pretty( dump_to_sheet( s.data.all, sht ) )
|
62
|
+
end
|
63
|
+
wb.sheets(1).select
|
64
|
+
wb
|
65
|
+
end
|
66
|
+
|
52
67
|
end
|
53
68
|
|
54
69
|
end
|
@@ -6,7 +6,16 @@ require_relative 'section.rb'
|
|
6
6
|
module RubyExcel
|
7
7
|
|
8
8
|
def self.sample_data
|
9
|
-
|
9
|
+
[
|
10
|
+
[ 'Part', 'Ref1', 'Ref2', 'Qty', 'Cost' ],
|
11
|
+
[ 'Type1', 'QT1', '231', 1, 35.15 ],
|
12
|
+
[ 'Type2', 'QT3', '123', 1, 40 ],
|
13
|
+
[ 'Type3', 'XT1', '321', 3, 0.1 ],
|
14
|
+
[ 'Type1', 'XY2', '132', 1, 30.00 ],
|
15
|
+
[ 'Type4', 'XT3', '312', 2, 3 ],
|
16
|
+
[ 'Type2', 'QY2', '213', 1, 99.99 ],
|
17
|
+
[ 'Type1', 'QT4', '123', 2, 104 ]
|
18
|
+
]
|
10
19
|
end
|
11
20
|
|
12
21
|
def self.sample_sheet
|
data/lib/rubyexcel/section.rb
CHANGED
@@ -43,8 +43,7 @@ module RubyExcel
|
|
43
43
|
alias [] read
|
44
44
|
|
45
45
|
def summarise
|
46
|
-
|
47
|
-
each_wh { |v| h[v]+=1 }; h
|
46
|
+
each_wh.inject( Hash.new(0) ) { |h, v| h[v]+=1; h }
|
48
47
|
end
|
49
48
|
alias summarize summarise
|
50
49
|
|
@@ -75,6 +74,12 @@ module RubyExcel
|
|
75
74
|
each_address { |addr| yield Element.new( sheet, addr ) }
|
76
75
|
end
|
77
76
|
|
77
|
+
def each_cell_without_headers
|
78
|
+
return to_enum(:each_cell) unless block_given?
|
79
|
+
each_address { |addr| yield Element.new( sheet, addr ) }
|
80
|
+
end
|
81
|
+
alias each_cell_wh each_cell_without_headers
|
82
|
+
|
78
83
|
def map!
|
79
84
|
return to_enum(:map!) unless block_given?
|
80
85
|
each_address { |addr| data[addr] = ( yield data[addr] ) }
|
@@ -84,8 +89,7 @@ module RubyExcel
|
|
84
89
|
|
85
90
|
def translate_address( addr )
|
86
91
|
case self
|
87
|
-
when Row
|
88
|
-
col_letter( addr ) + idx.to_s
|
92
|
+
when Row ; col_letter( addr ) + idx.to_s
|
89
93
|
when Column
|
90
94
|
addr = addr.to_s unless addr.is_a?( String )
|
91
95
|
fail ArgumentError, "Invalid address : #{ addr }" if addr =~ /[^\d]/
|
@@ -107,6 +111,11 @@ module RubyExcel
|
|
107
111
|
def getref( header )
|
108
112
|
column_id( sheet.row(1).find &/#{header}/ )
|
109
113
|
end
|
114
|
+
|
115
|
+
def value_by_header( header )
|
116
|
+
self[ getref( header ) ]
|
117
|
+
end
|
118
|
+
alias val value_by_header
|
110
119
|
|
111
120
|
private
|
112
121
|
|
data/lib/rubyexcel.rb
CHANGED
@@ -17,53 +17,42 @@ module RubyExcel
|
|
17
17
|
|
18
18
|
def <<( other )
|
19
19
|
case other
|
20
|
-
when Workbook
|
21
|
-
|
22
|
-
when
|
23
|
-
|
20
|
+
when Workbook ; other.each { |sht| sht.workbook = self; @sheets << sht }
|
21
|
+
when Sheet ; @sheets << other; other.workbook = self
|
22
|
+
when Array ; @sheets << add.load( other )
|
23
|
+
else ; fail TypeError, "Unsupported Type: #{ other.class }"
|
24
24
|
end
|
25
|
+
self
|
25
26
|
end
|
26
27
|
|
27
28
|
def add( ref=nil )
|
28
29
|
case ref
|
29
|
-
when nil
|
30
|
-
|
31
|
-
when Sheet
|
32
|
-
|
33
|
-
s.workbook = self
|
34
|
-
when String
|
35
|
-
s = Sheet.new( ref, self )
|
36
|
-
else
|
37
|
-
fail TypeError, "Unsupported Type: #{ ref.class }"
|
30
|
+
when nil ; s = Sheet.new( 'Sheet' + ( @sheets.count + 1 ).to_s, self )
|
31
|
+
when Sheet ; ( s = ref ).workbook = self
|
32
|
+
when String ; s = Sheet.new( ref, self )
|
33
|
+
else ; fail TypeError, "Unsupported Type: #{ ref.class }"
|
38
34
|
end
|
39
|
-
@sheets << s
|
40
|
-
s
|
35
|
+
@sheets << s; s
|
41
36
|
end
|
42
37
|
alias add_sheet add
|
43
38
|
|
44
39
|
def clear_all
|
45
|
-
@sheets = []
|
46
|
-
self
|
40
|
+
@sheets = []; self
|
47
41
|
end
|
48
42
|
|
49
43
|
def delete( ref )
|
50
44
|
case ref
|
51
|
-
when Fixnum
|
52
|
-
|
53
|
-
when
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
when Sheet
|
58
|
-
@sheets.reject! { |s| s == ref }
|
59
|
-
else
|
60
|
-
fail ArgumentError, "Unrecognised Argument Type: #{ ref.class }"
|
61
|
-
end
|
45
|
+
when Fixnum ; @sheets.delete_at( ref - 1 )
|
46
|
+
when String ; @sheets.reject! { |s| s.name == ref }
|
47
|
+
when Regexp ; @sheets.reject! { |s| s.name =~ ref }
|
48
|
+
when Sheet ; @sheets.reject! { |s| s == ref }
|
49
|
+
else ; fail ArgumentError, "Unrecognised Argument Type: #{ ref.class }"
|
50
|
+
end ; self
|
62
51
|
end
|
63
52
|
|
64
53
|
def dup
|
65
54
|
wb = Workbook.new
|
66
|
-
self.each {|s| wb.add s.dup }
|
55
|
+
self.each { |s| wb.add s.dup }
|
67
56
|
wb
|
68
57
|
end
|
69
58
|
|
@@ -80,14 +69,13 @@ module RubyExcel
|
|
80
69
|
ref.is_a?( Fixnum ) ? @sheets[ ref - 1 ] : @sheets.find { |s| s.name =~ /^#{ ref }$/i }
|
81
70
|
end
|
82
71
|
|
72
|
+
def sort!
|
73
|
+
@sheets = @sheets.sort(&block)
|
74
|
+
end
|
75
|
+
|
83
76
|
def sort_by!( &block )
|
84
|
-
|
85
|
-
@sheets = @sheets.sort_by(&block)
|
86
|
-
else
|
87
|
-
@sheets = @sheets.sort_by(&:name)
|
88
|
-
end
|
77
|
+
@sheets = @sheets.sort_by(&block)
|
89
78
|
end
|
90
|
-
alias sort! sort_by!
|
91
79
|
|
92
80
|
include Enumerable
|
93
81
|
|
@@ -96,22 +84,21 @@ module RubyExcel
|
|
96
84
|
@sheets.each { |s| yield s }
|
97
85
|
end
|
98
86
|
|
99
|
-
include Excel_Tools
|
100
|
-
|
101
87
|
end
|
102
88
|
|
103
89
|
class Sheet
|
104
90
|
|
105
91
|
attr_reader :data
|
106
|
-
attr_accessor :name, :header_rows, :
|
107
|
-
alias parent workbook
|
92
|
+
attr_accessor :name, :header_rows, :workbook
|
93
|
+
alias parent workbook; alias parent= workbook=
|
94
|
+
alias headers header_rows; alias headers= header_rows=
|
108
95
|
|
109
96
|
include Address
|
110
97
|
|
111
98
|
def initialize( name, workbook )
|
112
99
|
@workbook = workbook
|
113
100
|
@name = name
|
114
|
-
@header_rows
|
101
|
+
@header_rows = nil
|
115
102
|
@data = Data.new( self, [[]] )
|
116
103
|
end
|
117
104
|
|
@@ -130,23 +117,18 @@ module RubyExcel
|
|
130
117
|
|
131
118
|
def -( other )
|
132
119
|
case other
|
133
|
-
when Array
|
134
|
-
|
135
|
-
|
136
|
-
Workbook.new.load( data.all - other.data.no_headers )
|
137
|
-
else
|
138
|
-
fail ArgumentError, "Unsupported class: #{ other.class }"
|
120
|
+
when Array ; Workbook.new.load( data.all - other )
|
121
|
+
when Sheet ; Workbook.new.load( data.all - other.data.no_headers )
|
122
|
+
else ; fail ArgumentError, "Unsupported class: #{ other.class }"
|
139
123
|
end
|
140
124
|
end
|
141
125
|
|
142
126
|
def <<( other )
|
143
127
|
case other
|
144
|
-
when Array
|
145
|
-
|
146
|
-
when Sheet
|
147
|
-
|
148
|
-
else
|
149
|
-
fail ArgumentError, "Unsupported class: #{ other.class }"
|
128
|
+
when Array ; load( data.all + other, header_rows )
|
129
|
+
when Hash ; load( data.all + _convert_hash( other ) )
|
130
|
+
when Sheet ; load( data.all + other.data.no_headers, header_rows )
|
131
|
+
else ; fail ArgumentError, "Unsupported class: #{ other.class }"
|
150
132
|
end
|
151
133
|
end
|
152
134
|
|
@@ -165,26 +147,32 @@ module RubyExcel
|
|
165
147
|
alias ch column_by_header
|
166
148
|
|
167
149
|
def columns( start_column = 'A', end_column = data.cols )
|
168
|
-
start_column, end_column = col_letter( start_column ), col_letter( end_column )
|
169
150
|
return to_enum(:columns, start_column, end_column) unless block_given?
|
170
|
-
( start_column..end_column ).each { |idx| yield column( idx ) }
|
151
|
+
( col_letter( start_column )..col_letter( end_column ) ).each { |idx| yield column( idx ) }; self
|
171
152
|
end
|
172
153
|
|
173
154
|
def compact!
|
174
|
-
data.compact
|
175
|
-
self
|
155
|
+
data.compact!; self
|
176
156
|
end
|
177
157
|
|
178
158
|
def delete
|
179
159
|
workbook.delete self
|
180
160
|
end
|
181
161
|
|
162
|
+
def delete_rows_if
|
163
|
+
rows.reverse_each { |r| r.delete if yield r }; self
|
164
|
+
end
|
165
|
+
|
166
|
+
def delete_columns_if
|
167
|
+
columns.reverse_each { |c| c.delete if yield c }; self
|
168
|
+
end
|
169
|
+
|
182
170
|
def dup
|
183
171
|
s = Sheet.new( name, workbook )
|
184
172
|
d = data
|
185
173
|
unless d.nil?
|
186
174
|
d = d.dup
|
187
|
-
s.load( d.all, header_rows
|
175
|
+
s.load( d.all, header_rows )
|
188
176
|
d.sheet = s
|
189
177
|
end
|
190
178
|
s
|
@@ -199,41 +187,36 @@ module RubyExcel
|
|
199
187
|
end
|
200
188
|
|
201
189
|
def filter!( ref, &block )
|
202
|
-
data.filter!( ref, &block )
|
203
|
-
self
|
190
|
+
data.filter!( ref, &block ); self
|
204
191
|
end
|
205
192
|
|
206
193
|
def get_columns( *headers )
|
207
|
-
|
208
|
-
s.data.get_columns!( *headers )
|
209
|
-
s
|
194
|
+
dup.data.get_columns!( *headers )
|
210
195
|
end
|
211
196
|
alias gc get_columns
|
212
197
|
|
213
198
|
def get_columns!( *headers )
|
214
|
-
data.get_columns!( *headers )
|
215
|
-
self
|
199
|
+
data.get_columns!( *headers ); self
|
216
200
|
end
|
217
201
|
alias gc! get_columns!
|
218
202
|
|
219
203
|
def insert_columns( *args )
|
220
|
-
data.insert_columns( *args )
|
221
|
-
self
|
204
|
+
data.insert_columns( *args ); self
|
222
205
|
end
|
223
206
|
|
224
207
|
def insert_rows( *args )
|
225
|
-
data.insert_rows( *args )
|
226
|
-
self
|
208
|
+
data.insert_rows( *args ); self
|
227
209
|
end
|
228
210
|
|
229
211
|
def inspect
|
230
212
|
"#{ self.class }:0x#{ '%x' % (object_id << 1) }: #{ name }"
|
231
213
|
end
|
232
214
|
|
233
|
-
def load( input_data, header_rows=1
|
234
|
-
|
235
|
-
|
236
|
-
|
215
|
+
def load( input_data, header_rows=1 )
|
216
|
+
input_data = _convert_hash(input_data) if input_data.is_a?(Hash)
|
217
|
+
input_data.is_a?(Array) or fail ArgumentError, 'Input must be an Array or Hash'
|
218
|
+
@header_rows = header_rows
|
219
|
+
@data = Data.new( self, input_data ); self
|
237
220
|
end
|
238
221
|
|
239
222
|
def match( header, &block )
|
@@ -252,6 +235,14 @@ module RubyExcel
|
|
252
235
|
def range( first_cell, last_cell=nil )
|
253
236
|
Element.new( self, to_range_address( first_cell, last_cell ) )
|
254
237
|
end
|
238
|
+
|
239
|
+
def reverse_columns!
|
240
|
+
data.reverse_columns!
|
241
|
+
end
|
242
|
+
|
243
|
+
def reverse_rows!
|
244
|
+
data.reverse_rows!
|
245
|
+
end
|
255
246
|
|
256
247
|
def row( index )
|
257
248
|
Row.new( self, index )
|
@@ -259,17 +250,20 @@ module RubyExcel
|
|
259
250
|
|
260
251
|
def rows( start_row = 1, end_row = data.rows )
|
261
252
|
return to_enum(:rows, start_row, end_row) unless block_given?
|
262
|
-
( start_row..end_row ).each { |idx| yield row( idx ) }
|
253
|
+
( start_row..end_row ).each { |idx| yield row( idx ) }; self
|
254
|
+
end
|
255
|
+
|
256
|
+
def sort!( &block )
|
257
|
+
data.sort!( &block ); self
|
258
|
+
end
|
259
|
+
|
260
|
+
def sort_by!( &block )
|
261
|
+
data.sort_by!( &block ); self
|
263
262
|
end
|
264
263
|
|
265
264
|
def sumif( find_header, sum_header )
|
266
|
-
|
267
|
-
|
268
|
-
total = 0
|
269
|
-
col1.each_cell do |ce|
|
270
|
-
total += col2[ ce.row ].to_i if yield( ce.value ) && ce.row >= header_rows
|
271
|
-
end
|
272
|
-
total
|
265
|
+
find_col, sum_col = ch( find_header ), ch( sum_header )
|
266
|
+
find_col.each_cell.inject(0) { |sum,ce| yield( ce.value ) && ce.row > header_rows ? sum + sum_col[ ce.row ] : sum }
|
273
267
|
end
|
274
268
|
|
275
269
|
def to_a
|
@@ -281,15 +275,29 @@ module RubyExcel
|
|
281
275
|
end
|
282
276
|
|
283
277
|
def to_s
|
284
|
-
data.nil? ? '' : data.map { |ar| ar.join "\t" }.join( $/ )
|
278
|
+
data.nil? ? '' : data.map { |ar| ar.map { |v| v.to_s.gsub(/\t|\n/,' ') }.join "\t" }.join( $/ )
|
285
279
|
end
|
286
280
|
|
287
281
|
def uniq!( header )
|
288
|
-
data.uniq!( header )
|
289
|
-
self
|
282
|
+
data.uniq!( header ); self
|
290
283
|
end
|
291
284
|
alias unique! uniq!
|
292
285
|
|
286
|
+
def vlookup( find_header, return_header, &block )
|
287
|
+
find_col, return_col = ch( find_header ), ch( return_header )
|
288
|
+
return_col[ row_id( find_col.find( &block ) ) ] rescue nil
|
289
|
+
end
|
290
|
+
|
291
|
+
private
|
292
|
+
|
293
|
+
def _hash_to_a(h)
|
294
|
+
h.map { |k,v| v.is_a?(Hash) ? _hash_to_a(v).map { |val| ([ k ] + [ val ]).flatten(1) } : [ k, v ] }.flatten(1)
|
295
|
+
end
|
296
|
+
|
297
|
+
def _convert_hash(h)
|
298
|
+
_hash_to_a(h).each_slice(2).map { |a1,a2| a1 << a2.last }
|
299
|
+
end
|
300
|
+
|
293
301
|
end
|
294
302
|
|
295
303
|
end
|
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.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,22 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-10 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
|
-
description: A tabular data structure, mixing Ruby with some of Excel's API.
|
15
|
-
email:
|
14
|
+
description: A tabular data structure, mixing Ruby with some of Excel's API style.
|
15
|
+
email: VirtuosoJoel@gmail.com
|
16
16
|
executables: []
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
|
-
- lib/rubyexcel.rb
|
21
|
-
- lib/rubyexcel/excel_tools.rb
|
22
|
-
- lib/rubyexcel/rubyexcel_components.rb
|
20
|
+
- lib/rubyexcel/address.rb
|
23
21
|
- lib/rubyexcel/data.rb
|
24
22
|
- lib/rubyexcel/element.rb
|
23
|
+
- lib/rubyexcel/excel_tools.rb
|
24
|
+
- lib/rubyexcel/rubyexcel_components.rb
|
25
25
|
- lib/rubyexcel/section.rb
|
26
|
-
- lib/rubyexcel
|
27
|
-
homepage:
|
26
|
+
- lib/rubyexcel.rb
|
27
|
+
homepage: https://github.com/VirtuosoJoel
|
28
28
|
licenses: []
|
29
29
|
post_install_message:
|
30
30
|
rdoc_options: []
|