fastcsv 0.0.4 → 0.0.5
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 +1 -0
- data/Gemfile +1 -1
- data/LICENSE +1 -1
- data/README.md +12 -17
- data/TESTS.md +4 -5
- data/ext/fastcsv/fastcsv.c +2494 -153
- data/ext/fastcsv/fastcsv.rl +43 -8
- data/fastcsv.gemspec +5 -6
- data/lib/fastcsv.rb +1 -1
- data/spec/fastcsv_spec.rb +0 -1
- data/test/csv/test_csv_parsing.rb +10 -10
- data/test/csv/test_encodings.rb +23 -23
- data/test/csv/test_features.rb +17 -17
- data/test/csv/test_headers.rb +14 -14
- data/test/csv/test_interface.rb +39 -39
- metadata +9 -11
data/ext/fastcsv/fastcsv.rl
CHANGED
@@ -22,6 +22,9 @@ if (enc2 != NULL) { \
|
|
22
22
|
#define FREE \
|
23
23
|
if (buf != NULL) { \
|
24
24
|
free(buf); \
|
25
|
+
} \
|
26
|
+
if (row_sep != NULL) { \
|
27
|
+
free(row_sep); \
|
25
28
|
}
|
26
29
|
|
27
30
|
static VALUE cClass, cParser, eError;
|
@@ -96,9 +99,23 @@ typedef struct {
|
|
96
99
|
|
97
100
|
action mark_row {
|
98
101
|
d->start = p;
|
102
|
+
|
103
|
+
if (len_row_sep) {
|
104
|
+
if (p - mark_row_sep != len_row_sep || row_sep[0] != *mark_row_sep || (len_row_sep == 2 && row_sep[1] != *(mark_row_sep + 1))) {
|
105
|
+
FREE;
|
106
|
+
|
107
|
+
rb_raise(eError, "Unquoted fields do not allow \\r or \\n (line %d).", curline - 1);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
else {
|
111
|
+
len_row_sep = p - mark_row_sep;
|
112
|
+
row_sep = ALLOC_N(char, len_row_sep);
|
113
|
+
memcpy(row_sep, mark_row_sep, len_row_sep);
|
114
|
+
}
|
99
115
|
}
|
100
116
|
|
101
117
|
action new_row {
|
118
|
+
mark_row_sep = p;
|
102
119
|
curline++;
|
103
120
|
|
104
121
|
if (d->start == 0 || p == d->start) {
|
@@ -118,7 +135,7 @@ typedef struct {
|
|
118
135
|
}
|
119
136
|
|
120
137
|
action last_row {
|
121
|
-
if (d->start == 0 || p == d->start) {
|
138
|
+
if (d->start == 0 || p == d->start) { // same as new_row
|
122
139
|
rb_ivar_set(self, s_row, rb_str_new2(""));
|
123
140
|
}
|
124
141
|
else if (p > d->start) {
|
@@ -135,8 +152,8 @@ typedef struct {
|
|
135
152
|
}
|
136
153
|
|
137
154
|
EOF = 0;
|
138
|
-
quote_char =
|
139
|
-
col_sep =
|
155
|
+
quote_char = any when { fc == quote_char };
|
156
|
+
col_sep = any when { fc == col_sep } >new_field;
|
140
157
|
row_sep = ('\r' '\n'? | '\n');
|
141
158
|
unquoted = (any* -- quote_char -- col_sep -- row_sep - EOF) %read_unquoted;
|
142
159
|
quoted = quote_char >open_quote (any - quote_char - EOF | quote_char quote_char | row_sep)* %read_quoted quote_char >close_quote;
|
@@ -184,18 +201,18 @@ static void rb_io_ext_int_to_encs(rb_encoding *ext, rb_encoding *intern, rb_enco
|
|
184
201
|
|
185
202
|
static VALUE raw_parse(int argc, VALUE *argv, VALUE self) {
|
186
203
|
int cs, act, have = 0, curline = 1, io = 0;
|
187
|
-
char *ts = 0, *te = 0, *buf = 0, *eof = 0;
|
204
|
+
char *ts = 0, *te = 0, *buf = 0, *eof = 0, *mark_row_sep = 0, *row_sep = 0;
|
188
205
|
|
189
206
|
VALUE port, opts, r_encoding;
|
190
207
|
VALUE row = rb_ary_new(), field = Qnil, bufsize = Qnil;
|
191
|
-
int done = 0, unclosed_line = 0, buffer_size = 0, taint = 0;
|
208
|
+
int done = 0, unclosed_line = 0, buffer_size = 0, taint = 0, len_row_sep = 0;
|
192
209
|
rb_encoding *enc = NULL, *enc2 = NULL, *encoding = NULL;
|
193
210
|
|
194
211
|
Data *d;
|
195
212
|
Data_Get_Struct(self, Data, d);
|
196
213
|
|
197
214
|
VALUE option;
|
198
|
-
char quote_char = '"';
|
215
|
+
char quote_char = '"', col_sep = ',';
|
199
216
|
|
200
217
|
rb_scan_args(argc, argv, "11", &port, &opts);
|
201
218
|
taint = OBJ_TAINTED(port);
|
@@ -217,6 +234,22 @@ static VALUE raw_parse(int argc, VALUE *argv, VALUE self) {
|
|
217
234
|
rb_raise(rb_eArgError, "options has to be a Hash or nil");
|
218
235
|
}
|
219
236
|
|
237
|
+
option = rb_hash_aref(opts, ID2SYM(rb_intern("quote_char")));
|
238
|
+
if (TYPE(option) == T_STRING && RSTRING_LEN(option) == 1) {
|
239
|
+
quote_char = *StringValueCStr(option);
|
240
|
+
}
|
241
|
+
else if (!NIL_P(option)) {
|
242
|
+
rb_raise(rb_eArgError, ":quote_char has to be a single character String");
|
243
|
+
}
|
244
|
+
|
245
|
+
option = rb_hash_aref(opts, ID2SYM(rb_intern("col_sep")));
|
246
|
+
if (TYPE(option) == T_STRING && RSTRING_LEN(option) == 1) {
|
247
|
+
col_sep = *StringValueCStr(option);
|
248
|
+
}
|
249
|
+
else if (!NIL_P(option)) {
|
250
|
+
rb_raise(rb_eArgError, ":col_sep has to be a single character String");
|
251
|
+
}
|
252
|
+
|
220
253
|
// @see rb_io_extract_modeenc
|
221
254
|
/* Set to defaults */
|
222
255
|
rb_io_ext_int_to_encs(NULL, NULL, &enc, &enc2, 0);
|
@@ -351,7 +384,7 @@ static VALUE raw_parse(int argc, VALUE *argv, VALUE self) {
|
|
351
384
|
while (!done) {
|
352
385
|
VALUE str;
|
353
386
|
char *p, *pe;
|
354
|
-
int len, space = buffer_size - have, tokstart_diff, tokend_diff, start_diff;
|
387
|
+
int len, space = buffer_size - have, tokstart_diff, tokend_diff, start_diff, mark_row_sep_diff;
|
355
388
|
|
356
389
|
if (io) {
|
357
390
|
if (space == 0) {
|
@@ -359,6 +392,7 @@ static VALUE raw_parse(int argc, VALUE *argv, VALUE self) {
|
|
359
392
|
tokstart_diff = ts - buf;
|
360
393
|
tokend_diff = te - buf;
|
361
394
|
start_diff = d->start - buf;
|
395
|
+
mark_row_sep_diff = mark_row_sep - buf;
|
362
396
|
|
363
397
|
buffer_size += BUFSIZE;
|
364
398
|
REALLOC_N(buf, char, buffer_size);
|
@@ -368,6 +402,7 @@ static VALUE raw_parse(int argc, VALUE *argv, VALUE self) {
|
|
368
402
|
ts = buf + tokstart_diff;
|
369
403
|
te = buf + tokend_diff;
|
370
404
|
d->start = buf + start_diff;
|
405
|
+
mark_row_sep = buf + mark_row_sep_diff;
|
371
406
|
}
|
372
407
|
p = buf + have;
|
373
408
|
|
@@ -408,7 +443,7 @@ static VALUE raw_parse(int argc, VALUE *argv, VALUE self) {
|
|
408
443
|
%% write exec;
|
409
444
|
|
410
445
|
if (done && cs < raw_parse_first_final) {
|
411
|
-
if (d->start == 0 || p == d->start) {
|
446
|
+
if (d->start == 0 || p == d->start) { // same as new_row
|
412
447
|
rb_ivar_set(self, s_row, rb_str_new2(""));
|
413
448
|
}
|
414
449
|
else if (p > d->start) {
|
data/fastcsv.gemspec
CHANGED
@@ -2,12 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "fastcsv"
|
5
|
-
s.version = '0.0.
|
5
|
+
s.version = '0.0.5'
|
6
6
|
s.platform = Gem::Platform::RUBY
|
7
|
-
s.authors = ["
|
8
|
-
s.
|
9
|
-
s.
|
10
|
-
s.summary = %q{A fast Ragel-based CSV parser}
|
7
|
+
s.authors = ["James McKinney"]
|
8
|
+
s.homepage = "https://github.com/jpmckinney/fastcsv"
|
9
|
+
s.summary = %q{A fast Ragel-based CSV parser, compatible with Ruby's CSV}
|
11
10
|
s.license = 'MIT'
|
12
11
|
|
13
12
|
s.files = `git ls-files`.split("\n")
|
@@ -17,7 +16,7 @@ Gem::Specification.new do |s|
|
|
17
16
|
s.extensions = ["ext/fastcsv/extconf.rb"]
|
18
17
|
|
19
18
|
s.add_development_dependency('coveralls')
|
20
|
-
s.add_development_dependency('json', '~> 1.
|
19
|
+
s.add_development_dependency('json', '~> 1.8') # to silence coveralls warning
|
21
20
|
s.add_development_dependency('rake')
|
22
21
|
s.add_development_dependency('rake-compiler')
|
23
22
|
s.add_development_dependency('rspec', '~> 3.1')
|
data/lib/fastcsv.rb
CHANGED
data/spec/fastcsv_spec.rb
CHANGED
@@ -147,7 +147,6 @@ RSpec.shared_examples 'a CSV parser' do
|
|
147
147
|
it 'should raise an error on mixed row separators' do
|
148
148
|
csv = "foo\rbar\nbaz\r\n"
|
149
149
|
expect{CSV.parse(csv)}.to raise_error(CSV::MalformedCSVError, 'Unquoted fields do not allow \r or \n (line 2).')
|
150
|
-
skip
|
151
150
|
expect{FastCSV.parse(csv)}.to raise_error(FastCSV::MalformedCSVError, 'Unquoted fields do not allow \r or \n (line 2).')
|
152
151
|
end
|
153
152
|
|
@@ -160,16 +160,16 @@ class TestCSV::Parsing < TestCSV
|
|
160
160
|
assert_equal(6, lines.size)
|
161
161
|
assert_match(/\Aline,4/, lines.find { |l| l =~ /some\rjunk/ })
|
162
162
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
163
|
+
csv = FastCSV.new(bad_data)
|
164
|
+
begin
|
165
|
+
loop do
|
166
|
+
assert_not_nil(csv.shift)
|
167
|
+
assert_send([csv.lineno, :<, 5]) # FIXME 4
|
168
|
+
end
|
169
|
+
rescue FastCSV::MalformedCSVError
|
170
|
+
assert_equal( "Unquoted fields do not allow \\r or \\n (line 4).",
|
171
|
+
$!.message )
|
172
|
+
end
|
173
173
|
|
174
174
|
assert_raise(FastCSV::MalformedCSVError) { FastCSV.parse_line('1,2,"3...') }
|
175
175
|
|
data/test/csv/test_encodings.rb
CHANGED
@@ -72,7 +72,7 @@ class TestCSV::Encodings < TestCSV
|
|
72
72
|
each_encoding do |encoding|
|
73
73
|
begin
|
74
74
|
assert_parses( [ %w[ abc def ],
|
75
|
-
%w[ ghi jkl ] ], encoding, col_sep: "
|
75
|
+
%w[ ghi jkl ] ], encoding, col_sep: "|" )
|
76
76
|
rescue Encoding::ConverterNotFoundError
|
77
77
|
fail("Failed to properly escape #{encoding.name}.")
|
78
78
|
end
|
@@ -112,8 +112,8 @@ class TestCSV::Encodings < TestCSV
|
|
112
112
|
def test_csv_chars_are_transcoded
|
113
113
|
encode_for_tests([%w[abc def]]) do |data|
|
114
114
|
%w[col_sep row_sep quote_char].each do |csv_char|
|
115
|
-
assert_equal( "
|
116
|
-
FastCSV.new(data, csv_char.to_sym => "
|
115
|
+
assert_equal( "|".encode(data.encoding),
|
116
|
+
FastCSV.new(data, csv_char.to_sym => "|").send(csv_char) )
|
117
117
|
end
|
118
118
|
end
|
119
119
|
end
|
@@ -221,15 +221,15 @@ class TestCSV::Encodings < TestCSV
|
|
221
221
|
each_encoding do |encoding|
|
222
222
|
# test generate_line with encoding hint
|
223
223
|
begin
|
224
|
-
csv = %w[abc d
|
225
|
-
to_csv(col_sep: "
|
224
|
+
csv = %w[abc d|ef].map { |f| f.encode(encoding) }.
|
225
|
+
to_csv(col_sep: "|", encoding: encoding.name)
|
226
226
|
rescue Encoding::ConverterNotFoundError
|
227
227
|
next
|
228
228
|
end
|
229
229
|
assert_equal(encoding, csv.encoding)
|
230
230
|
|
231
231
|
# test generate_line with encoding guessing from fields
|
232
|
-
csv = %w[abc d
|
232
|
+
csv = %w[abc d|ef].map { |f| f.encode(encoding) }.to_csv(col_sep: "|")
|
233
233
|
assert_equal(encoding, csv.encoding)
|
234
234
|
|
235
235
|
# writing to files
|
@@ -283,23 +283,23 @@ class TestCSV::Encodings < TestCSV
|
|
283
283
|
end unless encoding == __ENCODING__
|
284
284
|
rescue Encoding::ConverterNotFoundError
|
285
285
|
end
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
286
|
+
options[:encoding] = encoding.name
|
287
|
+
FastCSV.open(@temp_csv_path, options) do |csv|
|
288
|
+
csv.each_with_index do |row, i|
|
289
|
+
assert_equal(fields[i], row)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
options.delete(:encoding)
|
293
|
+
options[:external_encoding] = encoding.name
|
294
|
+
options[:internal_encoding] = __ENCODING__.name
|
295
|
+
begin
|
296
|
+
FastCSV.open(@temp_csv_path, options) do |csv|
|
297
|
+
csv.each_with_index do |row, i|
|
298
|
+
assert_equal(orig_fields[i], row)
|
299
|
+
end
|
300
|
+
end unless encoding == __ENCODING__
|
301
|
+
rescue Encoding::ConverterNotFoundError
|
302
|
+
end
|
303
303
|
end
|
304
304
|
|
305
305
|
def encode_ary(ary, encoding)
|
data/test/csv/test_features.rb
CHANGED
@@ -47,16 +47,16 @@ class TestCSV::Features < TestCSV
|
|
47
47
|
@csv = FastCSV.new(@sample_data)
|
48
48
|
end
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
50
|
+
def test_col_sep
|
51
|
+
[";", "\t"].each do |sep|
|
52
|
+
TEST_CASES.each do |test_case|
|
53
|
+
assert_equal( test_case.last.map { |t| t.tr(",", sep) unless t.nil? },
|
54
|
+
FastCSV.parse_line( test_case.first.tr(",", sep),
|
55
|
+
col_sep: sep ) )
|
56
|
+
end
|
57
|
+
end
|
58
|
+
assert_equal([",,,", nil], FastCSV.parse_line(",,,;", col_sep: ";"))
|
59
|
+
end
|
60
60
|
|
61
61
|
# def test_row_sep
|
62
62
|
# assert_raise(FastCSV::MalformedCSVError) do
|
@@ -66,13 +66,13 @@ class TestCSV::Features < TestCSV
|
|
66
66
|
# FastCSV.parse_line(%Q{1,2,"3\n",4,5\r\n}, row_sep: "\r\n"))
|
67
67
|
# end
|
68
68
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
69
|
+
def test_quote_char
|
70
|
+
TEST_CASES.each do |test_case|
|
71
|
+
assert_equal( test_case.last.map { |t| t.tr('"', "'") unless t.nil? },
|
72
|
+
FastCSV.parse_line( test_case.first.tr('"', "'"),
|
73
|
+
quote_char: "'" ) )
|
74
|
+
end
|
75
|
+
end
|
76
76
|
|
77
77
|
def test_csv_char_readers
|
78
78
|
%w[col_sep row_sep quote_char].each do |reader|
|
data/test/csv/test_headers.rb
CHANGED
@@ -131,20 +131,20 @@ class TestCSV::Headers < TestCSV
|
|
131
131
|
assert(!row.field_row?)
|
132
132
|
end
|
133
133
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
134
|
+
def test_csv_header_string_inherits_separators
|
135
|
+
# parse with custom col_sep
|
136
|
+
csv = nil
|
137
|
+
assert_nothing_raised(Exception) do
|
138
|
+
csv = FastCSV.parse( @data.tr(",", "|"), col_sep: "|",
|
139
|
+
headers: "my|new|headers" )
|
140
|
+
end
|
141
|
+
|
142
|
+
# verify headers were recognized
|
143
|
+
row = csv[0]
|
144
|
+
assert_not_nil(row)
|
145
|
+
assert_instance_of(FastCSV::Row, row)
|
146
|
+
assert_equal([%w{my first}, %w{new second}, %w{headers third}], row.to_a)
|
147
|
+
end
|
148
148
|
|
149
149
|
def test_return_headers
|
150
150
|
# activate headers and request they are returned
|
data/test/csv/test_interface.rb
CHANGED
@@ -20,8 +20,8 @@ class TestCSV::Interface < TestCSV
|
|
20
20
|
@path = @tempfile.path
|
21
21
|
|
22
22
|
File.open(@path, "wb") do |file|
|
23
|
-
file << "1
|
24
|
-
file << "4
|
23
|
+
file << "1\t2\t3\r\n"
|
24
|
+
file << "4\t5\r\n"
|
25
25
|
end
|
26
26
|
|
27
27
|
@expected = [%w{1 2 3}, %w{4 5}]
|
@@ -35,19 +35,19 @@ class TestCSV::Interface < TestCSV
|
|
35
35
|
### Test Read Interface ###
|
36
36
|
|
37
37
|
def test_foreach
|
38
|
-
FastCSV.foreach(@path, col_sep: "
|
38
|
+
FastCSV.foreach(@path, col_sep: "\t", row_sep: "\r\n") do |row|
|
39
39
|
assert_equal(@expected.shift, row)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
def test_foreach_enum
|
44
|
-
FastCSV.foreach(@path, col_sep: "
|
44
|
+
FastCSV.foreach(@path, col_sep: "\t", row_sep: "\r\n").zip(@expected) do |row, exp|
|
45
45
|
assert_equal(exp, row)
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
def test_open_and_close
|
50
|
-
csv = FastCSV.open(@path, "r+", col_sep: "
|
50
|
+
csv = FastCSV.open(@path, "r+", col_sep: "\t", row_sep: "\r\n")
|
51
51
|
assert_not_nil(csv)
|
52
52
|
assert_instance_of(FastCSV, csv)
|
53
53
|
assert_equal(false, csv.closed?)
|
@@ -66,21 +66,21 @@ class TestCSV::Interface < TestCSV
|
|
66
66
|
def test_parse
|
67
67
|
data = File.binread(@path)
|
68
68
|
assert_equal( @expected,
|
69
|
-
FastCSV.parse(data, col_sep: "
|
69
|
+
FastCSV.parse(data, col_sep: "\t", row_sep: "\r\n") )
|
70
70
|
|
71
|
-
FastCSV.parse(data, col_sep: "
|
71
|
+
FastCSV.parse(data, col_sep: "\t", row_sep: "\r\n") do |row|
|
72
72
|
assert_equal(@expected.shift, row)
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
76
|
def test_parse_line
|
77
|
-
row = FastCSV.parse_line("1
|
77
|
+
row = FastCSV.parse_line("1;2;3", col_sep: ";")
|
78
78
|
assert_not_nil(row)
|
79
79
|
assert_instance_of(Array, row)
|
80
80
|
assert_equal(%w{1 2 3}, row)
|
81
81
|
|
82
82
|
# shortcut interface
|
83
|
-
row = "1
|
83
|
+
row = "1;2;3".parse_csv(col_sep: ";")
|
84
84
|
assert_not_nil(row)
|
85
85
|
assert_instance_of(Array, row)
|
86
86
|
assert_equal(%w{1 2 3}, row)
|
@@ -93,29 +93,29 @@ class TestCSV::Interface < TestCSV
|
|
93
93
|
|
94
94
|
def test_read_and_readlines
|
95
95
|
assert_equal( @expected,
|
96
|
-
FastCSV.read(@path, col_sep: "
|
96
|
+
FastCSV.read(@path, col_sep: "\t", row_sep: "\r\n") )
|
97
97
|
assert_equal( @expected,
|
98
|
-
FastCSV.readlines(@path, col_sep: "
|
98
|
+
FastCSV.readlines(@path, col_sep: "\t", row_sep: "\r\n") )
|
99
99
|
|
100
100
|
|
101
|
-
data = FastCSV.open(@path, col_sep: "
|
101
|
+
data = FastCSV.open(@path, col_sep: "\t", row_sep: "\r\n") do |csv|
|
102
102
|
csv.read
|
103
103
|
end
|
104
104
|
assert_equal(@expected, data)
|
105
|
-
data = FastCSV.open(@path, col_sep: "
|
105
|
+
data = FastCSV.open(@path, col_sep: "\t", row_sep: "\r\n") do |csv|
|
106
106
|
csv.readlines
|
107
107
|
end
|
108
108
|
assert_equal(@expected, data)
|
109
109
|
end
|
110
110
|
|
111
111
|
def test_table
|
112
|
-
table = FastCSV.table(@path, col_sep: "
|
112
|
+
table = FastCSV.table(@path, col_sep: "\t", row_sep: "\r\n")
|
113
113
|
assert_instance_of(FastCSV::Table, table)
|
114
114
|
assert_equal([[:"1", :"2", :"3"], [4, 5, nil]], table.to_a)
|
115
115
|
end
|
116
116
|
|
117
117
|
def test_shift # aliased as gets() and readline()
|
118
|
-
FastCSV.open(@path, "rb+", col_sep: "
|
118
|
+
FastCSV.open(@path, "rb+", col_sep: "\t", row_sep: "\r\n") do |csv|
|
119
119
|
assert_equal(@expected.shift, csv.shift)
|
120
120
|
assert_equal(@expected.shift, csv.shift)
|
121
121
|
assert_equal(nil, csv.shift)
|
@@ -123,7 +123,7 @@ class TestCSV::Interface < TestCSV
|
|
123
123
|
end
|
124
124
|
|
125
125
|
def test_enumerators_are_supported
|
126
|
-
FastCSV.open(@path, col_sep: "
|
126
|
+
FastCSV.open(@path, col_sep: "\t", row_sep: "\r\n") do |csv|
|
127
127
|
enum = csv.each
|
128
128
|
assert_instance_of(Enumerator, enum)
|
129
129
|
assert_equal(@expected.shift, enum.next)
|
@@ -149,16 +149,16 @@ class TestCSV::Interface < TestCSV
|
|
149
149
|
end
|
150
150
|
|
151
151
|
def test_generate_line
|
152
|
-
line = FastCSV.generate_line(%w{1 2 3}, col_sep: "
|
152
|
+
line = FastCSV.generate_line(%w{1 2 3}, col_sep: ";")
|
153
153
|
assert_not_nil(line)
|
154
154
|
assert_instance_of(String, line)
|
155
|
-
assert_equal("1
|
155
|
+
assert_equal("1;2;3\n", line)
|
156
156
|
|
157
157
|
# shortcut interface
|
158
|
-
line = %w{1 2 3}.to_csv(col_sep: "
|
158
|
+
line = %w{1 2 3}.to_csv(col_sep: ";")
|
159
159
|
assert_not_nil(line)
|
160
160
|
assert_instance_of(String, line)
|
161
|
-
assert_equal("1
|
161
|
+
assert_equal("1;2;3\n", line)
|
162
162
|
end
|
163
163
|
|
164
164
|
def test_write_header_detection
|
@@ -242,19 +242,19 @@ class TestCSV::Interface < TestCSV
|
|
242
242
|
File.unlink(@path)
|
243
243
|
|
244
244
|
lines = [{"a" => 1, "b" => 2, "c" => 3}, {"a" => 4, "b" => 5, "c" => 6}]
|
245
|
-
FastCSV.open(@path, "wb", headers: "b
|
245
|
+
FastCSV.open(@path, "wb", headers: "b|a|c", col_sep: "|") do |csv|
|
246
246
|
lines.each { |line| csv << line }
|
247
247
|
end
|
248
248
|
|
249
249
|
# test writing fields in the correct order
|
250
250
|
File.open(@path, "rb") do |f|
|
251
|
-
assert_equal("2
|
252
|
-
assert_equal("5
|
251
|
+
assert_equal("2|1|3", f.gets.strip)
|
252
|
+
assert_equal("5|4|6", f.gets.strip)
|
253
253
|
end
|
254
254
|
|
255
255
|
# test reading FastCSV with headers
|
256
|
-
FastCSV.open( @path, "rb", headers: "b
|
257
|
-
col_sep: "
|
256
|
+
FastCSV.open( @path, "rb", headers: "b|a|c",
|
257
|
+
col_sep: "|",
|
258
258
|
converters: :all ) do |csv|
|
259
259
|
csv.each { |line| assert_equal(lines.shift, line.to_hash) }
|
260
260
|
end
|
@@ -264,22 +264,22 @@ class TestCSV::Interface < TestCSV
|
|
264
264
|
File.unlink(@path)
|
265
265
|
|
266
266
|
lines = [{"a" => 1, "b" => 2, "c" => 3}, {"a" => 4, "b" => 5, "c" => 6}]
|
267
|
-
FastCSV.open( @path, "wb", headers: "b
|
267
|
+
FastCSV.open( @path, "wb", headers: "b|a|c",
|
268
268
|
write_headers: true,
|
269
|
-
col_sep: "
|
269
|
+
col_sep: "|" ) do |csv|
|
270
270
|
lines.each { |line| csv << line }
|
271
271
|
end
|
272
272
|
|
273
273
|
# test writing fields in the correct order
|
274
274
|
File.open(@path, "rb") do |f|
|
275
|
-
assert_equal("b
|
276
|
-
assert_equal("2
|
277
|
-
assert_equal("5
|
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
278
|
end
|
279
279
|
|
280
280
|
# test reading FastCSV with headers
|
281
281
|
FastCSV.open( @path, "rb", headers: true,
|
282
|
-
col_sep: "
|
282
|
+
col_sep: "|",
|
283
283
|
converters: :all ) do |csv|
|
284
284
|
csv.each { |line| assert_equal(lines.shift, line.to_hash) }
|
285
285
|
end
|
@@ -288,7 +288,7 @@ class TestCSV::Interface < TestCSV
|
|
288
288
|
def test_append # aliased add_row() and puts()
|
289
289
|
File.unlink(@path)
|
290
290
|
|
291
|
-
FastCSV.open(@path, "wb", col_sep: "
|
291
|
+
FastCSV.open(@path, "wb", col_sep: "\t", row_sep: "\r\n") do |csv|
|
292
292
|
@expected.each { |row| csv << row }
|
293
293
|
end
|
294
294
|
|
@@ -297,7 +297,7 @@ class TestCSV::Interface < TestCSV
|
|
297
297
|
# same thing using FastCSV::Row objects
|
298
298
|
File.unlink(@path)
|
299
299
|
|
300
|
-
FastCSV.open(@path, "wb", col_sep: "
|
300
|
+
FastCSV.open(@path, "wb", col_sep: "\t", row_sep: "\r\n") do |csv|
|
301
301
|
@expected.each { |row| csv << FastCSV::Row.new(Array.new, row) }
|
302
302
|
end
|
303
303
|
|
@@ -310,8 +310,8 @@ class TestCSV::Interface < TestCSV
|
|
310
310
|
assert_respond_to(FastCSV, :filter)
|
311
311
|
|
312
312
|
expected = [[1, 2, 3], [4, 5]]
|
313
|
-
FastCSV.filter( "1
|
314
|
-
in_col_sep: "
|
313
|
+
FastCSV.filter( "1;2;3\n4;5\n", (result = String.new),
|
314
|
+
in_col_sep: ";", out_col_sep: ",",
|
315
315
|
converters: :all ) do |row|
|
316
316
|
assert_equal(row, expected.shift)
|
317
317
|
row.map! { |n| n * 2 }
|
@@ -325,20 +325,20 @@ class TestCSV::Interface < TestCSV
|
|
325
325
|
|
326
326
|
first = nil
|
327
327
|
assert_nothing_raised(Exception) do
|
328
|
-
first = FastCSV.instance(csv, col_sep: "
|
328
|
+
first = FastCSV.instance(csv, col_sep: ";")
|
329
329
|
first << %w{a b c}
|
330
330
|
end
|
331
331
|
|
332
|
-
assert_equal("a
|
332
|
+
assert_equal("a;b;c\n", csv)
|
333
333
|
|
334
334
|
second = nil
|
335
335
|
assert_nothing_raised(Exception) do
|
336
|
-
second = FastCSV.instance(csv, col_sep: "
|
336
|
+
second = FastCSV.instance(csv, col_sep: ";")
|
337
337
|
second << [1, 2, 3]
|
338
338
|
end
|
339
339
|
|
340
340
|
assert_equal(first.object_id, second.object_id)
|
341
|
-
assert_equal("a
|
341
|
+
assert_equal("a;b;c\n1;2;3\n", csv)
|
342
342
|
|
343
343
|
# shortcuts
|
344
344
|
assert_equal(STDOUT, FastCSV.instance.instance_eval { @io })
|