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
data/test/tc_rp_cases.rb
ADDED
@@ -0,0 +1,45 @@
|
|
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 TestFasterCSVRPCases < Test::Unit::TestCase
|
13
|
+
def setup
|
14
|
+
@path = File.join(File.dirname(__FILE__), "export.csv")
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
# File.unlink(@path)
|
19
|
+
end
|
20
|
+
|
21
|
+
#RPBS-2760
|
22
|
+
def test_failed_export
|
23
|
+
lines = []
|
24
|
+
csv = FasterCSV.open(@path, :raise_exception => true)
|
25
|
+
assert_raise(FasterCSV::MalformedCSVError) do
|
26
|
+
while line = csv.gets
|
27
|
+
lines<<line
|
28
|
+
end
|
29
|
+
end
|
30
|
+
assert_equal(4,lines.size)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_success_export
|
34
|
+
lines = []
|
35
|
+
csv = FasterCSV.open(@path, :raise_exception => false)
|
36
|
+
assert_nothing_raised do
|
37
|
+
while line = csv.gets
|
38
|
+
lines<<line
|
39
|
+
end
|
40
|
+
end
|
41
|
+
assert_equal(5,lines.size)
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
# tc_serialization.rb
|
4
|
+
#
|
5
|
+
# Created by James Edward Gray II on 2006-03-28.
|
6
|
+
# Copyright 2006 Gray Productions. All rights reserved.
|
7
|
+
|
8
|
+
require "test/unit"
|
9
|
+
|
10
|
+
require "faster_csv"
|
11
|
+
|
12
|
+
# An example of how to provide custom CSV serialization.
|
13
|
+
class Hash
|
14
|
+
def self.csv_load( meta, headers, fields )
|
15
|
+
self[*headers.zip(fields).flatten.map { |e| eval(e) }]
|
16
|
+
end
|
17
|
+
|
18
|
+
def csv_headers
|
19
|
+
keys.map { |key| key.inspect }
|
20
|
+
end
|
21
|
+
|
22
|
+
def csv_dump( headers )
|
23
|
+
headers.map { |header| fetch(eval(header)).inspect }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class TestSerialization < Test::Unit::TestCase
|
28
|
+
|
29
|
+
### Classes Used to Test Serialization ###
|
30
|
+
|
31
|
+
class ReadOnlyName
|
32
|
+
def initialize( first, last )
|
33
|
+
@first, @last = first, last
|
34
|
+
end
|
35
|
+
|
36
|
+
attr_reader :first, :last
|
37
|
+
|
38
|
+
def ==( other )
|
39
|
+
%w{first last}.all? { |att| send(att) == other.send(att) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
Name = Struct.new(:first, :last)
|
44
|
+
|
45
|
+
class FullName < Name
|
46
|
+
def initialize( first, last, suffix = nil )
|
47
|
+
super(first, last)
|
48
|
+
|
49
|
+
@suffix = suffix
|
50
|
+
end
|
51
|
+
|
52
|
+
attr_accessor :suffix
|
53
|
+
|
54
|
+
def ==( other )
|
55
|
+
%w{first last suffix}.all? { |att| send(att) == other.send(att) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
### Tests ###
|
60
|
+
|
61
|
+
def test_class_dump
|
62
|
+
@names = [ %w{James Gray},
|
63
|
+
%w{Dana Gray},
|
64
|
+
%w{Greg Brown} ].map do |first, last|
|
65
|
+
ReadOnlyName.new(first, last)
|
66
|
+
end
|
67
|
+
|
68
|
+
assert_nothing_raised(Exception) do
|
69
|
+
@data = FasterCSV.dump(@names)
|
70
|
+
end
|
71
|
+
assert_equal(<<-END_CLASS_DUMP.gsub(/^\s*/, ""), @data)
|
72
|
+
class,TestSerialization::ReadOnlyName
|
73
|
+
@first,@last
|
74
|
+
James,Gray
|
75
|
+
Dana,Gray
|
76
|
+
Greg,Brown
|
77
|
+
END_CLASS_DUMP
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_struct_dump
|
81
|
+
@names = [ %w{James Gray},
|
82
|
+
%w{Dana Gray},
|
83
|
+
%w{Greg Brown} ].map do |first, last|
|
84
|
+
Name.new(first, last)
|
85
|
+
end
|
86
|
+
|
87
|
+
assert_nothing_raised(Exception) do
|
88
|
+
@data = FasterCSV.dump(@names)
|
89
|
+
end
|
90
|
+
assert_equal(<<-END_STRUCT_DUMP.gsub(/^\s*/, ""), @data)
|
91
|
+
class,TestSerialization::Name
|
92
|
+
first=,last=
|
93
|
+
James,Gray
|
94
|
+
Dana,Gray
|
95
|
+
Greg,Brown
|
96
|
+
END_STRUCT_DUMP
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_inherited_struct_dump
|
100
|
+
@names = [ %w{James Gray II},
|
101
|
+
%w{Dana Gray},
|
102
|
+
%w{Greg Brown} ].map do |first, last, suffix|
|
103
|
+
FullName.new(first, last, suffix)
|
104
|
+
end
|
105
|
+
|
106
|
+
assert_nothing_raised(Exception) do
|
107
|
+
@data = FasterCSV.dump(@names)
|
108
|
+
end
|
109
|
+
assert_equal(<<-END_STRUCT_DUMP.gsub(/^\s*/, ""), @data)
|
110
|
+
class,TestSerialization::FullName
|
111
|
+
@suffix,first=,last=
|
112
|
+
II,James,Gray
|
113
|
+
,Dana,Gray
|
114
|
+
,Greg,Brown
|
115
|
+
END_STRUCT_DUMP
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_load
|
119
|
+
%w{ test_class_dump
|
120
|
+
test_struct_dump
|
121
|
+
test_inherited_struct_dump }.each do |test|
|
122
|
+
send(test)
|
123
|
+
FasterCSV.load(@data).each do |loaded|
|
124
|
+
assert_instance_of(@names.first.class, loaded)
|
125
|
+
assert_equal(@names.shift, loaded)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_io
|
131
|
+
test_class_dump
|
132
|
+
|
133
|
+
data_file = File.join(File.dirname(__FILE__), "temp_test_data.csv")
|
134
|
+
FasterCSV.dump(@names, File.open(data_file, "w"))
|
135
|
+
|
136
|
+
assert(File.exist?(data_file))
|
137
|
+
assert_equal(<<-END_IO_DUMP.gsub(/^\s*/, ""), File.read(data_file))
|
138
|
+
class,TestSerialization::ReadOnlyName
|
139
|
+
@first,@last
|
140
|
+
James,Gray
|
141
|
+
Dana,Gray
|
142
|
+
Greg,Brown
|
143
|
+
END_IO_DUMP
|
144
|
+
|
145
|
+
assert_equal(@names, FasterCSV.load(File.open(data_file)))
|
146
|
+
|
147
|
+
File.unlink(data_file)
|
148
|
+
end
|
149
|
+
|
150
|
+
def test_custom_dump_and_load
|
151
|
+
obj = {1 => "simple", :test => Hash}
|
152
|
+
assert_equal(obj, FasterCSV.load(FasterCSV.dump([obj])).first)
|
153
|
+
end
|
154
|
+
end
|
data/test/tc_speed.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
# tc_speed.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
|
+
require "timeout"
|
10
|
+
|
11
|
+
require "faster_csv"
|
12
|
+
require "csv"
|
13
|
+
|
14
|
+
class TestFasterCSVSpeed < Test::Unit::TestCase
|
15
|
+
PATH = File.join(File.dirname(__FILE__), "test_data.csv")
|
16
|
+
BIG_DATA = "123456789\n" * 1024
|
17
|
+
|
18
|
+
def test_that_we_are_doing_the_same_work
|
19
|
+
FasterCSV.open(PATH) do |csv|
|
20
|
+
CSV.foreach(PATH) do |row|
|
21
|
+
assert_equal(row, csv.shift)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_speed_vs_csv
|
27
|
+
csv_time = Time.now
|
28
|
+
CSV.foreach(PATH) do |row|
|
29
|
+
# do nothing, we're just timing a read...
|
30
|
+
end
|
31
|
+
csv_time = Time.now - csv_time
|
32
|
+
|
33
|
+
faster_csv_time = Time.now
|
34
|
+
FasterCSV.foreach(PATH) do |row|
|
35
|
+
# do nothing, we're just timing a read...
|
36
|
+
end
|
37
|
+
faster_csv_time = Time.now - faster_csv_time
|
38
|
+
|
39
|
+
assert(faster_csv_time < csv_time / 3)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_the_parse_fails_fast_when_it_can_for_unquoted_fields
|
43
|
+
assert_parse_errors_out('valid,fields,bad start"' + BIG_DATA)
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_the_parse_fails_fast_when_it_can_for_unescaped_quotes
|
47
|
+
assert_parse_errors_out('valid,fields,"bad start"unescaped' + BIG_DATA)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_field_size_limit_controls_lookahead
|
51
|
+
assert_parse_errors_out( 'valid,fields,"' + BIG_DATA + '"',
|
52
|
+
:field_size_limit => 2048 )
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def assert_parse_errors_out(*args)
|
58
|
+
assert_raise(FasterCSV::MalformedCSVError) do
|
59
|
+
Timeout.timeout(0.2) do
|
60
|
+
FasterCSV.parse(*args)
|
61
|
+
fail("Parse didn't error out")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/test/tc_table.rb
ADDED
@@ -0,0 +1,408 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
# tc_table.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 TestFasterCSVTable < Test::Unit::TestCase
|
13
|
+
def setup
|
14
|
+
@rows = [ FasterCSV::Row.new(%w{A B C}, [1, 2, 3]),
|
15
|
+
FasterCSV::Row.new(%w{A B C}, [4, 5, 6]),
|
16
|
+
FasterCSV::Row.new(%w{A B C}, [7, 8, 9]) ]
|
17
|
+
@table = FasterCSV::Table.new(@rows)
|
18
|
+
|
19
|
+
@header_table = FasterCSV::Table.new(
|
20
|
+
[FasterCSV::Row.new(%w{A B C}, %w{A B C}, true)] + @rows
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_initialze
|
25
|
+
assert_not_nil(@table)
|
26
|
+
assert_instance_of(FasterCSV::Table, @table)
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_modes
|
30
|
+
assert_equal(:col_or_row, @table.mode)
|
31
|
+
|
32
|
+
# non-destructive changes, intended for one shot calls
|
33
|
+
cols = @table.by_col
|
34
|
+
assert_equal(:col_or_row, @table.mode)
|
35
|
+
assert_equal(:col, cols.mode)
|
36
|
+
assert_equal(@table, cols)
|
37
|
+
|
38
|
+
rows = @table.by_row
|
39
|
+
assert_equal(:col_or_row, @table.mode)
|
40
|
+
assert_equal(:row, rows.mode)
|
41
|
+
assert_equal(@table, rows)
|
42
|
+
|
43
|
+
# destructive mode changing calls
|
44
|
+
assert_equal(@table, @table.by_row!)
|
45
|
+
assert_equal(:row, @table.mode)
|
46
|
+
assert_equal(@table, @table.by_col_or_row!)
|
47
|
+
assert_equal(:col_or_row, @table.mode)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_headers
|
51
|
+
assert_equal(@rows.first.headers, @table.headers)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_index
|
55
|
+
##################
|
56
|
+
### Mixed Mode ###
|
57
|
+
##################
|
58
|
+
# by row
|
59
|
+
@rows.each_index { |i| assert_equal(@rows[i], @table[i]) }
|
60
|
+
assert_equal(nil, @table[100]) # empty row
|
61
|
+
|
62
|
+
# by col
|
63
|
+
@rows.first.headers.each do |header|
|
64
|
+
assert_equal(@rows.map { |row| row[header] }, @table[header])
|
65
|
+
end
|
66
|
+
assert_equal([nil] * @rows.size, @table["Z"]) # empty col
|
67
|
+
|
68
|
+
# by cell, row then col
|
69
|
+
assert_equal(2, @table[0][1])
|
70
|
+
assert_equal(6, @table[1]["C"])
|
71
|
+
|
72
|
+
# by cell, col then row
|
73
|
+
assert_equal(5, @table["B"][1])
|
74
|
+
assert_equal(9, @table["C"][2])
|
75
|
+
|
76
|
+
# with headers (by col)
|
77
|
+
assert_equal(["B", 2, 5, 8], @header_table["B"])
|
78
|
+
|
79
|
+
###################
|
80
|
+
### Column Mode ###
|
81
|
+
###################
|
82
|
+
@table.by_col!
|
83
|
+
|
84
|
+
assert_equal([2, 5, 8], @table[1])
|
85
|
+
assert_equal([2, 5, 8], @table["B"])
|
86
|
+
|
87
|
+
################
|
88
|
+
### Row Mode ###
|
89
|
+
################
|
90
|
+
@table.by_row!
|
91
|
+
|
92
|
+
assert_equal(@rows[1], @table[1])
|
93
|
+
assert_raise(TypeError) { @table["B"] }
|
94
|
+
|
95
|
+
############################
|
96
|
+
### One Shot Mode Change ###
|
97
|
+
############################
|
98
|
+
assert_equal(@rows[1], @table[1])
|
99
|
+
assert_equal([2, 5, 8], @table.by_col[1])
|
100
|
+
assert_equal(@rows[1], @table[1])
|
101
|
+
end
|
102
|
+
|
103
|
+
def test_set_row_or_column
|
104
|
+
##################
|
105
|
+
### Mixed Mode ###
|
106
|
+
##################
|
107
|
+
# set row
|
108
|
+
@table[2] = [10, 11, 12]
|
109
|
+
assert_equal([%w[A B C], [1, 2, 3], [4, 5, 6], [10, 11, 12]], @table.to_a)
|
110
|
+
|
111
|
+
@table[3] = FasterCSV::Row.new(%w[A B C], [13, 14, 15])
|
112
|
+
assert_equal( [%w[A B C], [1, 2, 3], [4, 5, 6], [10, 11, 12], [13, 14, 15]],
|
113
|
+
@table.to_a )
|
114
|
+
|
115
|
+
# set col
|
116
|
+
@table["Type"] = "data"
|
117
|
+
assert_equal( [ %w[A B C Type],
|
118
|
+
[1, 2, 3, "data"],
|
119
|
+
[4, 5, 6, "data"],
|
120
|
+
[10, 11, 12, "data"],
|
121
|
+
[13, 14, 15, "data"] ],
|
122
|
+
@table.to_a )
|
123
|
+
|
124
|
+
@table["Index"] = [1, 2, 3]
|
125
|
+
assert_equal( [ %w[A B C Type Index],
|
126
|
+
[1, 2, 3, "data", 1],
|
127
|
+
[4, 5, 6, "data", 2],
|
128
|
+
[10, 11, 12, "data", 3],
|
129
|
+
[13, 14, 15, "data", nil] ],
|
130
|
+
@table.to_a )
|
131
|
+
|
132
|
+
@table["B"] = [100, 200]
|
133
|
+
assert_equal( [ %w[A B C Type Index],
|
134
|
+
[1, 100, 3, "data", 1],
|
135
|
+
[4, 200, 6, "data", 2],
|
136
|
+
[10, nil, 12, "data", 3],
|
137
|
+
[13, nil, 15, "data", nil] ],
|
138
|
+
@table.to_a )
|
139
|
+
|
140
|
+
# verify resulting table
|
141
|
+
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
|
142
|
+
A,B,C,Type,Index
|
143
|
+
1,100,3,data,1
|
144
|
+
4,200,6,data,2
|
145
|
+
10,,12,data,3
|
146
|
+
13,,15,data,
|
147
|
+
END_RESULT
|
148
|
+
|
149
|
+
# with headers
|
150
|
+
@header_table["Type"] = "data"
|
151
|
+
assert_equal(%w[Type data data data], @header_table["Type"])
|
152
|
+
|
153
|
+
###################
|
154
|
+
### Column Mode ###
|
155
|
+
###################
|
156
|
+
@table.by_col!
|
157
|
+
|
158
|
+
@table[1] = [2, 5, 11, 14]
|
159
|
+
assert_equal( [ %w[A B C Type Index],
|
160
|
+
[1, 2, 3, "data", 1],
|
161
|
+
[4, 5, 6, "data", 2],
|
162
|
+
[10, 11, 12, "data", 3],
|
163
|
+
[13, 14, 15, "data", nil] ],
|
164
|
+
@table.to_a )
|
165
|
+
|
166
|
+
@table["Extra"] = "new stuff"
|
167
|
+
assert_equal( [ %w[A B C Type Index Extra],
|
168
|
+
[1, 2, 3, "data", 1, "new stuff"],
|
169
|
+
[4, 5, 6, "data", 2, "new stuff"],
|
170
|
+
[10, 11, 12, "data", 3, "new stuff"],
|
171
|
+
[13, 14, 15, "data", nil, "new stuff"] ],
|
172
|
+
@table.to_a )
|
173
|
+
|
174
|
+
################
|
175
|
+
### Row Mode ###
|
176
|
+
################
|
177
|
+
@table.by_row!
|
178
|
+
|
179
|
+
@table[1] = (1..6).to_a
|
180
|
+
assert_equal( [ %w[A B C Type Index Extra],
|
181
|
+
[1, 2, 3, "data", 1, "new stuff"],
|
182
|
+
[1, 2, 3, 4, 5, 6],
|
183
|
+
[10, 11, 12, "data", 3, "new stuff"],
|
184
|
+
[13, 14, 15, "data", nil, "new stuff"] ],
|
185
|
+
@table.to_a )
|
186
|
+
|
187
|
+
assert_raise(TypeError) { @table["Extra"] = nil }
|
188
|
+
end
|
189
|
+
|
190
|
+
def test_each
|
191
|
+
######################
|
192
|
+
### Mixed/Row Mode ###
|
193
|
+
######################
|
194
|
+
i = 0
|
195
|
+
@table.each do |row|
|
196
|
+
assert_equal(@rows[i], row)
|
197
|
+
i += 1
|
198
|
+
end
|
199
|
+
|
200
|
+
# verify that we can chain the call
|
201
|
+
assert_equal(@table, @table.each { })
|
202
|
+
|
203
|
+
###################
|
204
|
+
### Column Mode ###
|
205
|
+
###################
|
206
|
+
@table.by_col!
|
207
|
+
|
208
|
+
headers = @table.headers
|
209
|
+
@table.each do |header, column|
|
210
|
+
assert_equal(headers.shift, header)
|
211
|
+
assert_equal(@table[header], column)
|
212
|
+
end
|
213
|
+
|
214
|
+
############################
|
215
|
+
### One Shot Mode Change ###
|
216
|
+
############################
|
217
|
+
@table.by_col_or_row!
|
218
|
+
|
219
|
+
@table.each { |row| assert_instance_of(FasterCSV::Row, row) }
|
220
|
+
@table.by_col.each { |tuple| assert_instance_of(Array, tuple) }
|
221
|
+
@table.each { |row| assert_instance_of(FasterCSV::Row, row) }
|
222
|
+
end
|
223
|
+
|
224
|
+
def test_enumerable
|
225
|
+
assert_equal( @rows.values_at(0, 2),
|
226
|
+
@table.select { |row| (row["B"] % 2).zero? } )
|
227
|
+
|
228
|
+
assert_equal(@rows[1], @table.find { |row| row["C"] > 5 })
|
229
|
+
end
|
230
|
+
|
231
|
+
def test_to_a
|
232
|
+
assert_equal([%w[A B C], [1, 2, 3], [4, 5, 6], [7, 8, 9]], @table.to_a)
|
233
|
+
|
234
|
+
# with headers
|
235
|
+
assert_equal( [%w[A B C], [1, 2, 3], [4, 5, 6], [7, 8, 9]],
|
236
|
+
@header_table.to_a )
|
237
|
+
end
|
238
|
+
|
239
|
+
def test_to_csv
|
240
|
+
csv = <<-END_CSV.gsub(/^\s+/, "")
|
241
|
+
A,B,C
|
242
|
+
1,2,3
|
243
|
+
4,5,6
|
244
|
+
7,8,9
|
245
|
+
END_CSV
|
246
|
+
|
247
|
+
# normal conversion
|
248
|
+
assert_equal(csv, @table.to_csv)
|
249
|
+
assert_equal(csv, @table.to_s) # alias
|
250
|
+
|
251
|
+
# with options
|
252
|
+
assert_equal( csv.gsub(",", "|").gsub("\n", "\r\n"),
|
253
|
+
@table.to_csv(:col_sep => "|", :row_sep => "\r\n") )
|
254
|
+
assert_equal( csv.to_a[1..-1].join,
|
255
|
+
@table.to_csv(:write_headers => false) )
|
256
|
+
|
257
|
+
# with headers
|
258
|
+
assert_equal(csv, @header_table.to_csv)
|
259
|
+
end
|
260
|
+
|
261
|
+
def test_append
|
262
|
+
# verify that we can chain the call
|
263
|
+
assert_equal(@table, @table << [10, 11, 12])
|
264
|
+
|
265
|
+
# Array append
|
266
|
+
assert_equal(FasterCSV::Row.new(%w[A B C], [10, 11, 12]), @table[-1])
|
267
|
+
|
268
|
+
# Row append
|
269
|
+
assert_equal(@table, @table << FasterCSV::Row.new(%w[A B C], [13, 14, 15]))
|
270
|
+
assert_equal(FasterCSV::Row.new(%w[A B C], [13, 14, 15]), @table[-1])
|
271
|
+
end
|
272
|
+
|
273
|
+
def test_delete
|
274
|
+
##################
|
275
|
+
### Mixed Mode ###
|
276
|
+
##################
|
277
|
+
# delete a row
|
278
|
+
assert_equal(@rows[1], @table.delete(1))
|
279
|
+
|
280
|
+
# delete a col
|
281
|
+
assert_equal(@rows.map { |row| row["A"] }, @table.delete("A"))
|
282
|
+
|
283
|
+
# verify resulting table
|
284
|
+
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
|
285
|
+
B,C
|
286
|
+
2,3
|
287
|
+
8,9
|
288
|
+
END_RESULT
|
289
|
+
|
290
|
+
###################
|
291
|
+
### Column Mode ###
|
292
|
+
###################
|
293
|
+
setup
|
294
|
+
@table.by_col!
|
295
|
+
|
296
|
+
assert_equal(@rows.map { |row| row[0] }, @table.delete(0))
|
297
|
+
assert_equal(@rows.map { |row| row["C"] }, @table.delete("C"))
|
298
|
+
|
299
|
+
# verify resulting table
|
300
|
+
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
|
301
|
+
B
|
302
|
+
2
|
303
|
+
5
|
304
|
+
8
|
305
|
+
END_RESULT
|
306
|
+
|
307
|
+
################
|
308
|
+
### Row Mode ###
|
309
|
+
################
|
310
|
+
setup
|
311
|
+
@table.by_row!
|
312
|
+
|
313
|
+
assert_equal(@rows[1], @table.delete(1))
|
314
|
+
assert_raise(TypeError) { @table.delete("C") }
|
315
|
+
|
316
|
+
# verify resulting table
|
317
|
+
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
|
318
|
+
A,B,C
|
319
|
+
1,2,3
|
320
|
+
7,8,9
|
321
|
+
END_RESULT
|
322
|
+
end
|
323
|
+
|
324
|
+
def test_delete_with_blank_rows
|
325
|
+
data = "col1,col2\nra1,ra2\n\nrb1,rb2"
|
326
|
+
table = FasterCSV.parse(data, :headers => true)
|
327
|
+
assert_equal(["ra2", nil, "rb2"], table.delete("col2"))
|
328
|
+
end
|
329
|
+
|
330
|
+
def test_delete_if
|
331
|
+
######################
|
332
|
+
### Mixed/Row Mode ###
|
333
|
+
######################
|
334
|
+
# verify that we can chain the call
|
335
|
+
assert_equal(@table, @table.delete_if { |row| (row["B"] % 2).zero? })
|
336
|
+
|
337
|
+
# verify resulting table
|
338
|
+
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
|
339
|
+
A,B,C
|
340
|
+
4,5,6
|
341
|
+
END_RESULT
|
342
|
+
|
343
|
+
###################
|
344
|
+
### Column Mode ###
|
345
|
+
###################
|
346
|
+
setup
|
347
|
+
@table.by_col!
|
348
|
+
|
349
|
+
assert_equal(@table, @table.delete_if { |h, v| h > "A" })
|
350
|
+
assert_equal(<<-END_RESULT.gsub(/^\s+/, ""), @table.to_csv)
|
351
|
+
A
|
352
|
+
1
|
353
|
+
4
|
354
|
+
7
|
355
|
+
END_RESULT
|
356
|
+
end
|
357
|
+
|
358
|
+
def test_values_at
|
359
|
+
##################
|
360
|
+
### Mixed Mode ###
|
361
|
+
##################
|
362
|
+
# rows
|
363
|
+
assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
|
364
|
+
assert_equal(@rows.values_at(1..2), @table.values_at(1..2))
|
365
|
+
|
366
|
+
# cols
|
367
|
+
assert_equal([[1, 3], [4, 6], [7, 9]], @table.values_at("A", "C"))
|
368
|
+
assert_equal([[2, 3], [5, 6], [8, 9]], @table.values_at("B".."C"))
|
369
|
+
|
370
|
+
###################
|
371
|
+
### Column Mode ###
|
372
|
+
###################
|
373
|
+
@table.by_col!
|
374
|
+
|
375
|
+
assert_equal([[1, 3], [4, 6], [7, 9]], @table.values_at(0, 2))
|
376
|
+
assert_equal([[1, 3], [4, 6], [7, 9]], @table.values_at("A", "C"))
|
377
|
+
|
378
|
+
################
|
379
|
+
### Row Mode ###
|
380
|
+
################
|
381
|
+
@table.by_row!
|
382
|
+
|
383
|
+
assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
|
384
|
+
assert_raise(TypeError) { @table.values_at("A", "C") }
|
385
|
+
|
386
|
+
############################
|
387
|
+
### One Shot Mode Change ###
|
388
|
+
############################
|
389
|
+
assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
|
390
|
+
assert_equal([[1, 3], [4, 6], [7, 9]], @table.by_col.values_at(0, 2))
|
391
|
+
assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
|
392
|
+
end
|
393
|
+
|
394
|
+
def test_array_delegation
|
395
|
+
assert(!@table.empty?, "Table was empty.")
|
396
|
+
|
397
|
+
assert_equal(@rows.size, @table.size)
|
398
|
+
end
|
399
|
+
|
400
|
+
def test_inspect_shows_current_mode
|
401
|
+
str = @table.inspect
|
402
|
+
assert(str.include?("mode:#{@table.mode}"), "Mode not shown.")
|
403
|
+
|
404
|
+
@table.by_col!
|
405
|
+
str = @table.inspect
|
406
|
+
assert(str.include?("mode:#{@table.mode}"), "Mode not shown.")
|
407
|
+
end
|
408
|
+
end
|