fastcsv 0.0.2 → 0.0.3
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.
- checksums.yaml +4 -4
- data/.travis.yml +11 -0
- data/README.md +37 -2
- data/TESTS.md +42 -0
- data/ext/fastcsv/fastcsv.c +281 -223
- data/ext/fastcsv/fastcsv.rl +149 -72
- data/fastcsv.gemspec +1 -1
- data/lib/fastcsv.rb +130 -0
- data/spec/fastcsv_spec.rb +189 -57
- data/spec/fixtures/csv.csv +3 -0
- data/spec/fixtures/iso-8859-1-quoted.csv +1 -0
- data/spec/fixtures/utf-8-quoted.csv +1 -0
- data/spec/spec_helper.rb +5 -0
- data/test/csv/base.rb +8 -0
- data/test/csv/line_endings.gz +0 -0
- data/test/csv/test_csv_parsing.rb +221 -0
- data/test/csv/test_csv_writing.rb +97 -0
- data/test/csv/test_data_converters.rb +263 -0
- data/test/csv/test_encodings.rb +339 -0
- data/test/csv/test_features.rb +317 -0
- data/test/csv/test_headers.rb +289 -0
- data/test/csv/test_interface.rb +362 -0
- data/test/csv/test_row.rb +349 -0
- data/test/csv/test_table.rb +420 -0
- data/test/csv/ts_all.rb +20 -0
- data/test/runner.rb +36 -0
- data/test/with_different_ofs.rb +17 -0
- metadata +38 -2
@@ -0,0 +1,362 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
# tc_interface.rb
|
5
|
+
#
|
6
|
+
# Created by James Edward Gray II on 2005-10-31.
|
7
|
+
# Copyright 2005 James Edward Gray II. You can redistribute or modify this code
|
8
|
+
# under the terms of Ruby's license.
|
9
|
+
|
10
|
+
require_relative "base"
|
11
|
+
require "tempfile"
|
12
|
+
|
13
|
+
class TestCSV::Interface < TestCSV
|
14
|
+
extend DifferentOFS
|
15
|
+
|
16
|
+
def setup
|
17
|
+
super
|
18
|
+
@tempfile = Tempfile.new(%w"temp .csv")
|
19
|
+
@tempfile.close
|
20
|
+
@path = @tempfile.path
|
21
|
+
|
22
|
+
File.open(@path, "wb") do |file|
|
23
|
+
file << "1,2,3\r\n"
|
24
|
+
file << "4,5\r\n"
|
25
|
+
end
|
26
|
+
|
27
|
+
@expected = [%w{1 2 3}, %w{4 5}]
|
28
|
+
end
|
29
|
+
|
30
|
+
def teardown
|
31
|
+
@tempfile.close(true)
|
32
|
+
super
|
33
|
+
end
|
34
|
+
|
35
|
+
### Test Read Interface ###
|
36
|
+
|
37
|
+
def test_foreach
|
38
|
+
FastCSV.foreach(@path, col_sep: ",", row_sep: "\r\n") do |row|
|
39
|
+
assert_equal(@expected.shift, row)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_foreach_enum
|
44
|
+
FastCSV.foreach(@path, col_sep: ",", row_sep: "\r\n").zip(@expected) do |row, exp|
|
45
|
+
assert_equal(exp, row)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_open_and_close
|
50
|
+
csv = FastCSV.open(@path, "r+", col_sep: ",", row_sep: "\r\n")
|
51
|
+
assert_not_nil(csv)
|
52
|
+
assert_instance_of(FastCSV, csv)
|
53
|
+
assert_equal(false, csv.closed?)
|
54
|
+
csv.close
|
55
|
+
assert(csv.closed?)
|
56
|
+
|
57
|
+
ret = FastCSV.open(@path) do |new_csv|
|
58
|
+
csv = new_csv
|
59
|
+
assert_instance_of(FastCSV, new_csv)
|
60
|
+
"Return value."
|
61
|
+
end
|
62
|
+
assert(csv.closed?)
|
63
|
+
assert_equal("Return value.", ret)
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_parse
|
67
|
+
data = File.binread(@path)
|
68
|
+
assert_equal( @expected,
|
69
|
+
FastCSV.parse(data, col_sep: ",", row_sep: "\r\n") )
|
70
|
+
|
71
|
+
FastCSV.parse(data, col_sep: ",", row_sep: "\r\n") do |row|
|
72
|
+
assert_equal(@expected.shift, row)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_parse_line
|
77
|
+
row = FastCSV.parse_line("1,2,3", col_sep: ",")
|
78
|
+
assert_not_nil(row)
|
79
|
+
assert_instance_of(Array, row)
|
80
|
+
assert_equal(%w{1 2 3}, row)
|
81
|
+
|
82
|
+
# shortcut interface
|
83
|
+
row = "1,2,3".parse_csv(col_sep: ",")
|
84
|
+
assert_not_nil(row)
|
85
|
+
assert_instance_of(Array, row)
|
86
|
+
assert_equal(%w{1 2 3}, row)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_parse_line_with_empty_lines
|
90
|
+
assert_equal(nil, FastCSV.parse_line("")) # to signal eof
|
91
|
+
assert_equal(Array.new, FastCSV.parse_line("\n1,2,3"))
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_read_and_readlines
|
95
|
+
assert_equal( @expected,
|
96
|
+
FastCSV.read(@path, col_sep: ",", row_sep: "\r\n") )
|
97
|
+
assert_equal( @expected,
|
98
|
+
FastCSV.readlines(@path, col_sep: ",", row_sep: "\r\n") )
|
99
|
+
|
100
|
+
|
101
|
+
data = FastCSV.open(@path, col_sep: ",", row_sep: "\r\n") do |csv|
|
102
|
+
csv.read
|
103
|
+
end
|
104
|
+
assert_equal(@expected, data)
|
105
|
+
data = FastCSV.open(@path, col_sep: ",", row_sep: "\r\n") do |csv|
|
106
|
+
csv.readlines
|
107
|
+
end
|
108
|
+
assert_equal(@expected, data)
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_table
|
112
|
+
table = FastCSV.table(@path, col_sep: ",", row_sep: "\r\n")
|
113
|
+
assert_instance_of(FastCSV::Table, table)
|
114
|
+
assert_equal([[:"1", :"2", :"3"], [4, 5, nil]], table.to_a)
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_shift # aliased as gets() and readline()
|
118
|
+
FastCSV.open(@path, "rb+", col_sep: ",", row_sep: "\r\n") do |csv|
|
119
|
+
assert_equal(@expected.shift, csv.shift)
|
120
|
+
assert_equal(@expected.shift, csv.shift)
|
121
|
+
assert_equal(nil, csv.shift)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_enumerators_are_supported
|
126
|
+
FastCSV.open(@path, col_sep: ",", row_sep: "\r\n") do |csv|
|
127
|
+
enum = csv.each
|
128
|
+
assert_instance_of(Enumerator, enum)
|
129
|
+
assert_equal(@expected.shift, enum.next)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
### Test Write Interface ###
|
134
|
+
|
135
|
+
def test_generate
|
136
|
+
str = FastCSV.generate do |csv| # default empty String
|
137
|
+
assert_instance_of(FastCSV, csv)
|
138
|
+
assert_equal(csv, csv << [1, 2, 3])
|
139
|
+
assert_equal(csv, csv << [4, nil, 5])
|
140
|
+
end
|
141
|
+
assert_not_nil(str)
|
142
|
+
assert_instance_of(String, str)
|
143
|
+
assert_equal("1,2,3\n4,,5\n", str)
|
144
|
+
|
145
|
+
FastCSV.generate(str) do |csv| # appending to a String
|
146
|
+
assert_equal(csv, csv << ["last", %Q{"row"}])
|
147
|
+
end
|
148
|
+
assert_equal(%Q{1,2,3\n4,,5\nlast,"""row"""\n}, str)
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_generate_line
|
152
|
+
line = FastCSV.generate_line(%w{1 2 3}, col_sep: ",")
|
153
|
+
assert_not_nil(line)
|
154
|
+
assert_instance_of(String, line)
|
155
|
+
assert_equal("1,2,3\n", line)
|
156
|
+
|
157
|
+
# shortcut interface
|
158
|
+
line = %w{1 2 3}.to_csv(col_sep: ",")
|
159
|
+
assert_not_nil(line)
|
160
|
+
assert_instance_of(String, line)
|
161
|
+
assert_equal("1,2,3\n", line)
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_write_header_detection
|
165
|
+
File.unlink(@path)
|
166
|
+
|
167
|
+
headers = %w{a b c}
|
168
|
+
FastCSV.open(@path, "w", headers: true) do |csv|
|
169
|
+
csv << headers
|
170
|
+
csv << %w{1 2 3}
|
171
|
+
assert_equal(headers, csv.instance_variable_get(:@headers))
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def test_write_lineno
|
176
|
+
File.unlink(@path)
|
177
|
+
|
178
|
+
FastCSV.open(@path, "w") do |csv|
|
179
|
+
lines = 20
|
180
|
+
lines.times { csv << %w{a b c} }
|
181
|
+
assert_equal(lines, csv.lineno)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_write_hash
|
186
|
+
File.unlink(@path)
|
187
|
+
|
188
|
+
lines = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}]
|
189
|
+
FastCSV.open( @path, "wb", headers: true,
|
190
|
+
header_converters: :symbol ) do |csv|
|
191
|
+
csv << lines.first.keys
|
192
|
+
lines.each { |line| csv << line }
|
193
|
+
end
|
194
|
+
FastCSV.open( @path, "rb", headers: true,
|
195
|
+
converters: :all,
|
196
|
+
header_converters: :symbol ) do |csv|
|
197
|
+
csv.each { |line| assert_equal(lines.shift, line.to_hash) }
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_write_hash_with_string_keys
|
202
|
+
File.unlink(@path)
|
203
|
+
|
204
|
+
lines = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}]
|
205
|
+
FastCSV.open( @path, "wb", headers: true ) do |csv|
|
206
|
+
csv << lines.first.keys
|
207
|
+
lines.each { |line| csv << line }
|
208
|
+
end
|
209
|
+
FastCSV.open( @path, "rb", headers: true ) do |csv|
|
210
|
+
csv.each do |line|
|
211
|
+
csv.headers.each_with_index do |header, h|
|
212
|
+
keys = line.to_hash.keys
|
213
|
+
assert_instance_of(String, keys[h])
|
214
|
+
assert_same(header, keys[h])
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def test_write_hash_with_headers_array
|
221
|
+
File.unlink(@path)
|
222
|
+
|
223
|
+
lines = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}]
|
224
|
+
FastCSV.open(@path, "wb", headers: [:b, :a, :c]) do |csv|
|
225
|
+
lines.each { |line| csv << line }
|
226
|
+
end
|
227
|
+
|
228
|
+
# test writing fields in the correct order
|
229
|
+
File.open(@path, "rb") do |f|
|
230
|
+
assert_equal("2,1,3", f.gets.strip)
|
231
|
+
assert_equal("5,4,6", f.gets.strip)
|
232
|
+
end
|
233
|
+
|
234
|
+
# test reading FastCSV with headers
|
235
|
+
FastCSV.open( @path, "rb", headers: [:b, :a, :c],
|
236
|
+
converters: :all ) do |csv|
|
237
|
+
csv.each { |line| assert_equal(lines.shift, line.to_hash) }
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def test_write_hash_with_headers_string
|
242
|
+
File.unlink(@path)
|
243
|
+
|
244
|
+
lines = [{"a" => 1, "b" => 2, "c" => 3}, {"a" => 4, "b" => 5, "c" => 6}]
|
245
|
+
FastCSV.open(@path, "wb", headers: "b,a,c", col_sep: ",") do |csv|
|
246
|
+
lines.each { |line| csv << line }
|
247
|
+
end
|
248
|
+
|
249
|
+
# test writing fields in the correct order
|
250
|
+
File.open(@path, "rb") do |f|
|
251
|
+
assert_equal("2,1,3", f.gets.strip)
|
252
|
+
assert_equal("5,4,6", f.gets.strip)
|
253
|
+
end
|
254
|
+
|
255
|
+
# test reading FastCSV with headers
|
256
|
+
FastCSV.open( @path, "rb", headers: "b,a,c",
|
257
|
+
col_sep: ",",
|
258
|
+
converters: :all ) do |csv|
|
259
|
+
csv.each { |line| assert_equal(lines.shift, line.to_hash) }
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_write_headers
|
264
|
+
File.unlink(@path)
|
265
|
+
|
266
|
+
lines = [{"a" => 1, "b" => 2, "c" => 3}, {"a" => 4, "b" => 5, "c" => 6}]
|
267
|
+
FastCSV.open( @path, "wb", headers: "b,a,c",
|
268
|
+
write_headers: true,
|
269
|
+
col_sep: "," ) do |csv|
|
270
|
+
lines.each { |line| csv << line }
|
271
|
+
end
|
272
|
+
|
273
|
+
# test writing fields in the correct order
|
274
|
+
File.open(@path, "rb") do |f|
|
275
|
+
assert_equal("b,a,c", f.gets.strip)
|
276
|
+
assert_equal("2,1,3", f.gets.strip)
|
277
|
+
assert_equal("5,4,6", f.gets.strip)
|
278
|
+
end
|
279
|
+
|
280
|
+
# test reading FastCSV with headers
|
281
|
+
FastCSV.open( @path, "rb", headers: true,
|
282
|
+
col_sep: ",",
|
283
|
+
converters: :all ) do |csv|
|
284
|
+
csv.each { |line| assert_equal(lines.shift, line.to_hash) }
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def test_append # aliased add_row() and puts()
|
289
|
+
File.unlink(@path)
|
290
|
+
|
291
|
+
FastCSV.open(@path, "wb", col_sep: ",", row_sep: "\r\n") do |csv|
|
292
|
+
@expected.each { |row| csv << row }
|
293
|
+
end
|
294
|
+
|
295
|
+
test_shift
|
296
|
+
|
297
|
+
# same thing using FastCSV::Row objects
|
298
|
+
File.unlink(@path)
|
299
|
+
|
300
|
+
FastCSV.open(@path, "wb", col_sep: ",", row_sep: "\r\n") do |csv|
|
301
|
+
@expected.each { |row| csv << FastCSV::Row.new(Array.new, row) }
|
302
|
+
end
|
303
|
+
|
304
|
+
test_shift
|
305
|
+
end
|
306
|
+
|
307
|
+
### Test Read and Write Interface ###
|
308
|
+
|
309
|
+
def test_filter
|
310
|
+
assert_respond_to(FastCSV, :filter)
|
311
|
+
|
312
|
+
expected = [[1, 2, 3], [4, 5]]
|
313
|
+
FastCSV.filter( "1,2,3\n4,5\n", (result = String.new),
|
314
|
+
in_col_sep: ",", out_col_sep: ",",
|
315
|
+
converters: :all ) do |row|
|
316
|
+
assert_equal(row, expected.shift)
|
317
|
+
row.map! { |n| n * 2 }
|
318
|
+
row << "Added\r"
|
319
|
+
end
|
320
|
+
assert_equal("2,4,6,\"Added\r\"\n8,10,\"Added\r\"\n", result)
|
321
|
+
end
|
322
|
+
|
323
|
+
def test_instance
|
324
|
+
csv = String.new
|
325
|
+
|
326
|
+
first = nil
|
327
|
+
assert_nothing_raised(Exception) do
|
328
|
+
first = FastCSV.instance(csv, col_sep: ",")
|
329
|
+
first << %w{a b c}
|
330
|
+
end
|
331
|
+
|
332
|
+
assert_equal("a,b,c\n", csv)
|
333
|
+
|
334
|
+
second = nil
|
335
|
+
assert_nothing_raised(Exception) do
|
336
|
+
second = FastCSV.instance(csv, col_sep: ",")
|
337
|
+
second << [1, 2, 3]
|
338
|
+
end
|
339
|
+
|
340
|
+
assert_equal(first.object_id, second.object_id)
|
341
|
+
assert_equal("a,b,c\n1,2,3\n", csv)
|
342
|
+
|
343
|
+
# shortcuts
|
344
|
+
assert_equal(STDOUT, FastCSV.instance.instance_eval { @io })
|
345
|
+
assert_equal(STDOUT, FastCSV { |new_csv| new_csv.instance_eval { @io } })
|
346
|
+
end
|
347
|
+
|
348
|
+
def test_options_are_not_modified
|
349
|
+
opt = {}.freeze
|
350
|
+
assert_nothing_raised { FastCSV.foreach(@path, opt) }
|
351
|
+
assert_nothing_raised { FastCSV.open(@path, opt){} }
|
352
|
+
assert_nothing_raised { FastCSV.parse("", opt) }
|
353
|
+
assert_nothing_raised { FastCSV.parse_line("", opt) }
|
354
|
+
assert_nothing_raised { FastCSV.read(@path, opt) }
|
355
|
+
assert_nothing_raised { FastCSV.readlines(@path, opt) }
|
356
|
+
assert_nothing_raised { FastCSV.table(@path, opt) }
|
357
|
+
assert_nothing_raised { FastCSV.generate(opt){} }
|
358
|
+
assert_nothing_raised { FastCSV.generate_line([], opt) }
|
359
|
+
assert_nothing_raised { FastCSV.filter("", "", opt){} }
|
360
|
+
assert_nothing_raised { FastCSV.instance("", opt) }
|
361
|
+
end
|
362
|
+
end
|
@@ -0,0 +1,349 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
# tc_row.rb
|
5
|
+
#
|
6
|
+
# Created by James Edward Gray II on 2005-10-31.
|
7
|
+
# Copyright 2005 James Edward Gray II. You can redistribute or modify this code
|
8
|
+
# under the terms of Ruby's license.
|
9
|
+
|
10
|
+
require_relative "base"
|
11
|
+
|
12
|
+
class TestCSV::Row < TestCSV
|
13
|
+
extend DifferentOFS
|
14
|
+
|
15
|
+
def setup
|
16
|
+
super
|
17
|
+
@row = FastCSV::Row.new(%w{A B C A A}, [1, 2, 3, 4])
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_initialize
|
21
|
+
# basic
|
22
|
+
row = FastCSV::Row.new(%w{A B C}, [1, 2, 3])
|
23
|
+
assert_not_nil(row)
|
24
|
+
assert_instance_of(FastCSV::Row, row)
|
25
|
+
assert_equal([["A", 1], ["B", 2], ["C", 3]], row.to_a)
|
26
|
+
|
27
|
+
# missing headers
|
28
|
+
row = FastCSV::Row.new(%w{A}, [1, 2, 3])
|
29
|
+
assert_not_nil(row)
|
30
|
+
assert_instance_of(FastCSV::Row, row)
|
31
|
+
assert_equal([["A", 1], [nil, 2], [nil, 3]], row.to_a)
|
32
|
+
|
33
|
+
# missing fields
|
34
|
+
row = FastCSV::Row.new(%w{A B C}, [1, 2])
|
35
|
+
assert_not_nil(row)
|
36
|
+
assert_instance_of(FastCSV::Row, row)
|
37
|
+
assert_equal([["A", 1], ["B", 2], ["C", nil]], row.to_a)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_row_type
|
41
|
+
# field rows
|
42
|
+
row = FastCSV::Row.new(%w{A B C}, [1, 2, 3]) # implicit
|
43
|
+
assert(!row.header_row?)
|
44
|
+
assert(row.field_row?)
|
45
|
+
row = FastCSV::Row.new(%w{A B C}, [1, 2, 3], false) # explicit
|
46
|
+
assert(!row.header_row?)
|
47
|
+
assert(row.field_row?)
|
48
|
+
|
49
|
+
# header row
|
50
|
+
row = FastCSV::Row.new(%w{A B C}, [1, 2, 3], true)
|
51
|
+
assert(row.header_row?)
|
52
|
+
assert(!row.field_row?)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_headers
|
56
|
+
assert_equal(%w{A B C A A}, @row.headers)
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_field
|
60
|
+
# by name
|
61
|
+
assert_equal(2, @row.field("B"))
|
62
|
+
assert_equal(2, @row["B"]) # alias
|
63
|
+
|
64
|
+
# by index
|
65
|
+
assert_equal(3, @row.field(2))
|
66
|
+
|
67
|
+
# missing
|
68
|
+
assert_nil(@row.field("Missing"))
|
69
|
+
assert_nil(@row.field(10))
|
70
|
+
|
71
|
+
# minimum index
|
72
|
+
assert_equal(1, @row.field("A"))
|
73
|
+
assert_equal(1, @row.field("A", 0))
|
74
|
+
assert_equal(4, @row.field("A", 1))
|
75
|
+
assert_equal(4, @row.field("A", 2))
|
76
|
+
assert_equal(4, @row.field("A", 3))
|
77
|
+
assert_equal(nil, @row.field("A", 4))
|
78
|
+
assert_equal(nil, @row.field("A", 5))
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_fetch
|
82
|
+
# only by name
|
83
|
+
assert_equal(2, @row.fetch('B'))
|
84
|
+
|
85
|
+
# missing header raises KeyError
|
86
|
+
assert_raise KeyError do
|
87
|
+
@row.fetch('foo')
|
88
|
+
end
|
89
|
+
|
90
|
+
# missing header yields itself to block
|
91
|
+
assert_equal 'bar', @row.fetch('foo') { |header|
|
92
|
+
header == 'foo' ? 'bar' : false }
|
93
|
+
|
94
|
+
# missing header returns the given default value
|
95
|
+
assert_equal 'bar', @row.fetch('foo', 'bar')
|
96
|
+
|
97
|
+
# more than one vararg raises ArgumentError
|
98
|
+
assert_raise ArgumentError do
|
99
|
+
@row.fetch('foo', 'bar', 'baz')
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_has_key?
|
104
|
+
assert_equal(true, @row.has_key?('B'))
|
105
|
+
assert_equal(false, @row.has_key?('foo'))
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_set_field
|
109
|
+
# set field by name
|
110
|
+
assert_equal(100, @row["A"] = 100)
|
111
|
+
|
112
|
+
# set field by index
|
113
|
+
assert_equal(300, @row[3] = 300)
|
114
|
+
|
115
|
+
# set field by name and minimum index
|
116
|
+
assert_equal([:a, :b, :c], @row["A", 4] = [:a, :b, :c])
|
117
|
+
|
118
|
+
# verify the changes
|
119
|
+
assert_equal( [ ["A", 100],
|
120
|
+
["B", 2],
|
121
|
+
["C", 3],
|
122
|
+
["A", 300],
|
123
|
+
["A", [:a, :b, :c]] ], @row.to_a )
|
124
|
+
|
125
|
+
# assigning an index past the end
|
126
|
+
assert_equal("End", @row[10] = "End")
|
127
|
+
assert_equal( [ ["A", 100],
|
128
|
+
["B", 2],
|
129
|
+
["C", 3],
|
130
|
+
["A", 300],
|
131
|
+
["A", [:a, :b, :c]],
|
132
|
+
[nil, nil],
|
133
|
+
[nil, nil],
|
134
|
+
[nil, nil],
|
135
|
+
[nil, nil],
|
136
|
+
[nil, nil],
|
137
|
+
[nil, "End"] ], @row.to_a )
|
138
|
+
|
139
|
+
# assigning a new field by header
|
140
|
+
assert_equal("New", @row[:new] = "New")
|
141
|
+
assert_equal( [ ["A", 100],
|
142
|
+
["B", 2],
|
143
|
+
["C", 3],
|
144
|
+
["A", 300],
|
145
|
+
["A", [:a, :b, :c]],
|
146
|
+
[nil, nil],
|
147
|
+
[nil, nil],
|
148
|
+
[nil, nil],
|
149
|
+
[nil, nil],
|
150
|
+
[nil, nil],
|
151
|
+
[nil, "End"],
|
152
|
+
[:new, "New"] ], @row.to_a )
|
153
|
+
end
|
154
|
+
|
155
|
+
def test_append
|
156
|
+
# add a value
|
157
|
+
assert_equal(@row, @row << "Value")
|
158
|
+
assert_equal( [ ["A", 1],
|
159
|
+
["B", 2],
|
160
|
+
["C", 3],
|
161
|
+
["A", 4],
|
162
|
+
["A", nil],
|
163
|
+
[nil, "Value"] ], @row.to_a )
|
164
|
+
|
165
|
+
# add a pair
|
166
|
+
assert_equal(@row, @row << %w{Header Field})
|
167
|
+
assert_equal( [ ["A", 1],
|
168
|
+
["B", 2],
|
169
|
+
["C", 3],
|
170
|
+
["A", 4],
|
171
|
+
["A", nil],
|
172
|
+
[nil, "Value"],
|
173
|
+
%w{Header Field} ], @row.to_a )
|
174
|
+
|
175
|
+
# a pair with Hash syntax
|
176
|
+
assert_equal(@row, @row << {key: :value})
|
177
|
+
assert_equal( [ ["A", 1],
|
178
|
+
["B", 2],
|
179
|
+
["C", 3],
|
180
|
+
["A", 4],
|
181
|
+
["A", nil],
|
182
|
+
[nil, "Value"],
|
183
|
+
%w{Header Field},
|
184
|
+
[:key, :value] ], @row.to_a )
|
185
|
+
|
186
|
+
# multiple fields at once
|
187
|
+
assert_equal(@row, @row.push(100, 200, [:last, 300]))
|
188
|
+
assert_equal( [ ["A", 1],
|
189
|
+
["B", 2],
|
190
|
+
["C", 3],
|
191
|
+
["A", 4],
|
192
|
+
["A", nil],
|
193
|
+
[nil, "Value"],
|
194
|
+
%w{Header Field},
|
195
|
+
[:key, :value],
|
196
|
+
[nil, 100],
|
197
|
+
[nil, 200],
|
198
|
+
[:last, 300] ], @row.to_a )
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_delete
|
202
|
+
# by index
|
203
|
+
assert_equal(["B", 2], @row.delete(1))
|
204
|
+
|
205
|
+
# by header
|
206
|
+
assert_equal(["C", 3], @row.delete("C"))
|
207
|
+
|
208
|
+
# using a block
|
209
|
+
assert_equal(@row, @row.delete_if { |h, f| h == "A" and not f.nil? })
|
210
|
+
assert_equal([["A", nil]], @row.to_a)
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_fields
|
214
|
+
# all fields
|
215
|
+
assert_equal([1, 2, 3, 4, nil], @row.fields)
|
216
|
+
|
217
|
+
# by header
|
218
|
+
assert_equal([1, 3], @row.fields("A", "C"))
|
219
|
+
|
220
|
+
# by index
|
221
|
+
assert_equal([2, 3, nil], @row.fields(1, 2, 10))
|
222
|
+
|
223
|
+
# by both
|
224
|
+
assert_equal([2, 3, 4], @row.fields("B", "C", 3))
|
225
|
+
|
226
|
+
# with minimum indices
|
227
|
+
assert_equal([2, 3, 4], @row.fields("B", "C", ["A", 3]))
|
228
|
+
|
229
|
+
# by header range
|
230
|
+
assert_equal([2, 3], @row.values_at("B".."C"))
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_index
|
234
|
+
# basic usage
|
235
|
+
assert_equal(0, @row.index("A"))
|
236
|
+
assert_equal(1, @row.index("B"))
|
237
|
+
assert_equal(2, @row.index("C"))
|
238
|
+
assert_equal(nil, @row.index("Z"))
|
239
|
+
|
240
|
+
# with minimum index
|
241
|
+
assert_equal(0, @row.index("A"))
|
242
|
+
assert_equal(0, @row.index("A", 0))
|
243
|
+
assert_equal(3, @row.index("A", 1))
|
244
|
+
assert_equal(3, @row.index("A", 2))
|
245
|
+
assert_equal(3, @row.index("A", 3))
|
246
|
+
assert_equal(4, @row.index("A", 4))
|
247
|
+
assert_equal(nil, @row.index("A", 5))
|
248
|
+
end
|
249
|
+
|
250
|
+
def test_queries
|
251
|
+
# headers
|
252
|
+
assert(@row.header?("A"))
|
253
|
+
assert(@row.header?("C"))
|
254
|
+
assert(!@row.header?("Z"))
|
255
|
+
assert(@row.include?("A")) # alias
|
256
|
+
|
257
|
+
# fields
|
258
|
+
assert(@row.field?(4))
|
259
|
+
assert(@row.field?(nil))
|
260
|
+
assert(!@row.field?(10))
|
261
|
+
end
|
262
|
+
|
263
|
+
def test_each
|
264
|
+
# array style
|
265
|
+
ary = @row.to_a
|
266
|
+
@row.each do |pair|
|
267
|
+
assert_equal(ary.first.first, pair.first)
|
268
|
+
assert_equal(ary.shift.last, pair.last)
|
269
|
+
end
|
270
|
+
|
271
|
+
# hash style
|
272
|
+
ary = @row.to_a
|
273
|
+
@row.each do |header, field|
|
274
|
+
assert_equal(ary.first.first, header)
|
275
|
+
assert_equal(ary.shift.last, field)
|
276
|
+
end
|
277
|
+
|
278
|
+
# verify that we can chain the call
|
279
|
+
assert_equal(@row, @row.each { })
|
280
|
+
end
|
281
|
+
|
282
|
+
def test_enumerable
|
283
|
+
assert_equal( [["A", 1], ["A", 4], ["A", nil]],
|
284
|
+
@row.select { |pair| pair.first == "A" } )
|
285
|
+
|
286
|
+
assert_equal(10, @row.inject(0) { |sum, (_, n)| sum + (n || 0) })
|
287
|
+
end
|
288
|
+
|
289
|
+
def test_to_a
|
290
|
+
row = FastCSV::Row.new(%w{A B C}, [1, 2, 3]).to_a
|
291
|
+
assert_instance_of(Array, row)
|
292
|
+
row.each do |pair|
|
293
|
+
assert_instance_of(Array, pair)
|
294
|
+
assert_equal(2, pair.size)
|
295
|
+
end
|
296
|
+
assert_equal([["A", 1], ["B", 2], ["C", 3]], row)
|
297
|
+
end
|
298
|
+
|
299
|
+
def test_to_hash
|
300
|
+
hash = @row.to_hash
|
301
|
+
assert_equal({"A" => nil, "B" => 2, "C" => 3}, hash)
|
302
|
+
hash.keys.each_with_index do |string_key, h|
|
303
|
+
assert_predicate(string_key, :frozen?)
|
304
|
+
assert_same(string_key, @row.headers[h])
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
def test_to_csv
|
309
|
+
# normal conversion
|
310
|
+
assert_equal("1,2,3,4,\n", @row.to_csv)
|
311
|
+
assert_equal("1,2,3,4,\n", @row.to_s) # alias
|
312
|
+
|
313
|
+
# with options
|
314
|
+
assert_equal( "1|2|3|4|\r\n",
|
315
|
+
@row.to_csv(col_sep: "|", row_sep: "\r\n") )
|
316
|
+
end
|
317
|
+
|
318
|
+
def test_array_delegation
|
319
|
+
assert(!@row.empty?, "Row was empty.")
|
320
|
+
|
321
|
+
assert_equal([@row.headers.size, @row.fields.size].max, @row.size)
|
322
|
+
end
|
323
|
+
|
324
|
+
def test_inspect_shows_header_field_pairs
|
325
|
+
str = @row.inspect
|
326
|
+
@row.each do |header, field|
|
327
|
+
assert( str.include?("#{header.inspect}:#{field.inspect}"),
|
328
|
+
"Header field pair not found." )
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
def test_inspect_encoding_is_ascii_compatible
|
333
|
+
assert( Encoding.compatible?( Encoding.find("US-ASCII"),
|
334
|
+
@row.inspect.encoding ),
|
335
|
+
"inspect() was not ASCII compatible." )
|
336
|
+
end
|
337
|
+
|
338
|
+
def test_inspect_shows_symbol_headers_as_bare_attributes
|
339
|
+
str = FastCSV::Row.new(@row.headers.map { |h| h.to_sym }, @row.fields).inspect
|
340
|
+
@row.each do |header, field|
|
341
|
+
assert( str.include?("#{header}:#{field.inspect}"),
|
342
|
+
"Header field pair not found." )
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
def test_can_be_compared_with_other_classes
|
347
|
+
assert(FastCSV::Row.new([ ], [ ]) != nil, "The row was nil")
|
348
|
+
end
|
349
|
+
end
|