rw_fastercsv 1.5.6
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +1 -0
- data/CHANGELOG +177 -0
- data/COPYING +340 -0
- data/INSTALL +41 -0
- data/LICENSE +7 -0
- data/README +71 -0
- data/Rakefile +93 -0
- data/TODO +6 -0
- data/examples/csv_converters.rb +28 -0
- data/examples/csv_filter.rb +23 -0
- data/examples/csv_rails_import.task +21 -0
- data/examples/csv_reading.rb +57 -0
- data/examples/csv_table.rb +56 -0
- data/examples/csv_writing.rb +67 -0
- data/examples/purchase.csv +3 -0
- data/examples/shortcut_interface.rb +36 -0
- data/lib/faster_csv.rb +2006 -0
- data/lib/fastercsv.rb +10 -0
- data/setup.rb +1360 -0
- data/test/export.csv +5 -0
- data/test/line_endings.gz +0 -0
- data/test/tc_csv_parsing.rb +194 -0
- data/test/tc_csv_writing.rb +96 -0
- data/test/tc_data_converters.rb +260 -0
- data/test/tc_encodings.rb +23 -0
- data/test/tc_features.rb +212 -0
- data/test/tc_headers.rb +277 -0
- data/test/tc_interface.rb +376 -0
- data/test/tc_row.rb +305 -0
- data/test/tc_rp_cases.rb +45 -0
- data/test/tc_serialization.rb +154 -0
- data/test/tc_speed.rb +65 -0
- data/test/tc_table.rb +408 -0
- data/test/test_data.csv +1000 -0
- data/test/ts_all.rb +21 -0
- metadata +97 -0
@@ -0,0 +1,376 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
# tc_interface.rb
|
4
|
+
#
|
5
|
+
# Created by James Edward Gray II on 2005-11-14.
|
6
|
+
# Copyright 2005 Gray Productions. All rights reserved.
|
7
|
+
|
8
|
+
require "test/unit"
|
9
|
+
|
10
|
+
require "faster_csv"
|
11
|
+
|
12
|
+
class TestFasterCSVInterface < Test::Unit::TestCase
|
13
|
+
def setup
|
14
|
+
@path = File.join(File.dirname(__FILE__), "temp_test_data.csv")
|
15
|
+
|
16
|
+
File.open(@path, "w") do |file|
|
17
|
+
file << "1\t2\t3\r\n"
|
18
|
+
file << "4\t5\r\n"
|
19
|
+
end
|
20
|
+
|
21
|
+
@expected = [%w{1 2 3}, %w{4 5}]
|
22
|
+
end
|
23
|
+
|
24
|
+
def teardown
|
25
|
+
File.unlink(@path)
|
26
|
+
end
|
27
|
+
|
28
|
+
### Test Read Interface ###
|
29
|
+
|
30
|
+
def test_foreach
|
31
|
+
FasterCSV.foreach(@path, :col_sep => "\t", :row_sep => "\r\n") do |row|
|
32
|
+
assert_equal(@expected.shift, row)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_open_and_close
|
37
|
+
csv = FasterCSV.open(@path, "r+", :col_sep => "\t", :row_sep => "\r\n")
|
38
|
+
assert_not_nil(csv)
|
39
|
+
assert_instance_of(FasterCSV, csv)
|
40
|
+
assert_equal(false, csv.closed?)
|
41
|
+
csv.close
|
42
|
+
assert(csv.closed?)
|
43
|
+
|
44
|
+
ret = FasterCSV.open(@path) do |csv|
|
45
|
+
assert_instance_of(FasterCSV, csv)
|
46
|
+
"Return value."
|
47
|
+
end
|
48
|
+
assert(csv.closed?)
|
49
|
+
assert_equal("Return value.", ret)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_parse
|
53
|
+
data = File.read(@path)
|
54
|
+
assert_equal( @expected,
|
55
|
+
FasterCSV.parse(data, :col_sep => "\t", :row_sep => "\r\n") )
|
56
|
+
|
57
|
+
FasterCSV.parse(data, :col_sep => "\t", :row_sep => "\r\n") do |row|
|
58
|
+
assert_equal(@expected.shift, row)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_parse_line
|
63
|
+
row = FasterCSV.parse_line("1;2;3", :col_sep => ";")
|
64
|
+
assert_not_nil(row)
|
65
|
+
assert_instance_of(Array, row)
|
66
|
+
assert_equal(%w{1 2 3}, row)
|
67
|
+
|
68
|
+
# shortcut interface
|
69
|
+
row = "1;2;3".parse_csv(:col_sep => ";")
|
70
|
+
assert_not_nil(row)
|
71
|
+
assert_instance_of(Array, row)
|
72
|
+
assert_equal(%w{1 2 3}, row)
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_parse_line_with_empty_lines
|
76
|
+
assert_equal(nil, FasterCSV.parse_line("")) # to signal eof
|
77
|
+
assert_equal(Array.new, FasterCSV.parse_line("\n1,2,3"))
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_read_and_readlines
|
81
|
+
assert_equal( @expected,
|
82
|
+
FasterCSV.read(@path, :col_sep => "\t", :row_sep => "\r\n") )
|
83
|
+
assert_equal( @expected,
|
84
|
+
FasterCSV.readlines( @path,
|
85
|
+
:col_sep => "\t", :row_sep => "\r\n") )
|
86
|
+
|
87
|
+
|
88
|
+
data = FasterCSV.open(@path, :col_sep => "\t", :row_sep => "\r\n") do |csv|
|
89
|
+
csv.read
|
90
|
+
end
|
91
|
+
assert_equal(@expected, data)
|
92
|
+
data = FasterCSV.open(@path, :col_sep => "\t", :row_sep => "\r\n") do |csv|
|
93
|
+
csv.readlines
|
94
|
+
end
|
95
|
+
assert_equal(@expected, data)
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_table
|
99
|
+
table = FasterCSV.table(@path, :col_sep => "\t", :row_sep => "\r\n")
|
100
|
+
assert_instance_of(FasterCSV::Table, table)
|
101
|
+
assert_equal([[:"1", :"2", :"3"], [4, 5, nil]], table.to_a)
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_shift # aliased as gets() and readline()
|
105
|
+
FasterCSV.open(@path, "r+", :col_sep => "\t", :row_sep => "\r\n") do |csv|
|
106
|
+
assert_equal(@expected.shift, csv.shift)
|
107
|
+
assert_equal(@expected.shift, csv.shift)
|
108
|
+
assert_equal(nil, csv.shift)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_long_line # ruby's regex parser may have problems with long rows
|
113
|
+
File.unlink(@path)
|
114
|
+
|
115
|
+
long_field_length = 2800
|
116
|
+
File.open(@path, "w") do |file|
|
117
|
+
file << "1\t2\t#{'3' * long_field_length}\r\n"
|
118
|
+
end
|
119
|
+
@expected = [%w{1 2} + ['3' * long_field_length]]
|
120
|
+
test_shift
|
121
|
+
end
|
122
|
+
|
123
|
+
### Test Write Interface ###
|
124
|
+
|
125
|
+
def test_generate
|
126
|
+
str = FasterCSV.generate do |csv| # default empty String
|
127
|
+
assert_instance_of(FasterCSV, csv)
|
128
|
+
assert_equal(csv, csv << [1, 2, 3])
|
129
|
+
assert_equal(csv, csv << [4, nil, 5])
|
130
|
+
end
|
131
|
+
assert_not_nil(str)
|
132
|
+
assert_instance_of(String, str)
|
133
|
+
assert_equal("1,2,3\n4,,5\n", str)
|
134
|
+
|
135
|
+
FasterCSV.generate(str) do |csv| # appending to a String
|
136
|
+
assert_equal(csv, csv << ["last", %Q{"row"}])
|
137
|
+
end
|
138
|
+
assert_equal(%Q{1,2,3\n4,,5\nlast,"""row"""\n}, str)
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_generate_line
|
142
|
+
line = FasterCSV.generate_line(%w{1 2 3}, :col_sep => ";")
|
143
|
+
assert_not_nil(line)
|
144
|
+
assert_instance_of(String, line)
|
145
|
+
assert_equal("1;2;3\n", line)
|
146
|
+
|
147
|
+
# shortcut interface
|
148
|
+
line = %w{1 2 3}.to_csv(:col_sep => ";")
|
149
|
+
assert_not_nil(line)
|
150
|
+
assert_instance_of(String, line)
|
151
|
+
assert_equal("1;2;3\n", line)
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_write_header_detection
|
155
|
+
File.unlink(@path)
|
156
|
+
|
157
|
+
headers = %w{a b c}
|
158
|
+
FasterCSV.open(@path, "w", :headers => true) do |csv|
|
159
|
+
csv << headers
|
160
|
+
csv << %w{1 2 3}
|
161
|
+
assert_equal(headers, csv.instance_variable_get(:@headers))
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def test_write_lineno
|
166
|
+
File.unlink(@path)
|
167
|
+
|
168
|
+
FasterCSV.open(@path, "w") do |csv|
|
169
|
+
lines = 20
|
170
|
+
lines.times { csv << %w{a b c} }
|
171
|
+
assert_equal(lines, csv.lineno)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_write_hash
|
176
|
+
File.unlink(@path)
|
177
|
+
|
178
|
+
lines = [{:a => 1, :b => 2, :c => 3}, {:a => 4, :b => 5, :c => 6}]
|
179
|
+
FasterCSV.open( @path, "w", :headers => true,
|
180
|
+
:header_converters => :symbol ) do |csv|
|
181
|
+
csv << lines.first.keys
|
182
|
+
lines.each { |line| csv << line }
|
183
|
+
end
|
184
|
+
FasterCSV.open( @path, "r", :headers => true,
|
185
|
+
:converters => :all,
|
186
|
+
:header_converters => :symbol ) do |csv|
|
187
|
+
csv.each { |line| assert_equal(lines.shift, line.to_hash) }
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_write_hash_with_headers_array
|
192
|
+
File.unlink(@path)
|
193
|
+
|
194
|
+
lines = [{:a => 1, :b => 2, :c => 3}, {:a => 4, :b => 5, :c => 6}]
|
195
|
+
FasterCSV.open(@path, "w", :headers => [:b, :a, :c]) do |csv|
|
196
|
+
lines.each { |line| csv << line }
|
197
|
+
end
|
198
|
+
|
199
|
+
# test writing fields in the correct order
|
200
|
+
File.open(@path, "r") do |f|
|
201
|
+
assert_equal("2,1,3", f.gets.strip)
|
202
|
+
assert_equal("5,4,6", f.gets.strip)
|
203
|
+
end
|
204
|
+
|
205
|
+
# test reading CSV with headers
|
206
|
+
FasterCSV.open( @path, "r", :headers => [:b, :a, :c],
|
207
|
+
:converters => :all ) do |csv|
|
208
|
+
csv.each { |line| assert_equal(lines.shift, line.to_hash) }
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_write_hash_with_headers_string
|
213
|
+
File.unlink(@path)
|
214
|
+
|
215
|
+
lines = [{"a" => 1, "b" => 2, "c" => 3}, {"a" => 4, "b" => 5, "c" => 6}]
|
216
|
+
FasterCSV.open( @path, "w", :headers => "b|a|c",
|
217
|
+
:col_sep => "|" ) do |csv|
|
218
|
+
lines.each { |line| csv << line }
|
219
|
+
end
|
220
|
+
|
221
|
+
# test writing fields in the correct order
|
222
|
+
File.open(@path, "r") do |f|
|
223
|
+
assert_equal("2|1|3", f.gets.strip)
|
224
|
+
assert_equal("5|4|6", f.gets.strip)
|
225
|
+
end
|
226
|
+
|
227
|
+
# test reading CSV with headers
|
228
|
+
FasterCSV.open( @path, "r", :headers => "b|a|c",
|
229
|
+
:col_sep => "|",
|
230
|
+
:converters => :all ) do |csv|
|
231
|
+
csv.each { |line| assert_equal(lines.shift, line.to_hash) }
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def test_write_headers
|
236
|
+
File.unlink(@path)
|
237
|
+
|
238
|
+
lines = [{"a" => 1, "b" => 2, "c" => 3}, {"a" => 4, "b" => 5, "c" => 6}]
|
239
|
+
FasterCSV.open( @path, "w", :headers => "b|a|c",
|
240
|
+
:write_headers => true,
|
241
|
+
:col_sep => "|" ) do |csv|
|
242
|
+
lines.each { |line| csv << line }
|
243
|
+
end
|
244
|
+
|
245
|
+
# test writing fields in the correct order
|
246
|
+
File.open(@path, "r") do |f|
|
247
|
+
assert_equal("b|a|c", f.gets.strip)
|
248
|
+
assert_equal("2|1|3", f.gets.strip)
|
249
|
+
assert_equal("5|4|6", f.gets.strip)
|
250
|
+
end
|
251
|
+
|
252
|
+
# test reading CSV with headers
|
253
|
+
FasterCSV.open( @path, "r", :headers => true,
|
254
|
+
:col_sep => "|",
|
255
|
+
:converters => :all ) do |csv|
|
256
|
+
csv.each { |line| assert_equal(lines.shift, line.to_hash) }
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_append # aliased add_row() and puts()
|
261
|
+
File.unlink(@path)
|
262
|
+
|
263
|
+
FasterCSV.open(@path, "w", :col_sep => "\t", :row_sep => "\r\n") do |csv|
|
264
|
+
@expected.each { |row| csv << row }
|
265
|
+
end
|
266
|
+
|
267
|
+
test_shift
|
268
|
+
|
269
|
+
# same thing using FasterCSV::Row objects
|
270
|
+
File.unlink(@path)
|
271
|
+
|
272
|
+
FasterCSV.open(@path, "w", :col_sep => "\t", :row_sep => "\r\n") do |csv|
|
273
|
+
@expected.each { |row| csv << FasterCSV::Row.new(Array.new, row) }
|
274
|
+
end
|
275
|
+
|
276
|
+
test_shift
|
277
|
+
end
|
278
|
+
|
279
|
+
### Test Read and Write Interface ###
|
280
|
+
|
281
|
+
def test_filter
|
282
|
+
assert_respond_to(FasterCSV, :filter)
|
283
|
+
|
284
|
+
expected = [[1, 2, 3], [4, 5]]
|
285
|
+
FasterCSV.filter( "1;2;3\n4;5\n", (result = String.new),
|
286
|
+
:in_col_sep => ";", :out_col_sep => ",",
|
287
|
+
:converters => :all ) do |row|
|
288
|
+
assert_equal(row, expected.shift)
|
289
|
+
row.map! { |n| n * 2 }
|
290
|
+
row << "Added\r"
|
291
|
+
end
|
292
|
+
assert_equal("2,4,6,\"Added\r\"\n8,10,\"Added\r\"\n", result)
|
293
|
+
end
|
294
|
+
|
295
|
+
def test_instance
|
296
|
+
csv = String.new
|
297
|
+
|
298
|
+
first = nil
|
299
|
+
assert_nothing_raised(Exception) do
|
300
|
+
first = FasterCSV.instance(csv, :col_sep => ";")
|
301
|
+
first << %w{a b c}
|
302
|
+
end
|
303
|
+
|
304
|
+
assert_equal("a;b;c\n", csv)
|
305
|
+
|
306
|
+
second = nil
|
307
|
+
assert_nothing_raised(Exception) do
|
308
|
+
second = FasterCSV.instance(csv, :col_sep => ";")
|
309
|
+
second << [1, 2, 3]
|
310
|
+
end
|
311
|
+
|
312
|
+
assert_equal(first.object_id, second.object_id)
|
313
|
+
assert_equal("a;b;c\n1;2;3\n", csv)
|
314
|
+
|
315
|
+
# shortcuts
|
316
|
+
assert_equal(STDOUT, FasterCSV.instance.instance_eval { @io })
|
317
|
+
assert_equal(STDOUT, FasterCSV { |csv| csv.instance_eval { @io } })
|
318
|
+
assert_equal(STDOUT, FCSV.instance.instance_eval { @io })
|
319
|
+
assert_equal(STDOUT, FCSV { |csv| csv.instance_eval { @io } })
|
320
|
+
end
|
321
|
+
|
322
|
+
### Test Alternate Interface ###
|
323
|
+
|
324
|
+
def test_csv_interface
|
325
|
+
require "csv"
|
326
|
+
data = ["Number", 42, "Tricky Field", 'This has embedded "quotes"!']
|
327
|
+
data_file = File.join(File.dirname(__FILE__), "temp_csv_data.csv")
|
328
|
+
CSV.open(data_file, "w") { |f| 10.times { f << data } }
|
329
|
+
csv = CSV.generate_line(data)
|
330
|
+
tests = { :foreach => Array.new,
|
331
|
+
:generate_line => csv,
|
332
|
+
:open => Array.new,
|
333
|
+
:parse => CSV.parse(csv),
|
334
|
+
:parse_w_block => Array.new,
|
335
|
+
:parse_line => CSV.parse_line(csv),
|
336
|
+
:readlines => CSV.readlines(data_file) }
|
337
|
+
CSV.foreach(data_file) { |row| tests[:foreach] << row }
|
338
|
+
CSV.open(data_file, "r") { |row| tests[:open] << row }
|
339
|
+
CSV.parse(([csv] * 3).join("\n")) { |row| tests[:parse_w_block] << row }
|
340
|
+
Object.send(:remove_const, :CSV)
|
341
|
+
|
342
|
+
assert_nothing_raised(Exception) do
|
343
|
+
FasterCSV.build_csv_interface
|
344
|
+
end
|
345
|
+
|
346
|
+
%w{ foreach
|
347
|
+
generate_line
|
348
|
+
open
|
349
|
+
parse
|
350
|
+
parse_line
|
351
|
+
readlines }.each do |meth|
|
352
|
+
assert_respond_to(::CSV, meth)
|
353
|
+
end
|
354
|
+
|
355
|
+
faster_csv = Array.new
|
356
|
+
CSV.foreach(data_file) { |row| faster_csv << row }
|
357
|
+
assert_equal(tests[:foreach], faster_csv)
|
358
|
+
assert_equal(tests[:generate_line], CSV.generate_line(data))
|
359
|
+
faster_csv.clear
|
360
|
+
CSV.open(data_file, "r") { |row| faster_csv << row }
|
361
|
+
assert_equal(tests[:open], faster_csv)
|
362
|
+
comp_file = data_file.sub("_csv_data", "_faster_csv_data")
|
363
|
+
CSV.open(comp_file, "w") { |f| 10.times { f << data } }
|
364
|
+
assert_equal(File.read(data_file), File.read(comp_file))
|
365
|
+
assert_equal(tests[:parse], CSV.parse(csv))
|
366
|
+
faster_csv.clear
|
367
|
+
CSV.parse(([csv] * 3).join("\n")) { |row| faster_csv << row }
|
368
|
+
assert_equal(tests[:parse_w_block], faster_csv)
|
369
|
+
assert_equal(tests[:parse_line], CSV.parse_line(csv))
|
370
|
+
assert_equal(tests[:readlines], CSV.readlines(data_file))
|
371
|
+
|
372
|
+
Object.send(:remove_const, :CSV)
|
373
|
+
load "csv.rb"
|
374
|
+
[data_file, comp_file].each { |file| File.unlink(file) }
|
375
|
+
end
|
376
|
+
end
|
data/test/tc_row.rb
ADDED
@@ -0,0 +1,305 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
# tc_row.rb
|
4
|
+
#
|
5
|
+
# Created by James Edward Gray II on 2006-02-24.
|
6
|
+
# Copyright 2006 Gray Productions. All rights reserved.
|
7
|
+
|
8
|
+
require "test/unit"
|
9
|
+
|
10
|
+
require "faster_csv"
|
11
|
+
|
12
|
+
class TestFasterCSVRow < Test::Unit::TestCase
|
13
|
+
def setup
|
14
|
+
@row = FasterCSV::Row.new(%w{A B C A A}, [1, 2, 3, 4])
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_initialize
|
18
|
+
# basic
|
19
|
+
row = FasterCSV::Row.new(%w{A B C}, [1, 2, 3])
|
20
|
+
assert_not_nil(row)
|
21
|
+
assert_instance_of(FasterCSV::Row, row)
|
22
|
+
assert_equal([["A", 1], ["B", 2], ["C", 3]], row.to_a)
|
23
|
+
|
24
|
+
# missing headers
|
25
|
+
row = FasterCSV::Row.new(%w{A}, [1, 2, 3])
|
26
|
+
assert_not_nil(row)
|
27
|
+
assert_instance_of(FasterCSV::Row, row)
|
28
|
+
assert_equal([["A", 1], [nil, 2], [nil, 3]], row.to_a)
|
29
|
+
|
30
|
+
# missing fields
|
31
|
+
row = FasterCSV::Row.new(%w{A B C}, [1, 2])
|
32
|
+
assert_not_nil(row)
|
33
|
+
assert_instance_of(FasterCSV::Row, row)
|
34
|
+
assert_equal([["A", 1], ["B", 2], ["C", nil]], row.to_a)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_row_type
|
38
|
+
# field rows
|
39
|
+
row = FasterCSV::Row.new(%w{A B C}, [1, 2, 3]) # implicit
|
40
|
+
assert(!row.header_row?)
|
41
|
+
assert(row.field_row?)
|
42
|
+
row = FasterCSV::Row.new(%w{A B C}, [1, 2, 3], false) # explicit
|
43
|
+
assert(!row.header_row?)
|
44
|
+
assert(row.field_row?)
|
45
|
+
|
46
|
+
# header row
|
47
|
+
row = FasterCSV::Row.new(%w{A B C}, [1, 2, 3], true)
|
48
|
+
assert(row.header_row?)
|
49
|
+
assert(!row.field_row?)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_headers
|
53
|
+
assert_equal(%w{A B C A A}, @row.headers)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_field
|
57
|
+
# by name
|
58
|
+
assert_equal(2, @row.field("B"))
|
59
|
+
assert_equal(2, @row["B"]) # alias
|
60
|
+
|
61
|
+
# by index
|
62
|
+
assert_equal(3, @row.field(2))
|
63
|
+
|
64
|
+
# missing
|
65
|
+
assert_nil(@row.field("Missing"))
|
66
|
+
assert_nil(@row.field(10))
|
67
|
+
|
68
|
+
# minimum index
|
69
|
+
assert_equal(1, @row.field("A"))
|
70
|
+
assert_equal(1, @row.field("A", 0))
|
71
|
+
assert_equal(4, @row.field("A", 1))
|
72
|
+
assert_equal(4, @row.field("A", 2))
|
73
|
+
assert_equal(4, @row.field("A", 3))
|
74
|
+
assert_equal(nil, @row.field("A", 4))
|
75
|
+
assert_equal(nil, @row.field("A", 5))
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_set_field
|
79
|
+
# set field by name
|
80
|
+
assert_equal(100, @row["A"] = 100)
|
81
|
+
|
82
|
+
# set field by index
|
83
|
+
assert_equal(300, @row[3] = 300)
|
84
|
+
|
85
|
+
# set field by name and minimum index
|
86
|
+
assert_equal([:a, :b, :c], @row["A", 4] = [:a, :b, :c])
|
87
|
+
|
88
|
+
# verify the changes
|
89
|
+
assert_equal( [ ["A", 100],
|
90
|
+
["B", 2],
|
91
|
+
["C", 3],
|
92
|
+
["A", 300],
|
93
|
+
["A", [:a, :b, :c]] ], @row.to_a )
|
94
|
+
|
95
|
+
# assigning an index past the end
|
96
|
+
assert_equal("End", @row[10] = "End")
|
97
|
+
assert_equal( [ ["A", 100],
|
98
|
+
["B", 2],
|
99
|
+
["C", 3],
|
100
|
+
["A", 300],
|
101
|
+
["A", [:a, :b, :c]],
|
102
|
+
[nil, nil],
|
103
|
+
[nil, nil],
|
104
|
+
[nil, nil],
|
105
|
+
[nil, nil],
|
106
|
+
[nil, nil],
|
107
|
+
[nil, "End"] ], @row.to_a )
|
108
|
+
|
109
|
+
# assigning a new field by header
|
110
|
+
assert_equal("New", @row[:new] = "New")
|
111
|
+
assert_equal( [ ["A", 100],
|
112
|
+
["B", 2],
|
113
|
+
["C", 3],
|
114
|
+
["A", 300],
|
115
|
+
["A", [:a, :b, :c]],
|
116
|
+
[nil, nil],
|
117
|
+
[nil, nil],
|
118
|
+
[nil, nil],
|
119
|
+
[nil, nil],
|
120
|
+
[nil, nil],
|
121
|
+
[nil, "End"],
|
122
|
+
[:new, "New"] ], @row.to_a )
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_append
|
126
|
+
# add a value
|
127
|
+
assert_equal(@row, @row << "Value")
|
128
|
+
assert_equal( [ ["A", 1],
|
129
|
+
["B", 2],
|
130
|
+
["C", 3],
|
131
|
+
["A", 4],
|
132
|
+
["A", nil],
|
133
|
+
[nil, "Value"] ], @row.to_a )
|
134
|
+
|
135
|
+
# add a pair
|
136
|
+
assert_equal(@row, @row << %w{Header Field})
|
137
|
+
assert_equal( [ ["A", 1],
|
138
|
+
["B", 2],
|
139
|
+
["C", 3],
|
140
|
+
["A", 4],
|
141
|
+
["A", nil],
|
142
|
+
[nil, "Value"],
|
143
|
+
%w{Header Field} ], @row.to_a )
|
144
|
+
|
145
|
+
# a pair with Hash syntax
|
146
|
+
assert_equal(@row, @row << {:key => :value})
|
147
|
+
assert_equal( [ ["A", 1],
|
148
|
+
["B", 2],
|
149
|
+
["C", 3],
|
150
|
+
["A", 4],
|
151
|
+
["A", nil],
|
152
|
+
[nil, "Value"],
|
153
|
+
%w{Header Field},
|
154
|
+
[:key, :value] ], @row.to_a )
|
155
|
+
|
156
|
+
# multiple fields at once
|
157
|
+
assert_equal(@row, @row.push(100, 200, [:last, 300]))
|
158
|
+
assert_equal( [ ["A", 1],
|
159
|
+
["B", 2],
|
160
|
+
["C", 3],
|
161
|
+
["A", 4],
|
162
|
+
["A", nil],
|
163
|
+
[nil, "Value"],
|
164
|
+
%w{Header Field},
|
165
|
+
[:key, :value],
|
166
|
+
[nil, 100],
|
167
|
+
[nil, 200],
|
168
|
+
[:last, 300] ], @row.to_a )
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_delete
|
172
|
+
# by index
|
173
|
+
assert_equal(["B", 2], @row.delete(1))
|
174
|
+
|
175
|
+
# by header
|
176
|
+
assert_equal(["C", 3], @row.delete("C"))
|
177
|
+
|
178
|
+
# using a block
|
179
|
+
assert_equal(@row, @row.delete_if { |h, f| h == "A" and not f.nil? })
|
180
|
+
assert_equal([["A", nil]], @row.to_a)
|
181
|
+
end
|
182
|
+
|
183
|
+
def test_fields
|
184
|
+
# all fields
|
185
|
+
assert_equal([1, 2, 3, 4, nil], @row.fields)
|
186
|
+
|
187
|
+
# by header
|
188
|
+
assert_equal([1, 3], @row.fields("A", "C"))
|
189
|
+
|
190
|
+
# by index
|
191
|
+
assert_equal([2, 3, nil], @row.fields(1, 2, 10))
|
192
|
+
|
193
|
+
# by both
|
194
|
+
assert_equal([2, 3, 4], @row.fields("B", "C", 3))
|
195
|
+
|
196
|
+
# with minimum indices
|
197
|
+
assert_equal([2, 3, 4], @row.fields("B", "C", ["A", 3]))
|
198
|
+
|
199
|
+
# by header range
|
200
|
+
assert_equal([2, 3], @row.values_at("B".."C"))
|
201
|
+
end
|
202
|
+
|
203
|
+
def test_index
|
204
|
+
# basic usage
|
205
|
+
assert_equal(0, @row.index("A"))
|
206
|
+
assert_equal(1, @row.index("B"))
|
207
|
+
assert_equal(2, @row.index("C"))
|
208
|
+
assert_equal(nil, @row.index("Z"))
|
209
|
+
|
210
|
+
# with minimum index
|
211
|
+
assert_equal(0, @row.index("A"))
|
212
|
+
assert_equal(0, @row.index("A", 0))
|
213
|
+
assert_equal(3, @row.index("A", 1))
|
214
|
+
assert_equal(3, @row.index("A", 2))
|
215
|
+
assert_equal(3, @row.index("A", 3))
|
216
|
+
assert_equal(4, @row.index("A", 4))
|
217
|
+
assert_equal(nil, @row.index("A", 5))
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_queries
|
221
|
+
# headers
|
222
|
+
assert(@row.header?("A"))
|
223
|
+
assert(@row.header?("C"))
|
224
|
+
assert(!@row.header?("Z"))
|
225
|
+
assert(@row.include?("A")) # alias
|
226
|
+
|
227
|
+
# fields
|
228
|
+
assert(@row.field?(4))
|
229
|
+
assert(@row.field?(nil))
|
230
|
+
assert(!@row.field?(10))
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_each
|
234
|
+
# array style
|
235
|
+
ary = @row.to_a
|
236
|
+
@row.each do |pair|
|
237
|
+
assert_equal(ary.first.first, pair.first)
|
238
|
+
assert_equal(ary.shift.last, pair.last)
|
239
|
+
end
|
240
|
+
|
241
|
+
# hash style
|
242
|
+
ary = @row.to_a
|
243
|
+
@row.each do |header, field|
|
244
|
+
assert_equal(ary.first.first, header)
|
245
|
+
assert_equal(ary.shift.last, field)
|
246
|
+
end
|
247
|
+
|
248
|
+
# verify that we can chain the call
|
249
|
+
assert_equal(@row, @row.each { })
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_enumerable
|
253
|
+
assert_equal( [["A", 1], ["A", 4], ["A", nil]],
|
254
|
+
@row.select { |pair| pair.first == "A" } )
|
255
|
+
|
256
|
+
assert_equal(10, @row.inject(0) { |sum, (header, n)| sum + (n || 0) })
|
257
|
+
end
|
258
|
+
|
259
|
+
def test_to_a
|
260
|
+
row = FasterCSV::Row.new(%w{A B C}, [1, 2, 3]).to_a
|
261
|
+
assert_instance_of(Array, row)
|
262
|
+
row.each do |pair|
|
263
|
+
assert_instance_of(Array, pair)
|
264
|
+
assert_equal(2, pair.size)
|
265
|
+
end
|
266
|
+
assert_equal([["A", 1], ["B", 2], ["C", 3]], row)
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_to_hash
|
270
|
+
assert_equal({"A" => nil, "B" => 2, "C" => 3}, @row.to_hash)
|
271
|
+
end
|
272
|
+
|
273
|
+
def test_to_csv
|
274
|
+
# normal conversion
|
275
|
+
assert_equal("1,2,3,4,\n", @row.to_csv)
|
276
|
+
assert_equal("1,2,3,4,\n", @row.to_s) # alias
|
277
|
+
|
278
|
+
# with options
|
279
|
+
assert_equal( "1|2|3|4|\r\n",
|
280
|
+
@row.to_csv(:col_sep => "|", :row_sep => "\r\n") )
|
281
|
+
end
|
282
|
+
|
283
|
+
def test_array_delegation
|
284
|
+
assert(!@row.empty?, "Row was empty.")
|
285
|
+
|
286
|
+
assert_equal([@row.headers.size, @row.fields.size].max, @row.size)
|
287
|
+
end
|
288
|
+
|
289
|
+
def test_inspect_shows_header_field_pairs
|
290
|
+
str = @row.inspect
|
291
|
+
@row.each do |header, field|
|
292
|
+
assert( str.include?("#{header.inspect}:#{field.inspect}"),
|
293
|
+
"Header field pair not found." )
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
def test_inspect_shows_symbol_headers_as_bare_attributes
|
298
|
+
str = FasterCSV::Row.new( @row.headers.map { |h| h.to_sym },
|
299
|
+
@row.fields ).inspect
|
300
|
+
@row.each do |header, field|
|
301
|
+
assert( str.include?("#{header}:#{field.inspect}"),
|
302
|
+
"Header field pair not found." )
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|