rubyexcel 0.0.1 → 0.0.2

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.
@@ -0,0 +1,65 @@
1
+ module RubyExcel
2
+
3
+ module Address
4
+
5
+ def address_to_col_index( address )
6
+ col_index( column_id( address ) )
7
+ end
8
+
9
+ def address_to_indices( address )
10
+ [ row_id( address ), address_to_col_index( address ) ]
11
+ end
12
+
13
+ def col_index( letter )
14
+ return letter if letter.is_a? Fixnum
15
+ letter !~ /[^A-Z]/ && [1,2,3].include?( letter.length ) or fail ArgumentError, "Invalid column reference: #{ letter }"
16
+ idx, a = 1, 'A'
17
+ loop { return idx if a == letter; idx+=1; a.next! }
18
+ end
19
+
20
+ def col_letter( index )
21
+ return index if index.is_a? String
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
25
+ end
26
+
27
+ def column_id( address )
28
+ address[/[A-Z]+/] or fail ArgumentError, "Invalid address: #{ address }"
29
+ end
30
+
31
+ def expand( address )
32
+ 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 }" } }
35
+ end
36
+
37
+ def indices_to_address( row_idx, column_idx )
38
+ [ row_idx, column_idx ].all? { |a| a.is_a?( Fixnum ) } or fail ArgumentError, 'Input must be Fixnum'
39
+ col_letter( column_idx ) + row_idx.to_s
40
+ end
41
+
42
+ def multi_array?( obj )
43
+ obj.all? { |el| el.is_a?( Array ) } && obj.is_a?( Array ) rescue false
44
+ end
45
+
46
+ def offset(address, row, col)
47
+ ( col_letter( address_to_col_index( address ) + col ) ) + ( row_id( address ) + row ).to_s
48
+ end
49
+
50
+ def to_range_address( obj1, obj2 )
51
+ if obj2
52
+ obj2.is_a?( String ) ? ( obj1 + ':' + obj2 ) : "#{ obj1.address }:#{ obj2.address }"
53
+ else
54
+ obj1.is_a?( String ) ? obj1 : obj1.address
55
+ end
56
+ end
57
+
58
+ def row_id( address )
59
+ return nil unless address
60
+ address[/\d+/].to_i
61
+ end
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,172 @@
1
+ module RubyExcel
2
+
3
+ require_relative 'address.rb'
4
+
5
+ class Data
6
+ attr_reader :rows, :cols
7
+ attr_accessor :sheet
8
+ alias parent sheet
9
+
10
+ include Address
11
+
12
+ def initialize( sheet, input_data )
13
+ @sheet = sheet
14
+ ( input_data.kind_of?( Array ) && input_data.all? { |el| el.kind_of?( Array ) } ) or fail ArgumentError, 'Input must be Array of Arrays'
15
+ @data = input_data.dup
16
+ calc_dimensions
17
+ end
18
+
19
+ def all
20
+ @data.dup
21
+ end
22
+
23
+ def append( multi_array )
24
+ @data
25
+ @data += multi_array
26
+ calc_dimensions
27
+ end
28
+
29
+ def colref_by_header( header )
30
+ 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
36
+ fail IndexError, "#{ header } is not a valid header"
37
+ end
38
+
39
+ def compact!
40
+ compact_columns!
41
+ compact_rows!
42
+ end
43
+
44
+ def compact_columns!
45
+ ensure_shape
46
+ @data = @data.transpose.delete_if { |ar| ar.all? { |el| el.to_s.empty? } || ar.empty? }.transpose
47
+ calc_dimensions
48
+ @data
49
+ end
50
+
51
+ def compact_rows!
52
+ @data.delete_if { |ar| ar.all? { |el| el.to_s.empty? } || ar.empty? }
53
+ calc_dimensions
54
+ @data
55
+ end
56
+
57
+ def delete( object )
58
+ case object
59
+ when Row
60
+ @data.slice!( object.idx - 1 )
61
+ when Column
62
+ idx = col_index( object.idx ) - 1
63
+ @data.each { |r| r.slice! idx }
64
+ when Element
65
+ addresses = expand( object.address )
66
+ indices = [ address_to_indices( addresses.first.first ), address_to_indices( addresses.last.last ) ].flatten.map { |n| n-1 }
67
+ @data[ indices[0]..indices[2] ].each { |r| r.slice!( indices[1], indices[3] - indices[1] + 1 ) }
68
+ @data.delete_if.with_index { |r,i| r.empty? && i.between?( indices[0], indices[2] ) }
69
+ else
70
+ fail NoMethodError, "#{ object.class } is not supported"
71
+ end
72
+ self
73
+ end
74
+
75
+ def delete_column( ref )
76
+ delete( Column.new( sheet, ref ) )
77
+ end
78
+
79
+ def delete_row( ref )
80
+ delete( Row.new( sheet, ref ) )
81
+ end
82
+
83
+ def delete_range( ref )
84
+ delete( Element.new( sheet, ref ) )
85
+ end
86
+
87
+ def dup
88
+ Data.new( sheet, @data.dup )
89
+ end
90
+
91
+ def empty?
92
+ no_headers.empty?
93
+ end
94
+
95
+ def filter!( header )
96
+ hrows = sheet.header_rows
97
+ idx = col_index( hrows > 0 ? colref_by_header( header ) : header )
98
+ @data = @data.select.with_index { |row, i| hrows > i || yield( row[ idx -1 ] ) }
99
+ calc_dimensions
100
+ self
101
+ end
102
+
103
+ def get_columns!( *headers )
104
+ hrow = sheet.header_rows - 1
105
+ ensure_shape
106
+ @data = @data.transpose.select{ |col| headers.include?( col[hrow] ) }
107
+ ensure_shape
108
+ @data = @data.sort_by{ |col| headers.index( col[hrow] ) || col[hrow] }.transpose
109
+ calc_dimensions
110
+ self
111
+ end
112
+
113
+ def insert_columns( before, number=1 )
114
+ a = Array.new( number, nil )
115
+ before = col_index( before ) - 1
116
+ @data.map! { |row| row.insert( before, *a ) }
117
+ end
118
+
119
+ def insert_rows( before, number=1 )
120
+ @data = @data.insert( ( col_index( before ) - 1 ), *Array.new( number, [nil] ) )
121
+ end
122
+
123
+ 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
129
+ end
130
+
131
+ def read( addr )
132
+ row_idx, col_idx = address_to_indices( addr )
133
+ @data[ row_idx-1 ][ col_idx-1 ]
134
+ end
135
+ alias [] read
136
+
137
+ def uniq!( header )
138
+ column = col_index( colref_by_header( header ) )
139
+ @data = @data.uniq { |row| row[ column - 1 ] }
140
+ self
141
+ end
142
+ alias unique! uniq!
143
+
144
+ def write( addr, val )
145
+ row_idx, col_idx = address_to_indices( addr )
146
+ ( row_idx - rows ).times { @data << [] }
147
+ @data[ row_idx-1 ][ col_idx-1 ] = val
148
+ calc_dimensions
149
+ end
150
+ alias []= write
151
+
152
+ include Enumerable
153
+
154
+ def each
155
+ @data.each { |ar| yield ar }
156
+ end
157
+
158
+ private
159
+
160
+ def calc_dimensions
161
+ @rows, @cols = @data.length, @data.max_by(&:length).length
162
+ end
163
+
164
+ def ensure_shape
165
+ calc_dimensions
166
+ @data.map! { |ar| ar.length == cols ? ar : ar + Array.new( cols - ar.length, nil) }
167
+ @data
168
+ end
169
+
170
+ end
171
+
172
+ end
@@ -0,0 +1,68 @@
1
+ module RubyExcel
2
+
3
+ class Element
4
+
5
+ attr_reader :sheet, :address, :data, :column, :row
6
+ alias parent sheet
7
+
8
+ def initialize( sheet, addr )
9
+ fail ArgumentError, "Invalid range: #{ addr }" unless addr =~ /\A[A-Z]+\d+:[A-Z]+\d+\z|\A[A-Z]+\d+\z/
10
+ @sheet = sheet
11
+ @data = sheet.data
12
+ @address = addr
13
+ @column = column_id( addr )
14
+ @row = row_id( addr )
15
+ end
16
+
17
+ def delete
18
+ data.delete( self )
19
+ end
20
+
21
+ include Address
22
+
23
+ def value
24
+ if address.include? ':'
25
+ expand( address ).map { |ar| ar.map { |addr| data[ addr ] } }
26
+ else
27
+ data[ address ]
28
+ end
29
+ end
30
+
31
+ def value=( val )
32
+ if address.include? ':'
33
+ if multi_array?( val )
34
+ expand( address ).each_with_index { |row,idx| row.each_with_index { |el,i| data[ el ] = val[idx][i] } }
35
+ else
36
+ expand( address ).each { |ar| ar.each { |addr| data[ addr ] = val } }
37
+ end
38
+ else
39
+ data[ address ] = val
40
+ end
41
+ self
42
+ end
43
+
44
+ def to_s
45
+ value.is_a?( Array ) ? value.map { |ar| ar.join "\t" }.join($/) : value.to_s
46
+ end
47
+
48
+ def inspect
49
+ "#{ self.class }:0x#{ '%x' % (object_id << 1) }: #{ address }"
50
+ end
51
+
52
+ include Enumerable
53
+
54
+ def each
55
+ expand( address ).flatten.each { |addr| yield data[ addr ] }
56
+ end
57
+
58
+ def each_cell
59
+ expand( address ).flatten.each { |addr| yield Element.new( sheet, addr ) }
60
+ end
61
+
62
+ def map!
63
+ expand( address ).flatten.each { |addr| data[ addr ] = yield data[ addr ] }
64
+ end
65
+
66
+ end
67
+
68
+ end
@@ -1,348 +1,16 @@
1
- module RubyExcel
2
-
3
- module Address
4
-
5
- def address_to_col_index( address )
6
- col_index( column_id( address ) )
7
- end
8
-
9
- def address_to_indices( address )
10
- [ row_id( address ), address_to_col_index( address ) ]
11
- end
12
-
13
- def col_index( letter )
14
- return letter if letter.is_a? Fixnum
15
- letter !~ /[^A-Z]/ && [1,2,3].include?( letter.length ) or fail ArgumentError, "Invalid column reference: #{ letter }"
16
- idx, a = 1, 'A'
17
- loop { return idx if a == letter; idx+=1; a.next! }
18
- end
19
-
20
- def col_letter( index )
21
- return index if index.is_a? String
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
25
- end
26
-
27
- def column_id( address )
28
- address[/[A-Z]+/] or fail ArgumentError, "Invalid address: #{ address }"
29
- end
30
-
31
- def expand( address )
32
- 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 }" } }
35
- end
36
-
37
- def indices_to_address( row_idx, column_idx )
38
- [ row_idx, column_idx ].all? { |a| a.is_a?( Fixnum ) } or fail ArgumentError, 'Input must be Fixnum'
39
- col_letter( column_idx ) + row_idx.to_s
40
- end
41
-
42
- def multi_array?( obj )
43
- obj.all? { |el| el.is_a?( Array ) } && obj.is_a?( Array ) rescue false
44
- end
45
-
46
- def offset(address, row, col)
47
- ( col_letter( address_to_col_index( address ) + col ) ) + ( row_id( address ) + row ).to_s
48
- end
49
-
50
- def to_range_address( obj1, obj2 )
51
- if obj2
52
- obj2.is_a?( String ) ? ( obj1 + ':' + obj2 ) : "#{ obj1.address }:#{ obj2.address }"
53
- else
54
- obj1.is_a?( String ) ? obj1 : obj1.address
55
- end
56
- end
57
-
58
- def row_id( address )
59
- return nil unless address
60
- address[/\d+/].to_i
61
- end
62
-
63
- end
64
-
65
- class Data
66
- attr_reader :rows, :cols
67
- attr_accessor :sheet
68
- alias parent sheet
69
-
70
- include Address
71
-
72
- def initialize( sheet, input_data )
73
- @sheet = sheet
74
- ( input_data.kind_of?( Array ) && input_data.all? { |el| el.kind_of?( Array ) } ) or fail ArgumentError, 'Input must be Array of Arrays'
75
- @data = input_data.dup
76
- calc_dimensions
77
- end
78
-
79
- def all
80
- @data.dup
81
- end
82
-
83
- def append( multi_array )
84
- @data
85
- @data += multi_array
86
- calc_dimensions
87
- end
88
-
89
- def colref_by_header( header )
90
- sheet.header_rows > 0 or fail NoMethodError, 'No header rows present'
91
- @data[ 0..sheet.header_rows-1 ].each do |r|
92
- if ( idx = r.index( header ) )
93
- return col_letter( idx+1 )
94
- end
95
- end
96
- fail IndexError, "#{ header } is not a valid header"
97
- end
98
-
99
- def compact!
100
- compact_columns!
101
- compact_rows!
102
- end
103
-
104
- def compact_columns!
105
- ensure_shape
106
- @data = @data.transpose.delete_if { |ar| ar.all? { |el| el.to_s.empty? } || ar.empty? }.transpose
107
- calc_dimensions
108
- @data
109
- end
110
-
111
- def compact_rows!
112
- @data.delete_if { |ar| ar.all? { |el| el.to_s.empty? } || ar.empty? }
113
- calc_dimensions
114
- @data
115
- end
116
-
117
- def dup
118
- Data.new( sheet, @data.dup )
119
- end
120
-
121
- def empty?
122
- no_headers.empty?
123
- end
124
-
125
- def insert_columns( before, number=1 )
126
- a = Array.new( number, nil )
127
- before = col_index( before ) - 1
128
- @data.map! { |row| row.insert( before, *a ) }
129
- end
130
-
131
- def insert_rows( before, number=1 )
132
- @data = @data.insert( ( col_index( before ) - 1 ), *Array.new( number, [nil] ) )
133
- end
134
-
135
- def no_headers
136
- if sheet.header_cols.zero?
137
- @data[ sheet.header_rows..-1 ].dup
138
- else
139
- @data[ sheet.header_rows..-1 ].map { |row| row[ sheet.header_cols..-1 ] }
140
- end
141
- end
142
-
143
- def read( addr )
144
- row_idx, col_idx = address_to_indices( addr )
145
- @data[ row_idx-1 ][ col_idx-1 ]
146
- end
147
- alias [] read
148
-
149
- def write( addr, val )
150
- row_idx, col_idx = address_to_indices( addr )
151
- ( row_idx - rows ).times { @data << [] }
152
- @data[ row_idx-1 ][ col_idx-1 ] = val
153
- calc_dimensions
154
- end
155
- alias []= write
156
-
157
- include Enumerable
158
-
159
- def each
160
- @data.each { |ar| yield ar }
161
- end
162
-
163
- private
164
-
165
- def calc_dimensions
166
- @rows, @cols = @data.length, @data.max_by(&:length).length
167
- end
168
-
169
- def ensure_shape
170
- calc_dimensions
171
- @data.map! { |ar| ar.length == cols ? ar : ar + Array.new( cols - ar.length, nil) }
172
- @data
173
- end
174
-
175
- end
176
-
177
- class Section
178
-
179
- include Address
1
+ require_relative 'address.rb'
2
+ require_relative 'data.rb'
3
+ require_relative 'element.rb'
4
+ require_relative 'section.rb'
180
5
 
