rubyexcel 0.0.9 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/README.md +9 -3
- data/lib/rubyexcel/data.rb +13 -19
- data/lib/rubyexcel/element.rb +22 -2
- data/lib/rubyexcel/section.rb +65 -57
- data/lib/rubyexcel.rb +2 -3
- data/lib/test/rubyexcel/tc_address.rb +81 -0
- data/lib/test/rubyexcel/tc_data.rb +153 -0
- data/lib/test/rubyexcel/tc_element.rb +42 -0
- data/lib/test/rubyexcel/tc_section.rb +59 -0
- data/lib/test/tc_rubyexcel.rb +272 -0
- data/lib/test/test_all.rb +5 -0
- metadata +8 -2
data/lib/README.md
CHANGED
@@ -3,13 +3,19 @@ RubyExcel
|
|
3
3
|
|
4
4
|
Designed for Ruby on Windows with MS Excel
|
5
5
|
|
6
|
-
Please feel free to log any bugs you find [here](https://github.com/VirtuosoJoel/RubyExcel/issues "Bug Tracker").
|
7
|
-
|
8
6
|
Introduction
|
9
7
|
------------
|
10
8
|
|
11
9
|
A Data-analysis tool for Ruby, with an Excel-style API.
|
12
10
|
|
11
|
+
You can find the gem [here](https://rubygems.org/gems/rubyexcel "Rubygems").
|
12
|
+
|
13
|
+
Main Documentation is [here](rubydoc.info/gems/rubyexcel "Rubydoc")
|
14
|
+
|
15
|
+
For any requests, comments, etc. I keep an eye on [This forum](http://www.ruby-forum.com/forum/ruby "Ruby Mailing List"). If you have "RubyExcel" in the title I should see it.
|
16
|
+
|
17
|
+
Please feel free to log any bugs you find [here](https://github.com/VirtuosoJoel/RubyExcel/issues "Bug Tracker").
|
18
|
+
|
13
19
|
Details
|
14
20
|
-----
|
15
21
|
|
@@ -36,7 +42,7 @@ As this works directly on the data, processing is faster than using Excel itself
|
|
36
42
|
This was written out of the frustration of editing tabular data using Ruby's multidimensional arrays,
|
37
43
|
without affecting headers and while maintaining code readability.
|
38
44
|
Its API is designed to simplify moving code across from VBA into Ruby format when processing spreadsheet data.
|
39
|
-
The combination of Ruby, WIN32OLE Excel, and
|
45
|
+
The combination of Ruby, WIN32OLE Excel, and analysing table data is probably quite rare; but I thought I'd share what I came up with.
|
40
46
|
|
41
47
|
Examples
|
42
48
|
========
|
data/lib/rubyexcel/data.rb
CHANGED
@@ -5,6 +5,8 @@ require_relative 'address.rb'
|
|
5
5
|
#
|
6
6
|
# The class which holds a Sheet's data
|
7
7
|
#
|
8
|
+
# @note This class is exposed to the API purely for debugging.
|
9
|
+
#
|
8
10
|
|
9
11
|
class Data
|
10
12
|
include Address
|
@@ -71,24 +73,15 @@ require_relative 'address.rb'
|
|
71
73
|
#
|
72
74
|
# Returns a copy of the data
|
73
75
|
#
|
76
|
+
# @return [Array<Array>]
|
77
|
+
#
|
74
78
|
|
75
79
|
def all
|
76
80
|
@data.dup
|
77
81
|
end
|
78
|
-
|
79
|
-
#
|
80
|
-
# Appends a multidimensional Array to the end of the data
|
81
|
-
#
|
82
|
-
# @param [Array<Array>] multi_array the multidimensional Array to add to the data
|
83
|
-
#
|
84
|
-
|
85
|
-
def append( multi_array )
|
86
|
-
@data << multi_array
|
87
|
-
calc_dimensions
|
88
|
-
end
|
89
|
-
|
82
|
+
|
90
83
|
#
|
91
|
-
# Finds a Column reference
|
84
|
+
# Finds a Column reference by a header
|
92
85
|
#
|
93
86
|
# @param [String] header the header to search for
|
94
87
|
# @return [String] the Column reference
|
@@ -162,7 +155,6 @@ require_relative 'address.rb'
|
|
162
155
|
|
163
156
|
def delete_column( ref )
|
164
157
|
delete( Column.new( sheet, ref ) )
|
165
|
-
calc_dimensions
|
166
158
|
end
|
167
159
|
|
168
160
|
#
|
@@ -171,7 +163,6 @@ require_relative 'address.rb'
|
|
171
163
|
|
172
164
|
def delete_row( ref )
|
173
165
|
delete( Row.new( sheet, ref ) )
|
174
|
-
calc_dimensions
|
175
166
|
end
|
176
167
|
|
177
168
|
#
|
@@ -180,7 +171,6 @@ require_relative 'address.rb'
|
|
180
171
|
|
181
172
|
def delete_range( ref )
|
182
173
|
delete( Element.new( sheet, ref ) )
|
183
|
-
calc_dimensions
|
184
174
|
end
|
185
175
|
|
186
176
|
#
|
@@ -194,7 +184,7 @@ require_relative 'address.rb'
|
|
194
184
|
end
|
195
185
|
|
196
186
|
#
|
197
|
-
# Check whether the data is empty
|
187
|
+
# Check whether the data (without headers) is empty
|
198
188
|
#
|
199
189
|
# @return [Boolean]
|
200
190
|
#
|
@@ -208,6 +198,7 @@ require_relative 'address.rb'
|
|
208
198
|
#
|
209
199
|
|
210
200
|
def each
|
201
|
+
return to_enum( :each ) unless block_given?
|
211
202
|
@data.each { |ar| yield ar }
|
212
203
|
end
|
213
204
|
|
@@ -230,6 +221,7 @@ require_relative 'address.rb'
|
|
230
221
|
# Select and re-order Columns by a list of headers
|
231
222
|
#
|
232
223
|
# @param [Array<String>] headers the ordered list of headers to keep
|
224
|
+
# @note This method can accept either a list of arguments or an Array
|
233
225
|
# @note Invalid headers will be skipped
|
234
226
|
#
|
235
227
|
|
@@ -258,7 +250,8 @@ require_relative 'address.rb'
|
|
258
250
|
#
|
259
251
|
|
260
252
|
def index_by_header( header )
|
261
|
-
|
253
|
+
sheet.header_rows > 0 or fail NoMethodError, 'No header rows present'
|
254
|
+
col_index( colref_by_header( header ) )
|
262
255
|
end
|
263
256
|
|
264
257
|
#
|
@@ -365,7 +358,7 @@ require_relative 'address.rb'
|
|
365
358
|
#
|
366
359
|
|
367
360
|
def sort_by!( &block )
|
368
|
-
@data = skip_headers { |d| d.sort_by( &block ) }
|
361
|
+
@data = skip_headers { |d| d.sort_by( &block ) }; self
|
369
362
|
end
|
370
363
|
|
371
364
|
#
|
@@ -391,6 +384,7 @@ require_relative 'address.rb'
|
|
391
384
|
( row_idx - rows ).times { @data << [] }
|
392
385
|
@data[ row_idx-1 ][ col_idx-1 ] = val
|
393
386
|
calc_dimensions
|
387
|
+
val
|
394
388
|
end
|
395
389
|
alias []= write
|
396
390
|
|
data/lib/rubyexcel/element.rb
CHANGED
@@ -65,15 +65,35 @@ module RubyExcel
|
|
65
65
|
#
|
66
66
|
|
67
67
|
def value=( val )
|
68
|
+
|
69
|
+
#Range
|
68
70
|
if address.include? ':'
|
71
|
+
|
72
|
+
addresses = expand( address )
|
73
|
+
|
74
|
+
# 2D Array of Values
|
69
75
|
if multi_array?( val )
|
70
|
-
|
76
|
+
|
77
|
+
#Check the dimensions
|
78
|
+
val_rows, val_cols, range_rows, range_cols = val.length, val.max_by(&:length).length, addresses.length, addresses.max_by(&:length).length
|
79
|
+
val_rows == range_rows && val_cols == range_cols or fail ArgumentError, "Dimension mismatch! Value rows, columns: #{ val_rows }, #{ val_cols }. Range rows, columns: #{ range_rows }, #{ range_cols }"
|
80
|
+
|
81
|
+
#Write the values in order
|
82
|
+
addresses.each_with_index { |row,idx| row.each_with_index { |el,i| data[ el ] = val[idx][i] } }
|
83
|
+
|
84
|
+
# Single Value
|
71
85
|
else
|
72
|
-
|
86
|
+
|
87
|
+
#Write the same value to every cell in the Range
|
88
|
+
addresses.each { |ar| ar.each { |addr| data[ addr ] = val } }
|
89
|
+
|
73
90
|
end
|
91
|
+
|
92
|
+
#Cell
|
74
93
|
else
|
75
94
|
data[ address ] = val
|
76
95
|
end
|
96
|
+
|
77
97
|
self
|
78
98
|
end
|
79
99
|
|
data/lib/rubyexcel/section.rb
CHANGED
@@ -28,16 +28,16 @@ module RubyExcel
|
|
28
28
|
|
29
29
|
#
|
30
30
|
# Append a value to the Section.
|
31
|
-
# This only adds an extra cell if it is the first Row / Column.
|
32
|
-
# This prevents a loop through Rows or Columns from extending diagonally away from the main data.
|
33
31
|
#
|
34
32
|
# @param [Object] value the object to append
|
33
|
+
# @note This only adds an extra cell if it is the first Row / Column.
|
34
|
+
# This prevents a loop through Rows or Columns from extending diagonally away from the main data.
|
35
35
|
#
|
36
36
|
|
37
37
|
def <<( value )
|
38
38
|
case self
|
39
|
-
when Row ; lastone = (
|
40
|
-
else ; lastone = (
|
39
|
+
when Row ; lastone = ( idx == 1 ? data.cols + 1 : data.cols )
|
40
|
+
else ; lastone = ( idx == 'A' ? data.rows + 1 : data.rows )
|
41
41
|
end
|
42
42
|
data[ translate_address( lastone ) ] = value
|
43
43
|
end
|
@@ -58,6 +58,44 @@ module RubyExcel
|
|
58
58
|
data.delete( self ); self
|
59
59
|
end
|
60
60
|
|
61
|
+
#
|
62
|
+
# Yields each value
|
63
|
+
#
|
64
|
+
|
65
|
+
def each
|
66
|
+
return to_enum(:each) unless block_given?
|
67
|
+
each_address { |addr| yield data[ addr ] }
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Yields each value, skipping headers
|
72
|
+
#
|
73
|
+
|
74
|
+
def each_without_headers
|
75
|
+
return to_enum( :each_without_headers ) unless block_given?
|
76
|
+
each_address_without_headers { |addr| yield data[ addr ] }
|
77
|
+
end
|
78
|
+
alias each_wh each_without_headers
|
79
|
+
|
80
|
+
#
|
81
|
+
# Yields each cell
|
82
|
+
#
|
83
|
+
|
84
|
+
def each_cell
|
85
|
+
return to_enum( :each_cell ) unless block_given?
|
86
|
+
each_address { |addr| yield Element.new( sheet, addr ) }
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# Yields each cell, skipping headers
|
91
|
+
#
|
92
|
+
|
93
|
+
def each_cell_without_headers
|
94
|
+
return to_enum( :each_cell_without_headers ) unless block_given?
|
95
|
+
each_address_without_headers { |addr| yield Element.new( sheet, addr ) }
|
96
|
+
end
|
97
|
+
alias each_cell_wh each_cell_without_headers
|
98
|
+
|
61
99
|
#
|
62
100
|
# Check whether the data in self is empty
|
63
101
|
#
|
@@ -86,6 +124,15 @@ module RubyExcel
|
|
86
124
|
"#{ self.class }:0x#{ '%x' % (object_id << 1) }: #{ idx }"
|
87
125
|
end
|
88
126
|
|
127
|
+
#
|
128
|
+
# Replaces each value with the result of the block
|
129
|
+
#
|
130
|
+
|
131
|
+
def map!
|
132
|
+
return to_enum( :map! ) unless block_given?
|
133
|
+
each_address { |addr| data[addr] = ( yield data[addr] ) }
|
134
|
+
end
|
135
|
+
|
89
136
|
#
|
90
137
|
# Read a value by address
|
91
138
|
#
|
@@ -128,53 +175,6 @@ module RubyExcel
|
|
128
175
|
end
|
129
176
|
alias []= write
|
130
177
|
|
131
|
-
#
|
132
|
-
# Yields each value
|
133
|
-
#
|
134
|
-
|
135
|
-
def each
|
136
|
-
return to_enum(:each) unless block_given?
|
137
|
-
each_address { |addr| yield data[ addr ] }
|
138
|
-
end
|
139
|
-
|
140
|
-
#
|
141
|
-
# Yields each value, skipping headers
|
142
|
-
#
|
143
|
-
|
144
|
-
def each_without_headers
|
145
|
-
return to_enum( :each_without_headers ) unless block_given?
|
146
|
-
each_address_without_headers { |addr| yield data[ addr ] }
|
147
|
-
end
|
148
|
-
alias each_wh each_without_headers
|
149
|
-
|
150
|
-
#
|
151
|
-
# Yields each cell
|
152
|
-
#
|
153
|
-
|
154
|
-
def each_cell
|
155
|
-
return to_enum( :each_cell ) unless block_given?
|
156
|
-
each_address { |addr| yield Element.new( sheet, addr ) }
|
157
|
-
end
|
158
|
-
|
159
|
-
#
|
160
|
-
# Yields each cell, skipping headers
|
161
|
-
#
|
162
|
-
|
163
|
-
def each_cell_without_headers
|
164
|
-
return to_enum( :each_cell_without_headers ) unless block_given?
|
165
|
-
each_address_without_headers { |addr| yield Element.new( sheet, addr ) }
|
166
|
-
end
|
167
|
-
alias each_cell_wh each_cell_without_headers
|
168
|
-
|
169
|
-
#
|
170
|
-
# Replaces each value with the result of the block
|
171
|
-
#
|
172
|
-
|
173
|
-
def map!
|
174
|
-
return to_enum( :map! ) unless block_given?
|
175
|
-
each_address { |addr| data[addr] = ( yield data[addr] ) }
|
176
|
-
end
|
177
|
-
|
178
178
|
private
|
179
179
|
|
180
180
|
def translate_address( addr )
|
@@ -192,11 +192,12 @@ module RubyExcel
|
|
192
192
|
|
193
193
|
#
|
194
194
|
# A Row in the Sheet
|
195
|
+
# @attr_reader [Fixnum] idx the Row index
|
196
|
+
# @attr_reader [Fixnum] length the Row length
|
195
197
|
#
|
196
198
|
|
197
199
|
class Row < Section
|
198
200
|
|
199
|
-
# The Row index
|
200
201
|
attr_reader :idx
|
201
202
|
|
202
203
|
#
|
@@ -238,6 +239,10 @@ module RubyExcel
|
|
238
239
|
fail ArgumentError, 'Invalid header: ' + header.to_s
|
239
240
|
end
|
240
241
|
|
242
|
+
def length
|
243
|
+
data.cols
|
244
|
+
end
|
245
|
+
|
241
246
|
#
|
242
247
|
# Find a value in this Row by its header
|
243
248
|
#
|
@@ -255,20 +260,19 @@ module RubyExcel
|
|
255
260
|
def each_address
|
256
261
|
( 'A'..col_letter( data.cols ) ).each { |col_id| yield "#{col_id}#{idx}" }
|
257
262
|
end
|
258
|
-
|
259
|
-
def each_address_without_headers
|
260
|
-
( 'A'..col_letter( data.cols ) ).each { |col_id| yield "#{col_id}#{idx}" }
|
261
|
-
end
|
263
|
+
alias each_address_without_headers each_address
|
262
264
|
|
263
265
|
end
|
264
266
|
|
265
267
|
#
|
266
268
|
# A Column in the Sheet
|
267
269
|
#
|
270
|
+
# @attr_reader [String] idx the Column index
|
271
|
+
# @attr_reader [Fixnum] length the Column length
|
272
|
+
#
|
268
273
|
|
269
274
|
class Column < Section
|
270
275
|
|
271
|
-
# The Row index
|
272
276
|
attr_reader :idx
|
273
277
|
|
274
278
|
#
|
@@ -282,6 +286,10 @@ module RubyExcel
|
|
282
286
|
@idx = idx
|
283
287
|
super( sheet )
|
284
288
|
end
|
289
|
+
|
290
|
+
def length
|
291
|
+
data.rows
|
292
|
+
end
|
285
293
|
|
286
294
|
private
|
287
295
|
|
data/lib/rubyexcel.rb
CHANGED
@@ -293,7 +293,7 @@ module RubyExcel
|
|
293
293
|
def <<( other )
|
294
294
|
case other
|
295
295
|
when Array ; load( data.all + other, header_rows )
|
296
|
-
when Hash ; load( data.all + _convert_hash( other ) )
|
296
|
+
when Hash ; load( data.all + _convert_hash( other ), header_rows )
|
297
297
|
when Sheet ; load( data.all + other.data.no_headers, header_rows )
|
298
298
|
else ; fail ArgumentError, "Unsupported class: #{ other.class }"
|
299
299
|
end
|
@@ -308,10 +308,8 @@ module RubyExcel
|
|
308
308
|
|
309
309
|
# @overload advanced_filter!( header, comparison_operator, search_criteria, ... )
|
310
310
|
# Filter on multiple criteria
|
311
|
-
#
|
312
311
|
# @example Filter to 'Part': 'Type1' and 'Type3', with Qty greater than 1
|
313
312
|
# s.advanced_filter!( 'Part', :=~, /Type[13]/, 'Qty', :>, 1 )
|
314
|
-
#
|
315
313
|
# @example Filter to 'Part': 'Type1', with 'Ref1' containing 'X'
|
316
314
|
# s.advanced_filter!( 'Part', :==, 'Type1', 'Ref1', :include?, 'X' )
|
317
315
|
#
|
@@ -474,6 +472,7 @@ module RubyExcel
|
|
474
472
|
# Select and re-order Columns by a list of headers
|
475
473
|
#
|
476
474
|
# @param [Array<String>] headers the ordered list of headers to keep
|
475
|
+
# @note This method can accept either a list of arguments or an Array
|
477
476
|
# @note Invalid headers will be skipped
|
478
477
|
#
|
479
478
|
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require_relative '../../rubyexcel'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
|
5
|
+
class TestAddress < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@s = RubyExcel.sample_sheet
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
@s = nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_address_to_col_index
|
16
|
+
|
17
|
+
assert( @s.address_to_col_index( 'A1' ) == 1 )
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_address_to_indices
|
22
|
+
|
23
|
+
assert_equal( [ 1, 1 ], @s.address_to_indices( 'A1' ) )
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_col_index
|
28
|
+
|
29
|
+
assert_equal( 1, @s.col_index( 'A' ) )
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_col_letter
|
34
|
+
|
35
|
+
assert_equal( 'A', @s.col_letter( 1 ) )
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_column_id
|
40
|
+
|
41
|
+
assert_equal( 'A', @s.column_id( 'A1' ) )
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_expand
|
46
|
+
|
47
|
+
assert_equal( [['A1','B1'],['A2', 'B2']], @s.expand( 'A1:B2' ) )
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_indices_to_address
|
52
|
+
|
53
|
+
assert_equal( 'A1', @s.indices_to_address( 1, 1 ) )
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_multi_array?
|
58
|
+
|
59
|
+
assert( @s.multi_array? RubyExcel.sample_data )
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_offset
|
64
|
+
|
65
|
+
assert_equal( 'B2', @s.offset( 'A1', 1, 1 ) )
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_to_range_address
|
70
|
+
|
71
|
+
assert_equal( 'A1:B2', @s.to_range_address( @s.cell(1,1), @s.cell(2,2) ) )
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_row_id
|
76
|
+
|
77
|
+
assert_equal( 2, @s.row_id( 'A2' ) )
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
require_relative '../../rubyexcel'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class TestData < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@s = RubyExcel.sample_sheet
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
@s = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_advanced_filter!
|
15
|
+
|
16
|
+
assert_equal( 3, @s.data.advanced_filter!( 'Part', :=~, /Type[13]/, 'Qty', :>, 1 ).rows )
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_colref_by_header
|
21
|
+
|
22
|
+
assert_equal( 'B', @s.data.colref_by_header( 'Ref1' ) )
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_compact
|
27
|
+
|
28
|
+
@s << [[1,2,3], [4,5,6]]
|
29
|
+
assert( @s.data.cols == 5 && @s.data.rows == 10 )
|
30
|
+
|
31
|
+
@s.rows( 9 ) { |r| r.map! { nil } }
|
32
|
+
@s.data.compact!
|
33
|
+
assert_equal( 8, @s.data.rows )
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_delete
|
38
|
+
|
39
|
+
@s.data.delete( @s.row(1) )
|
40
|
+
assert_equal( 7, @s.data.rows )
|
41
|
+
|
42
|
+
@s.data.delete( @s.column(1) )
|
43
|
+
assert_equal( 4, @s.data.cols )
|
44
|
+
|
45
|
+
@s.data.delete( @s.range('A:A') )
|
46
|
+
assert_equal( 3, @s.data.cols )
|
47
|
+
|
48
|
+
assert_raise( NoMethodError ) { @s.data.delete( [[]] ) }
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_each
|
53
|
+
|
54
|
+
assert_equal( 8, @s.data.each.count )
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_filter!
|
59
|
+
|
60
|
+
assert_equal( 3, @s.data.filter!( 'Part', &/Type2/ ).rows )
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_get_columns!
|
65
|
+
|
66
|
+
assert_equal( [ 'Ref2', 'Part' ], @s.data.get_columns!( 'Ref2', 'Part' ).sheet.row(1).to_a )
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_headers
|
71
|
+
|
72
|
+
assert_equal( 1, @s.data.headers.length )
|
73
|
+
|
74
|
+
@s.headers = 0
|
75
|
+
assert_equal( nil, @s.data.headers )
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_index_by_header
|
80
|
+
|
81
|
+
assert_equal( 1, @s.data.index_by_header( 'Part' ) )
|
82
|
+
|
83
|
+
@s.headers = 0
|
84
|
+
assert_raise( NoMethodError ) { @s.data.index_by_header( 'Part' ) }
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_insert
|
89
|
+
|
90
|
+
@s.data.insert_columns( 'A', 2 )
|
91
|
+
assert_equal( 7, @s.maxcol )
|
92
|
+
assert_equal( nil, @s['B2'] )
|
93
|
+
|
94
|
+
@s.data.insert_rows( 2, 2 )
|
95
|
+
assert_equal( 10, @s.maxrow )
|
96
|
+
assert_equal( nil, @s['B4'] )
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_no_headers
|
101
|
+
|
102
|
+
assert_equal( 7, @s.data.no_headers.length )
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_partition
|
107
|
+
|
108
|
+
ar1, ar2 = @s.data.partition( 'Part', &/Type[13]/ )
|
109
|
+
assert_equal( 5, ar1.length )
|
110
|
+
assert_equal( 'Type1', ar1[1][0] )
|
111
|
+
assert_equal( 4, ar2.length )
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_read_write
|
116
|
+
|
117
|
+
assert_equal( '123', @s.data.read( 'C3' ) )
|
118
|
+
|
119
|
+
@s.data.write( 'C3', '321' )
|
120
|
+
assert_equal( '321', @s.data.read( 'C3' ) )
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_reverse
|
125
|
+
|
126
|
+
@s.data.reverse_columns!
|
127
|
+
assert_equal( 'Cost', @s.A1 )
|
128
|
+
|
129
|
+
@s.data.reverse_rows!
|
130
|
+
assert_equal( 'QT1', @s.d8 )
|
131
|
+
|
132
|
+
@s.headers = 0
|
133
|
+
@s.data.reverse_rows!
|
134
|
+
assert_equal( 'Ref1', @s.d8 )
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_skip_headers
|
139
|
+
|
140
|
+
@s.load( @s.data.skip_headers { |data| data.map { |row| row.map { nil } } } )
|
141
|
+
assert_equal( 'Part', @s.a1 )
|
142
|
+
assert_equal( nil, @s.a2 )
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_uniq!
|
147
|
+
|
148
|
+
@s.data.uniq!( 'Part' )
|
149
|
+
assert_equal( 5, @s.maxrow )
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative '../../rubyexcel'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class TestElement < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@s = RubyExcel.sample_sheet
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
@s = nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_initialize
|
15
|
+
|
16
|
+
r = @s.range( 'A1:B2' )
|
17
|
+
assert_equal( @s, r.sheet )
|
18
|
+
assert_equal( 'A1:B2', r.address )
|
19
|
+
assert_equal( 'A', r.column )
|
20
|
+
assert_equal( 1, r.row )
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_value
|
25
|
+
|
26
|
+
r = @s.range( 'A1' )
|
27
|
+
assert_equal( 'Part', r.value )
|
28
|
+
|
29
|
+
r = @s.range( 'A1:B2' )
|
30
|
+
assert_equal( [['Part', 'Ref1'], ['Type1', 'QT1']], r.value )
|
31
|
+
|
32
|
+
assert_raise( ArgumentError ) { r.value = [[1, 2]] }
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_each
|
37
|
+
|
38
|
+
assert_equal( 6, @s.range( 'A1:C2' ).each.count )
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require_relative '../../rubyexcel'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class TestRowColumn < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@s = RubyExcel.sample_sheet
|
8
|
+
@r = @s.row(2)
|
9
|
+
@c = @s.column(2)
|
10
|
+
end
|
11
|
+
|
12
|
+
def teardown
|
13
|
+
@s = nil
|
14
|
+
@r = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_shovel
|
18
|
+
|
19
|
+
@r << 1
|
20
|
+
assert_equal( 5, @r.length )
|
21
|
+
|
22
|
+
@r = @s.row(1)
|
23
|
+
@r << 1
|
24
|
+
assert_equal( 6, @r.length )
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_cell
|
29
|
+
|
30
|
+
assert_equal( @r.cell(2).address, @c.cell(2).address )
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_find
|
35
|
+
|
36
|
+
assert_equal( 'B2', @r.find( &/QT1/ ) )
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_summarise
|
41
|
+
|
42
|
+
h = { 'Type1' => 3, 'Type2' => 2, 'Type3' => 1, 'Type4' => 1 }
|
43
|
+
assert_equal( h, @s.column(1).summarise )
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_getref
|
48
|
+
|
49
|
+
assert_equal( 'A', @r.getref( 'Part' ) )
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_value_by_header
|
54
|
+
|
55
|
+
assert_equal( 'Type1', @r.val( 'Part' ) )
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,272 @@
|
|
1
|
+
require_relative '../rubyexcel'
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class TestRegexp < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_to_proc
|
7
|
+
assert_equal(0, /a/.to_proc.call('a') )
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
class TestWorkbook < Test::Unit::TestCase
|
13
|
+
|
14
|
+
def setup
|
15
|
+
@wb = RubyExcel::Workbook.new
|
16
|
+
3.times { @wb.add.load RubyExcel.sample_data }
|
17
|
+
end
|
18
|
+
|
19
|
+
def teardown
|
20
|
+
@wb = nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_shovel
|
24
|
+
|
25
|
+
@wb << @wb.dup
|
26
|
+
assert_equal( 6, @wb.sheets.count )
|
27
|
+
|
28
|
+
@wb << @wb.sheets(1)
|
29
|
+
assert_equal( 7, @wb.sheets.count )
|
30
|
+
|
31
|
+
@wb << @wb.sheets(1).data.all
|
32
|
+
assert_equal( 8, @wb.sheets.count )
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_add
|
37
|
+
|
38
|
+
@wb.add 'Sheet4'
|
39
|
+
assert_equal( 4, @wb.sheets.count )
|
40
|
+
|
41
|
+
@wb.add
|
42
|
+
assert_equal( 5, @wb.sheets.count )
|
43
|
+
|
44
|
+
@wb.add @wb.sheets(1)
|
45
|
+
assert_equal( 6, @wb.sheets.count )
|
46
|
+
|
47
|
+
assert_raise( TypeError ) { @wb.add 1 }
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_clear_all
|
52
|
+
|
53
|
+
assert_equal( 0, @wb.clear_all.sheets.count )
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_delete
|
58
|
+
|
59
|
+
assert_equal( 2, @wb.delete(1).sheets.count )
|
60
|
+
|
61
|
+
assert_equal( 1, @wb.delete( 'Sheet2' ).sheets.count )
|
62
|
+
|
63
|
+
assert_equal( 0, @wb.delete( /Sheet/ ).sheets.count )
|
64
|
+
|
65
|
+
assert_equal( 0, @wb.delete( @wb.add ).sheets.count )
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_dup
|
70
|
+
|
71
|
+
dup_wb = @wb.dup
|
72
|
+
|
73
|
+
assert_equal( @wb.sheets(1).to_a, dup_wb.sheets(1).to_a )
|
74
|
+
|
75
|
+
assert_not_equal( @wb.object_id, dup_wb.object_id )
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_empty?
|
80
|
+
|
81
|
+
assert( !@wb.empty? )
|
82
|
+
|
83
|
+
assert( @wb.clear_all.empty? )
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_load
|
88
|
+
|
89
|
+
assert( @wb.load( [[]] ).class == RubyExcel::Sheet )
|
90
|
+
|
91
|
+
assert( @wb.load( RubyExcel.sample_data )['A1'] == 'Part' )
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_sheets
|
96
|
+
|
97
|
+
assert( @wb.sheets.class == Enumerator )
|
98
|
+
|
99
|
+
assert( @wb.sheets(2) == @wb.sheets('Sheet2') )
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
class TestSheet < Test::Unit::TestCase
|
106
|
+
|
107
|
+
def setup
|
108
|
+
@s = RubyExcel.sample_sheet
|
109
|
+
end
|
110
|
+
|
111
|
+
def teardown
|
112
|
+
@s = nil
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_basics
|
116
|
+
|
117
|
+
assert( @s['A1'] == @s.A1 )
|
118
|
+
|
119
|
+
@s << RubyExcel.sample_hash
|
120
|
+
assert( @s.maxrow == 20 && @s.maxcol == 5 )
|
121
|
+
|
122
|
+
@s << RubyExcel.sample_data
|
123
|
+
assert( @s.maxrow == 28 && @s.maxcol == 5 )
|
124
|
+
|
125
|
+
@s << @s
|
126
|
+
assert( @s.maxrow == 55 && @s.maxcol == 5 )
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_advanced_filter
|
131
|
+
|
132
|
+
@s.advanced_filter!( 'Part', :=~, /Type[13]/, 'Qty', :>, 1 )
|
133
|
+
assert( @s.maxrow == 3 )
|
134
|
+
|
135
|
+
setup
|
136
|
+
@s.advanced_filter!( 'Part', :==, 'Type1', 'Ref1', :include?, 'X' )
|
137
|
+
assert( @s.maxrow == 2 )
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_cell
|
142
|
+
|
143
|
+
assert( @s.cell(1,1).value == 'Part' && @s.cell(1,1).address == 'A1' )
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_column
|
148
|
+
|
149
|
+
assert( @s.column('A')[1] == 'Part' )
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
def test_column_by_header
|
154
|
+
|
155
|
+
assert( @s.ch( 'Part' )[1] == @s.ch( @s.column(1) )[1] )
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
def test_columns
|
160
|
+
|
161
|
+
assert( @s.columns.class == Enumerator )
|
162
|
+
|
163
|
+
assert( @s.columns( 'B' ).count == 4 )
|
164
|
+
|
165
|
+
assert( @s.columns( 'B', 'D' ).to_a[0][1] == 'Ref1' )
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
def test_filter
|
170
|
+
|
171
|
+
assert( @s.filter( 'Part', &/Type[13]/ ).maxrow == 5 )
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_get_columns
|
176
|
+
|
177
|
+
assert_equal( @s.get_columns( 'Ref2', 'Part' ).row(1).to_a, [ 'Ref2', 'Part' ] )
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_insert_columns
|
182
|
+
|
183
|
+
assert( @s.insert_columns( 2, 2 ).columns.count == 7 )
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_insert_rows
|
188
|
+
|
189
|
+
assert( @s.insert_rows( 2, 2 ).rows.count == 10 )
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
def test_match
|
194
|
+
|
195
|
+
assert( @s.match( 'Part', &/Type2/ ) == 3 )
|
196
|
+
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_method_missing
|
200
|
+
|
201
|
+
assert( @s.a1 == 'Part' )
|
202
|
+
|
203
|
+
assert_raise( NoMethodError ) { @s.abcd123 }
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_respond_to?
|
208
|
+
|
209
|
+
assert( @s.respond_to?(:A1) )
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_partition
|
214
|
+
|
215
|
+
s1, s2 = @s.partition( 'Qty' ) { |v| v > 1 }
|
216
|
+
assert_equal( s1.maxrow + 1, s2.maxrow )
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_range
|
221
|
+
|
222
|
+
assert( @s.range( 'A1:A1' ).value == @s.range( @s.cell(1,1), @s.cell( 1,1 ) ).value )
|
223
|
+
|
224
|
+
assert( @s.range( 'A1' ).value == @s.range( @s.cell(1,1) ).value )
|
225
|
+
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_reverse
|
229
|
+
|
230
|
+
assert( @s.reverse_columns!['A1'] == 'Cost' )
|
231
|
+
|
232
|
+
assert( @s.reverse_rows!['A2'] == 104 )
|
233
|
+
|
234
|
+
end
|
235
|
+
|
236
|
+
def test_row
|
237
|
+
|
238
|
+
assert( @s.row(1)['A'] == 'Part' )
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_rows
|
243
|
+
|
244
|
+
assert( @s.rows.class == Enumerator )
|
245
|
+
|
246
|
+
assert( @s.rows( 2 ).count == 7 )
|
247
|
+
|
248
|
+
assert( @s.rows( 2, 4 ).to_a[0]['A'] == 'Type1' )
|
249
|
+
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_sumif
|
253
|
+
|
254
|
+
assert( @s.sumif( 'Part', 'Cost', &/Type1/ ) == 169.15 )
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
def test_uniq
|
259
|
+
|
260
|
+
assert( @s.uniq( 'Part' ).maxrow == 5 )
|
261
|
+
|
262
|
+
end
|
263
|
+
|
264
|
+
def test_
|
265
|
+
|
266
|
+
assert( @s.vlookup( 'Part', 'Ref2', &/Type1/ ) == '231' )
|
267
|
+
|
268
|
+
end
|
269
|
+
|
270
|
+
|
271
|
+
|
272
|
+
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.1.0
|
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-
|
12
|
+
date: 2013-05-01 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: A tabular data structure, mixing Ruby with some of Excel's API style.
|
15
15
|
email: VirtuosoJoel@gmail.com
|
@@ -24,6 +24,12 @@ files:
|
|
24
24
|
- lib/rubyexcel/rubyexcel_components.rb
|
25
25
|
- lib/rubyexcel/section.rb
|
26
26
|
- lib/rubyexcel.rb
|
27
|
+
- lib/test/rubyexcel/tc_address.rb
|
28
|
+
- lib/test/rubyexcel/tc_data.rb
|
29
|
+
- lib/test/rubyexcel/tc_element.rb
|
30
|
+
- lib/test/rubyexcel/tc_section.rb
|
31
|
+
- lib/test/tc_rubyexcel.rb
|
32
|
+
- lib/test/test_all.rb
|
27
33
|
- lib/README.md
|
28
34
|
homepage: https://github.com/VirtuosoJoel
|
29
35
|
licenses: []
|