fastcsv 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|