181
- attr_reader :sheet, :idx, :data
182
- alias parent sheet
183
-
184
- def initialize( sheet )
185
- @sheet = sheet
186
- @data = sheet.data
187
- end
188
-
189
- def delete
190
- data.delete( self )
191
- end
192
-
193
- def empty?
194
- all? { |val| val.to_s.empty? }
195
- end
196
-
197
- def find
198
- each.with_index { |val,i| return translate_address( i + 1 ) if yield val }; nil
199
- end
200
-
201
- def inspect
202
- "#{ self.class }:0x#{ '%x' % (object_id << 1) }: #{ idx }"
203
- end
204
-
205
- def read( id )
206
- data[ translate_address( id ) ]
207
- end
208
- alias [] read
209
-
210
- def to_s
211
- to_a.join ( self.is_a?( Row ) ? "\t" : "\n" )
212
- end
213
-
214
- def write( id, val )
215
- data[ translate_address( id ) ] = val
216
- end
217
- alias []= write
218
-
219
- include Enumerable
220
-
221
- def each
222
- return to_enum(:each) unless block_given?
223
- each_address { |addr| yield data[ addr ] }
224
- end
225
-
226
- def each_cell
227
- return to_enum(:each_cell) unless block_given?
228
- each_address { |addr| yield Element.new( sheet, addr ) }
229
- end
230
-
231
- def map!
232
- return to_enum(:map!) unless block_given?
233
- each_address { |addr| data[addr] = ( yield data[addr] ) }
234
- end
235
-
236
- private
237
-
238
- def translate_address( addr )
239
- case self
240
- when Row
241
- col_letter( addr ) + idx.to_s
242
- when Column
243
- addr = addr.to_s unless addr.is_a?( String )
244
- fail ArgumentError, "Invalid address : #{ addr }" if addr =~ /[^\d]/
245
- idx + addr
246
- end
247
- end
248
-
249
- end
250
-
251
- class Row < Section
252
-
253
- attr_reader :idx
254
-
255
- def initialize( sheet, idx )
256
- @idx = idx.to_i
257
- super( sheet )
258
- end
259
-
260
- private
261
-
262
- def each_address
263
- ( 'A'..col_letter( data.cols ) ).each { |col_id| yield "#{col_id}#{idx}" }
264
- end
6
+ module RubyExcel
265
7
 
