rubyexcel 0.0.1

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,54 @@
1
+
2
+ module Excel_Tools
3
+
4
+ require 'win32ole'
5
+
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
33
+ end
34
+
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 ) )
44
+ end
45
+ wb.sheets(1).select
46
+ wb
47
+ end
48
+
49
+ def save_excel( filename = 'Output.xlsx' )
50
+ filename = Dir.pwd.gsub('/','\\') + '\\' + filename unless filename.include?('\\')
51
+ to_excel.saveas filename
52
+ end
53
+
54
+ end
@@ -0,0 +1,164 @@
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
@@ -0,0 +1,348 @@
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
180
+
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
265
+
266
+ end
267
+
268
+ class Column < Section
269
+
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
+
283
+ 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
+
348
+ end
data/lib/rubyexcel.rb ADDED
@@ -0,0 +1,230 @@
1
+ require_relative 'rubyexcel/rubyexcel_components.rb'
2
+ require_relative 'rubyexcel/rubyexcel_advanced.rb'
3
+ require_relative 'rubyexcel/excel_tools.rb'
4
+
5
+ class Regexp
6
+ def to_proc
7
+ proc { |s| self =~ s.to_s }
8
+ end
9
+ end
10
+
11
+ module RubyExcel
12
+
13
+ class Workbook
14
+
15
+ def initialize
16
+ @sheets = []
17
+ end
18
+
19
+ def <<( other )
20
+ case other
21
+ when RubyExcel
22
+ other.each { |s| @sheets << s }
23
+ when Sheet
24
+ @sheets << other
25
+ end
26
+ end
27
+
28
+ def add( ref=nil )
29
+ case ref
30
+ when nil
31
+ s = Sheet.new( 'Sheet' + ( @sheets.count + 1 ).to_s, self )
32
+ when Sheet
33
+ s = ref
34
+ s.workbook = self
35
+ when String
36
+ s = Sheet.new( ref, self )
37
+ else
38
+ fail TypeError, "Unsupported Type: #{ ref.class }"
39
+ end
40
+ @sheets << s
41
+ s
42
+ end
43
+ alias add_sheet add
44
+
45
+ def clear_all
46
+ @sheets = []
47
+ self
48
+ end
49
+
50
+ def delete( ref )
51
+ case ref
52
+ when Fixnum
53
+ @sheets.delete_at( ref - 1 )
54
+ when String
55
+ @sheets.reject! { |s| s.name == ref }
56
+ when Regexp
57
+ @sheets.reject! { |s| s.name =~ ref }
58
+ when Sheet
59
+ @sheets.reject! { |s| s == ref }
60
+ else
61
+ fail ArgumentError, "Unrecognised Argument Type: #{ ref.class }"
62
+ end
63
+ end
64
+
65
+ def dup
66
+ wb = Workbook.new
67
+ self.each {|s| wb.add s.dup }
68
+ wb
69
+ end
70
+
71
+ def empty?
72
+ @sheets.empty?
73
+ end
74
+
75
+ def load( *args )
76
+ add.load( *args )
77
+ end
78
+
79
+ def sheets( ref=nil )
80
+ return to_enum (:each) if ref.nil?
81
+ ref.is_a?( Fixnum ) ? @sheets[ ref - 1 ] : @sheets.find { |s| s.name =~ /^#{ ref }$/i }
82
+ end
83
+
84
+ def sort_by!( &block )
85
+ if block_given?
86
+ @sheets = @sheets.sort_by(&block)
87
+ else
88
+ @sheets = @sheets.sort_by(&:name)
89
+ end
90
+ end
91
+ alias sort! sort_by!
92
+
93
+ include Enumerable
94
+
95
+ def each
96
+ return to_enum(:each) unless block_given?
97
+ @sheets.each { |s| yield s }
98
+ end
99
+
100
+ include Excel_Tools
101
+
102
+ end
103
+
104
+ class Sheet
105
+
106
+ attr_reader :data
107
+ attr_accessor :name, :header_rows, :header_cols, :workbook
108
+ alias parent workbook
109
+
110
+ include Address
111
+
112
+ def initialize( name, workbook )
113
+ @workbook = workbook
114
+ @name = name
115
+ @header_rows, @header_cols = nil, nil
116
+ @data = Data.new( self, [[]] )
117
+ end
118
+
119
+ def[]( addr )
120
+ range( addr ).value
121
+ end
122
+
123
+ def []=( addr, val )
124
+ range( addr ).value = val
125
+ end
126
+
127
+ def cell( row, col )
128
+ Element.new( self, indices_to_address( row, col ) )
129
+ end
130
+ alias cells cell
131
+
132
+ def column( index )
133
+ Column.new( self, col_letter( index ) )
134
+ end
135
+
136
+ def columns( start_column = 'A', end_column = data.cols )
137
+ start_column, end_column = col_letter( start_column ), col_letter( end_column )
138
+ return to_enum(:columns, start_column, end_column) unless block_given?
139
+ ( start_column..end_column ).each { |idx| yield column( idx ) }
140
+ end
141
+
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 )
151
+ self
152
+ end
153
+ alias gc! get_columns!
154
+
155
+ def delete
156
+ workbook.delete self
157
+ end
158
+
159
+ def dup
160
+ s = Sheet.new( name, workbook )
161
+ d = data
162
+ unless d.nil?
163
+ d = d.dup
164
+ s.load( d.all, header_rows, header_cols )
165
+ d.sheet = s
166
+ end
167
+ s
168
+ end
169
+
170
+ def insert_columns( *args )
171
+ data.insert_columns( *args )
172
+ self
173
+ end
174
+
175
+ def insert_rows( *args )
176
+ data.insert_rows( *args )
177
+ self
178
+ end
179
+
180
+ def inspect
181
+ "#{ self.class }:0x#{ '%x' % (object_id << 1) }: #{ name }"
182
+ end
183
+
184
+ def load( input_data, header_rows=1, header_cols=0 )
185
+ @header_rows, @header_cols = header_rows, header_cols
186
+ @data = Data.new( self, input_data )
187
+ self
188
+ end
189
+
190
+ def match( header, &block )
191
+ row_id( column_by_header( header ).find( &block ) )
192
+ end
193
+
194
+ def maxrow
195
+ data.rows
196
+ end
197
+
198
+ def maxcol
199
+ data.cols
200
+ end
201
+ alias maxcolumn maxcol
202
+
203
+ def range( first_cell, last_cell=nil )
204
+ Element.new( self, to_range_address( first_cell, last_cell ) )
205
+ end
206
+
207
+ def row( index )
208
+ Row.new( self, index )
209
+ end
210
+
211
+ def rows( start_row = 1, end_row = data.rows )
212
+ return to_enum(:rows, start_row, end_row) unless block_given?
213
+ ( start_row..end_row ).each { |idx| yield row( idx ) }
214
+ end
215
+
216
+ def to_a
217
+ data.all
218
+ end
219
+
220
+ def to_excel
221
+ workbook.dup.clear_all.add( self.dup ).workbook.to_excel
222
+ end
223
+
224
+ def to_s
225
+ data.nil? ? '' : data.map { |ar| ar.join "\t" }.join( $/ )
226
+ end
227
+
228
+ end
229
+
230
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rubyexcel
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Joel Pearson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-03-23 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A tabular data structure, mixing Ruby with some of Excel's API.
15
+ email:
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/rubyexcel.rb
21
+ - lib/rubyexcel/excel_tools.rb
22
+ - lib/rubyexcel/rubyexcel_components.rb
23
+ - lib/rubyexcel/rubyexcel_advanced.rb
24
+ homepage:
25
+ licenses: []
26
+ post_install_message:
27
+ rdoc_options: []
28
+ require_paths:
29
+ - lib
30
+ required_ruby_version: !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ! '>='
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubyforge_project:
44
+ rubygems_version: 1.8.24
45
+ signing_key:
46
+ specification_version: 3
47
+ summary: Spreadsheets in Ruby
48
+ test_files: []
49
+ has_rdoc: