rubyexcel 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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' ; return a if index == 1
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]+/] or fail ArgumentError, "Invalid address: #{ address }"
27
+ address[/[A-Z]+/]
29
28
  end
30
29
 
31
30
  def expand( address )
32
31
  return [[address]] unless address.include? ':'
33
- start_col, end_col, start_row, end_row = [ address[/^[A-Z]+/], address[/(?<=:)[A-Z]+/] ].sort + [ address.match(/(\d+):/).captures.first, address[/\d+$/] ].sort
34
- (start_row..end_row).map { |r| (start_col..end_col).map { |c| "#{ c }#{ r }" } }
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
 
@@ -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 do |r|
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
- self
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
- if sheet.header_cols.zero?
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
- self
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(&:length).length
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! { |ar| ar.length == cols ? ar : ar + Array.new( cols - ar.length, nil) }
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
@@ -21,11 +21,7 @@ module RubyExcel
21
21
  include Address
22
22
 
23
23
  def value
24
- if address.include? ':'
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 Excel_Tools
3
+ module ExcelConstants; end
3
4
 
4
- require 'win32ole'
5
+ module RubyExcel
5
6
 
6
- def get_excel
7
- excel = WIN32OLE::connect( 'excel.application' ) rescue WIN32OLE::new( 'excel.application' )
8
- excel.visible = true
9
- excel
10
- end
11
-
12
- def get_workbook( excel=nil )
13
- excel ||= get_excel
14
- wb = excel.workbooks.add
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
- def to_excel
36
- fail NoMethodError, 'Duplicate sheet name' if self.sheets.count != self.sheets.map(&:name).uniq.length
37
- wb = get_workbook
38
- wb.parent.DisplayAlerts = false
39
- first_time = true
40
- self.each do |s|
41
- sht = ( first_time ? wb.sheets(1) : wb.sheets.add( { 'after' => wb.sheets( wb.sheets.count ) } ) ); first_time = false
42
- sht.name = s.name
43
- make_sheet_pretty( dump_to_sheet( s.data.all, sht ) )
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
- def save_excel( filename = 'Output.xlsx' )
50
- filename = Dir.pwd.gsub('/','\\') + '\\' + filename unless filename.include?('\\')
51
- to_excel.saveas filename
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
- a=[];8.times{|t|b=[];c='A';5.times{b<<"#{c}#{t+1}";c.next!};a<<b};a
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
@@ -43,8 +43,7 @@ module RubyExcel
43
43
  alias [] read
44
44
 
45
45
  def summarise
46
- h = Hash.new(0)
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
- other.inject( @sheets, :<< )
22
- when Sheet
23
- @sheets << other
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
- s = Sheet.new( 'Sheet' + ( @sheets.count + 1 ).to_s, self )
31
- when Sheet
32
- s = ref
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
- @sheets.delete_at( ref - 1 )
53
- when String
54
- @sheets.reject! { |s| s.name == ref }
55
- when Regexp
56
- @sheets.reject! { |s| s.name =~ ref }
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
- if block_given?
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, :header_cols, :workbook
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, @header_cols = nil, nil
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
- Workbook.new.load( data.all - other )
135
- when Sheet
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
- load( data.all + other, header_rows, header_cols )
146
- when Sheet
147
- load( data.all + other.data.no_headers, header_rows, header_cols )
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, header_cols )
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
- s = dup
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, header_cols=0 )
234
- @header_rows, @header_cols = header_rows, header_cols
235
- @data = Data.new( self, input_data )
236
- self
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
- col1 = column_by_header( find_header )
267
- col2 = column_by_header( sum_header )
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.2
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-02 00:00:00.000000000 Z
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/address.rb
27
- homepage:
26
+ - lib/rubyexcel.rb
27
+ homepage: https://github.com/VirtuosoJoel
28
28
  licenses: []
29
29
  post_install_message:
30
30
  rdoc_options: []