8
+ def self.sample_data
9
+ a=[];8.times{|t|b=[];c='A';5.times{b<<"#{c}#{t+1}";c.next!};a<<b};a
266
10
  end
267
-
268
- class Column < Section
269
11
 
270
- attr_reader :idx
271
-
272
- def initialize( sheet, idx )
273
- @idx = idx
274
- super( sheet )
275
- end
276
-
277
- private
278
-
279
- def each_address
280
- 1.upto( data.rows ) { |row_id| yield idx + row_id.to_s }
281
- end
282
-
12
+ def self.sample_sheet
13
+ Workbook.new.load RubyExcel.sample_data
283
14
  end
284
-
285
- class Element
286
-
287
- attr_reader :sheet, :address, :data
288
- alias parent sheet
289
-
290
- def initialize( sheet, addr )
291
- fail ArgumentError, "Invalid range: #{ addr }" unless addr =~ /\A[A-Z]+\d+:[A-Z]+\d+\z|\A[A-Z]+\d+\z/
292
- @sheet = sheet
293
- @data = sheet.data
294
- @address = addr
295
- end
296
-
297
- def delete
298
- data.delete( self )
299
- end
300
-
301
- include Address
302
-
303
- def value
304
- if address.include? ':'
305
- expand( address ).map { |ar| ar.map { |addr| data[ addr ] } }
306
- else
307
- data[ address ]
308
- end
309
- end
310
-
311
- def value=( val )
312
- if address.include? ':'
313
- if multi_array?( val )
314
- expand( address ).each_with_index { |row,idx| row.each_with_index { |el,i| data[ el ] = val[idx][i] } }
315
- else
316
- expand( address ).each { |ar| ar.each { |addr| data[ addr ] = val } }
317
- end
318
- else
319
- data[ address ] = val
320
- end
321
- self
322
- end
323
-
324
- def to_s
325
- value.is_a?( Array ) ? value.map { |ar| ar.join "\t" }.join($/) : value.to_s
326
- end
327
-
328
- def inspect
329
- "#{ self.class }:0x#{ '%x' % (object_id << 1) }: #{ address }"
330
- end
331
-
332
- include Enumerable
333
-
334
- def each
335
- expand( address ).flatten.each { |addr| yield data[ addr ] }
336
- end
337
-
338
- def each_cell
339
- expand( address ).flatten.each { |addr| yield Element.new( sheet, addr ) }
340
- end
341
-
342
- def map!
343
- expand( address ).flatten.each { |addr| data[ addr ] = yield data[ addr ] }
344
- end
345
-
346
- end
347
-
15
+
348
16
  end
