rw_fastercsv 1.5.6
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/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
|