@@ -0,0 +1,144 @@
1
+ module RubyExcel
2
+
3
+ class Section
4
+
5
+ include Address
6
+
7
+ attr_reader :sheet, :idx, :data
8
+ alias parent sheet
9
+
10
+ def initialize( sheet )
11
+ @sheet = sheet
12
+ @data = sheet.data
13
+ end
14
+
15
+ def <<( value )
16
+ if self.is_a? Row
17
+ lastone = ( col_index( idx ) == 1 ? data.cols + 1 : data.cols )
18
+ else
19
+ lastone = ( col_index( idx ) == 1 ? data.rows + 1 : data.rows )
20
+ end
21
+ data[ translate_address( lastone ) ] = value
22
+ end
23
+
24
+ def delete
25
+ data.delete( self )
26
+ end
27
+
28
+ def empty?
29
+ all? { |val| val.to_s.empty? }
30
+ end
31
+
32
+ def find
33
+ each_cell { |ce| return ce.address if yield ce.value }; nil
34
+ end
35
+
36
+ def inspect
37
+ "#{ self.class }:0x#{ '%x' % (object_id << 1) }: #{ idx }"
38
+ end
39
+
40
+ def read( id )
41
+ data[ translate_address( id ) ]
42
+ end
43
+ alias [] read
44
+
45
+ def summarise
46
+ h = Hash.new(0)
47
+ each_wh { |v| h[v]+=1 }; h
48
+ end
49
+ alias summarize summarise
50
+
51
+ def to_s
52
+ to_a.join ( self.is_a?( Row ) ? "\t" : "\n" )
53
+ end
54
+
55
+ def write( id, val )
56
+ data[ translate_address( id ) ] = val
57
+ end
58
+ alias []= write
59
+
60
+ include Enumerable
61
+
62
+ def each
63
+ return to_enum(:each) unless block_given?
64
+ each_address { |addr| yield data[ addr ] }
65
+ end
66
+
67
+ def each_without_headers
68
+ return to_enum(:each_without_headers) unless block_given?
69
+ each_address_without_headers { |addr| yield data[ addr ] }
70
+ end
71
+ alias each_wh each_without_headers
72
+
73
+ def each_cell
74
+ return to_enum(:each_cell) unless block_given?
75
+ each_address { |addr| yield Element.new( sheet, addr ) }
76
+ end
77
+
78
+ def map!
79
+ return to_enum(:map!) unless block_given?
80
+ each_address { |addr| data[addr] = ( yield data[addr] ) }
81
+ end
82
+
83
+ private
84
+
85
+ def translate_address( addr )
86
+ case self
87
+ when Row
88
+ col_letter( addr ) + idx.to_s
89
+ when Column
90
+ addr = addr.to_s unless addr.is_a?( String )
91
+ fail ArgumentError, "Invalid address : #{ addr }" if addr =~ /[^\d]/
92
+ idx + addr
93
+ end
94
+ end
95
+
96
+ end
97
+
98
+ class Row < Section
99
+
100
+ attr_reader :idx
101
+
102
+ def initialize( sheet, idx )
103
+ @idx = idx.to_i
104
+ super( sheet )
105
+ end
106
+
107
+ def getref( header )
108
+ column_id( sheet.row(1).find &/#{header}/ )
109
+ end
110
+
111
+ private
112
+
113
+ def each_address
114
+ ( 'A'..col_letter( data.cols ) ).each { |col_id| yield "#{col_id}#{idx}" }
115
+ end
116
+
117
+ def each_address_without_headers
118
+ ( col_letter( sheet.header_cols+1 )..col_letter( data.cols ) ).each { |col_id| yield "#{col_id}#{idx}" }
119
+ end
120
+
121
+ end
122
+
123
+ class Column < Section
124
+
125
+ attr_reader :idx
126
+
127
+ def initialize( sheet, idx )
128
+ @idx = idx
129
+ super( sheet )
130
+ end
131
+
132
+ private
133
+
134
+ def each_address
135
+ ( 1..data.rows ).each { |row_id| yield idx + row_id.to_s }
136
+ end
137
+
138
+ def each_address_without_headers
139
+ ( sheet.header_rows+1 ).upto( data.rows ) { |row_id| yield idx + row_id.to_s }
140
+ end
141
+
142
+ end
143
+
144
+ end
data/lib/rubyexcel.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  require_relative 'rubyexcel/rubyexcel_components.rb'
2
- require_relative 'rubyexcel/rubyexcel_advanced.rb'
3
2
  require_relative 'rubyexcel/excel_tools.rb'
4
3
 
5
4
  class Regexp
@@ -18,8 +17,8 @@ module RubyExcel
18
17
 
19
18
  def <<( other )
20
19
  case other
21
- when RubyExcel
22
- other.each { |s| @sheets << s }
20
+ when Workbook
21
+ other.inject( @sheets, :<< )
23
22
  when Sheet
24
23
  @sheets << other
25
24
  end
@@ -124,6 +123,33 @@ module RubyExcel
124
123
  range( addr ).value = val
125
124
  end
126
125
 
126
+
127
+ def +( other )
128
+ dup << other
129
+ end
130
+
131
+ def -( other )
132
+ 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 }"
139
+ end
140
+ end
141
+
142
+ def <<( other )
143
+ 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 }"
150
+ end
151
+ end
152
+
127
153
  def cell( row, col )
128
154
  Element.new( self, indices_to_address( row, col ) )
129
155
  end
@@ -133,24 +159,21 @@ module RubyExcel
133
159
  Column.new( self, col_letter( index ) )
134
160
  end
135
161
 
162
+ def column_by_header( header )
163
+ Column.new( self, data.colref_by_header( header ) )
164
+ end
165
+ alias ch column_by_header
166
+
136
167
  def columns( start_column = 'A', end_column = data.cols )
137
168
  start_column, end_column = col_letter( start_column ), col_letter( end_column )
138
169
  return to_enum(:columns, start_column, end_column) unless block_given?
139
170
  ( start_column..end_column ).each { |idx| yield column( idx ) }
140
171
  end
141
172
 
142
- def get_columns( *headers )
143
- s = dup
144
- s.data.get_columns!( *headers )
145
- s
146
- end
147
- alias gc get_columns
148
-
149
- def get_columns!( *headers )
150
- data.get_columns!( *headers )
173
+ def compact!
174
+ data.compact!
151
175
  self
152
176
  end
153
- alias gc! get_columns!
154
177
 
155
178
  def delete
156
179
  workbook.delete self
@@ -167,6 +190,32 @@ module RubyExcel
167
190
  s
168
191
  end
169
192
 
193
+ def empty?
194
+ data.empty?
195
+ end
196
+
197
+ def filter( ref, &block )
198
+ dup.filter!( ref, &block )
199
+ end
200
+
201
+ def filter!( ref, &block )
202
+ data.filter!( ref, &block )
203
+ self
204
+ end
205
+
206
+ def get_columns( *headers )
207
+ s = dup
208
+ s.data.get_columns!( *headers )
209
+ s
210
+ end
211
+ alias gc get_columns
212
+
213
+ def get_columns!( *headers )
214
+ data.get_columns!( *headers )
215
+ self
216
+ end
217
+ alias gc! get_columns!
218
+
170
219
  def insert_columns( *args )
171
220
  data.insert_columns( *args )
172
221
  self
@@ -213,6 +262,16 @@ module RubyExcel
213
262
  ( start_row..end_row ).each { |idx| yield row( idx ) }
214
263
  end
215
264
 
265
+ 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
273
+ end
274
+
216
275
  def to_a
217
276
  data.all
218
277
  end
@@ -225,6 +284,12 @@ module RubyExcel
225
284
  data.nil? ? '' : data.map { |ar| ar.join "\t" }.join( $/ )
226
285
  end
227
286
 
287
+ def uniq!( header )
288
+ data.uniq!( header )
289
+ self
290
+ end
291
+ alias unique! uniq!
292
+
228
293
  end
229
294
 
230
295
  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.1
4
+ version: 0.0.2
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-03-23 00:00:00.000000000 Z
12
+ date: 2013-04-02 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A tabular data structure, mixing Ruby with some of Excel's API.
15
15
  email:
@@ -20,7 +20,10 @@ files:
20
20
  - lib/rubyexcel.rb
21
21
  - lib/rubyexcel/excel_tools.rb
22
22
  - lib/rubyexcel/rubyexcel_components.rb
23
- - lib/rubyexcel/rubyexcel_advanced.rb
23
+ - lib/rubyexcel/data.rb
24
+ - lib/rubyexcel/element.rb
25
+ - lib/rubyexcel/section.rb
26
+ - lib/rubyexcel/address.rb
24
27
  homepage:
25
28
  licenses: []
26
29
  post_install_message:
@@ -1,164 +0,0 @@
1
- module RubyExcel
2
-
3
- def self.sample_data
4
- a=[];8.times{|t|b=[];c='A';5.times{b<<"#{c}#{t+1}";c.next!};a<<b};a
5
- end
6
-
7
- def self.sample_sheet
8
- Workbook.new.load RubyExcel.sample_data
9
- end
10
-
11
- class Sheet
12
-
13
- def +( other )
14
- dup << other
15
- end
16
-
17
- def -( other )
18
- case other
19
- when Array
20
- Workbook.new.load( data.all - other )
21
- when Sheet
22
- Workbook.new.load( data.all - other.data.no_headers )
23
- else
24
- fail ArgumentError, "Unsupported class: #{ other.class }"
25
- end
26
- end
27
-
28
- def <<( other )
29
- case other
30
- when Array
31
- load( data.all + other, header_rows, header_cols )
32
- when Sheet
33
- load( data.all + other.data.no_headers, header_rows, header_cols )
34
- else
35
- fail ArgumentError, "Unsupported class: #{ other.class }"
36
- end
37
- end
38
-
39
- def compact!
40
- data.compact!
41
- self
42
- end
43
-
44
- def empty?
45
- data.empty?
46
- end
47
-
48
- def column_by_header( header )
49
- Column.new( self, data.colref_by_header( header ) )
50
- end
51
- alias ch column_by_header
52
-
53
- def filter!( ref, &block )
54
- data.filter!( ref, &block )
55
- self
56
- end
57
-
58
- def sumif( find_header, sum_header )
59
- col1 = column_by_header( find_header )
60
- col2 = column_by_header( sum_header )
61
- total = 0
62
- col1.each.with_index do |val,idx|
63
- total += ( ( n = col2[ idx + 1 ] ).is_a?( String ) ? n.to_i : n ) if yield( val ) && idx >= header_rows
64
- end
65
- total
66
- end
67
-
68
- def uniq!( header )
69
- data.uniq!( header )
70
- self
71
- end
72
- alias unique! uniq!
73
-
74
- end
75
-
76
- class Data
77
-
78
- def delete( object )
79
- case object
80
- when Row
81
- @data.slice!( object.idx - 1 )
82
- when Column
83
- idx = col_index( object.idx ) - 1
84
- @data.each { |r| r.slice! idx }
85
- when Element
86
- addresses = expand( object.address )
87
- indices = [ address_to_indices( addresses.first.first ), address_to_indices( addresses.last.last ) ].flatten.map { |n| n-1 }
88
- @data[ indices[0]..indices[2] ].each { |r| r.slice!( indices[1], indices[3] - indices[1] + 1 ) }
89
- @data.delete_if.with_index { |r,i| r.empty? && i.between?( indices[0], indices[2] ) }
90
- else
91
- fail NoMethodError, "#{ object.class } is not supported"
92
- end
93
- self
94
- end
95
-
96
- def delete_column( ref )
97
- delete( Column.new( sheet, ref ) )
98
- end
99
-
100
- def delete_row( ref )
101
- delete( Row.new( sheet, ref ) )
102
- end
103
-
104
- def delete_range( ref )
105
- delete( Element.new( sheet, ref ) )
106
- end
107
-
108
- def filter!( header )
109
- hrows = sheet.header_rows
110
- idx = col_index( hrows > 0 ? colref_by_header( header ) : header )
111
- @data = @data.select.with_index { |row, i| hrows > i || yield( row[ idx -1 ] ) }
112
- calc_dimensions
113
- self
114
- end
115
-
116
- def get_columns!( *headers )
117
- hrow = sheet.header_rows - 1
118
- ensure_shape
119
- @data = @data.transpose.select{ |col| headers.include?( col[hrow] ) }
120
- ensure_shape
121
- @data = @data.sort_by{ |col| headers.index( col[hrow] ) || col[hrow] }.transpose
122
- calc_dimensions
123
- self
124
- end
125
-
126
- def uniq!( header )
127
- column = col_index( colref_by_header( header ) )
128
- @data = @data.uniq { |row| row[ column - 1 ] }
129
- self
130
- end
131
- alias unique! uniq!
132
-
133
- end
134
-
135
- class Section
136
-
137
- def <<( value )
138
- if self.is_a? Row
139
- lastone = ( col_index( idx ) == 1 ? data.cols + 1 : data.cols )
140
- else
141
- lastone = ( col_index( idx ) == 1 ? data.rows + 1 : data.rows )
142
- end
143
- data[ translate_address( lastone ) ] = value
144
- end
145
-
146
- end
147
-
148
- class Row < Section
149
-
150
- def getref( header )
151
- column_id( sheet.row(1).find &/#{header}/ )
152
- end
153
-
154
- end
155
-
156
- class Column < Section
157
-
158
- end
159
-
160
- class Element
161
-
162
- end
163
-
164
- end