fastercsv 0.1.4 → 0.1.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.
@@ -110,8 +110,8 @@ class TestCSVParsing < Test::Unit::TestCase
110
110
  end
111
111
 
112
112
  def test_malformed_csv
113
- assert_raise(FasterCSV::MalformedCSVError) do
114
- FasterCSV.parse_line("1,2\r,3")
113
+ assert_raise(FasterCSV::MalformedCSVError) do
114
+ FasterCSV.parse_line("1,2\r,3", :row_sep => "\n")
115
115
  end
116
116
 
117
117
  assert_raise(FasterCSV::MalformedCSVError) do
@@ -0,0 +1,166 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # tc_data_converters.rb
4
+ #
5
+ # Created by James Edward Gray II on 2005-12-30.
6
+ # Copyright 2005 Gray Productions. All rights reserved.
7
+
8
+ require "test/unit"
9
+
10
+ require "faster_csv"
11
+
12
+ class TestDataConverters < Test::Unit::TestCase
13
+ def setup
14
+ @data = "Numbers,:integer,1,:float,3.015"
15
+ @parser = FasterCSV.new(@data)
16
+
17
+ @custom = lambda { |field| field =~ /\A:(\S.*?)\s*\Z/ ? $1.to_sym : field }
18
+ end
19
+
20
+ def test_builtin_integer_converter
21
+ # does convert
22
+ [-5, 1, 10000000000].each do |n|
23
+ assert_equal(n, FasterCSV::Converters[:integer][n.to_s])
24
+ end
25
+
26
+ # does not convert
27
+ (%w{junk 1.0} + [""]).each do |str|
28
+ assert_equal(str, FasterCSV::Converters[:integer][str])
29
+ end
30
+ end
31
+
32
+ def test_builtin_float_converter
33
+ # does convert
34
+ [-5.1234, 0, 2.3e-11].each do |n|
35
+ assert_equal(n, FasterCSV::Converters[:float][n.to_s])
36
+ end
37
+
38
+ # does not convert
39
+ (%w{junk 1..0 .015F} + [""]).each do |str|
40
+ assert_equal(str, FasterCSV::Converters[:float][str])
41
+ end
42
+ end
43
+
44
+ def test_builtin_date_converter
45
+ # does convert
46
+ assert_instance_of(Date, FasterCSV::Converters[:date][Time.now.to_s])
47
+
48
+ # does not convert
49
+ assert_instance_of(String, FasterCSV::Converters[:date]["junk"])
50
+ end
51
+
52
+ def test_builtin_date_time_converter
53
+ # does convert
54
+ assert_instance_of( DateTime,
55
+ FasterCSV::Converters[:date_time][Time.now.to_s] )
56
+
57
+ # does not convert
58
+ assert_instance_of(String, FasterCSV::Converters[:date_time]["junk"])
59
+ end
60
+
61
+ def test_convert_with_builtin
62
+ # setup parser...
63
+ assert(@parser.respond_to?(:convert))
64
+ assert_nothing_raised(Exception) { @parser.convert(:integer) }
65
+
66
+ # and use
67
+ assert_equal(["Numbers", ":integer", 1, ":float", "3.015"], @parser.shift)
68
+
69
+ setup # reset
70
+
71
+ # setup parser...
72
+ assert_nothing_raised(Exception) { @parser.convert(:float) }
73
+
74
+ # and use
75
+ assert_equal(["Numbers", ":integer", 1.0, ":float", 3.015], @parser.shift)
76
+ end
77
+
78
+ def test_convert_order
79
+ # floats first, then integers...
80
+ assert_nothing_raised(Exception) do
81
+ @parser.convert(:float)
82
+ @parser.convert(:integer)
83
+ end
84
+
85
+ # gets us nothing but floats
86
+ assert_equal( [String, String, Float, String, Float],
87
+ @parser.shift.map { |field| field.class } )
88
+
89
+ setup # reset
90
+
91
+ # integers have precendance...
92
+ assert_nothing_raised(Exception) do
93
+ @parser.convert(:integer)
94
+ @parser.convert(:float)
95
+ end
96
+
97
+ # gives us proper number conversion
98
+ assert_equal( [String, String, Fixnum, String, Float],
99
+ @parser.shift.map { |field| field.class } )
100
+ end
101
+
102
+ def test_builtin_numeric_combo_converter
103
+ # setup parser...
104
+ assert_nothing_raised(Exception) { @parser.convert(:numeric) }
105
+
106
+ # and use
107
+ assert_equal( [String, String, Fixnum, String, Float],
108
+ @parser.shift.map { |field| field.class } )
109
+ end
110
+
111
+ def test_builtin_all_nested_combo_converter
112
+ # setup parser...
113
+ @data << ",#{Time.now}" # add a DateTime field
114
+ @parser = FasterCSV.new(@data) # reset parser
115
+ assert_nothing_raised(Exception) { @parser.convert(:all) }
116
+
117
+ # and use
118
+ assert_equal( [String, String, Fixnum, String, Float, DateTime],
119
+ @parser.shift.map { |field| field.class } )
120
+ end
121
+
122
+ def test_convert_with_custom_code
123
+ # define custom converter...
124
+ assert_nothing_raised(Exception) do
125
+ @parser.convert { |field| field =~ /\A:(\S.*?)\s*\Z/ ? $1.to_sym : field }
126
+ end
127
+
128
+ # and use
129
+ assert_equal(["Numbers", :integer, "1", :float, "3.015"], @parser.shift)
130
+
131
+ setup # reset
132
+
133
+ # mix built-in and custom...
134
+ assert_nothing_raised(Exception) { @parser.convert(:numeric) }
135
+ assert_nothing_raised(Exception) { @parser.convert(&@custom) }
136
+
137
+ # and use
138
+ assert_equal(["Numbers", :integer, 1, :float, 3.015], @parser.shift)
139
+ end
140
+
141
+ def test_convert_with_custom_code_using_field_info
142
+ # define custom converter that uses field information...
143
+ assert_nothing_raised(Exception) do
144
+ @parser.convert do |field, info|
145
+ assert_equal(1, info.line)
146
+ info.index == 4 ? Float(field).floor : field
147
+ end
148
+ end
149
+
150
+ # and use
151
+ assert_equal(["Numbers", ":integer", "1", ":float", 3], @parser.shift)
152
+ end
153
+
154
+ def test_shortcut_interface
155
+ assert_equal( ["Numbers", ":integer", 1, ":float", 3.015],
156
+ FasterCSV.parse_line(@data, :converters => :numeric) )
157
+
158
+ assert_equal( ["Numbers", ":integer", 1, ":float", 3.015],
159
+ FasterCSV.parse_line( @data, :converters => [ :integer,
160
+ :float ] ) )
161
+
162
+ assert_equal( ["Numbers", :integer, 1, :float, 3.015],
163
+ FasterCSV.parse_line( @data, :converters => [ :numeric,
164
+ @custom ] ) )
165
+ end
166
+ end
data/test/tc_features.rb CHANGED
@@ -49,6 +49,24 @@ class TestFasterCSVFeatures < Test::Unit::TestCase
49
49
  :row_sep => "\r\n") )
50
50
  end
51
51
 
52
+ def test_row_sep_auto_discovery
53
+ ["\r\n", "\n", "\r"].each do |line_end|
54
+ data = "1,2,3#{line_end}4,5#{line_end}"
55
+ discovered = FasterCSV.new(data).instance_eval { @row_sep }
56
+ assert_equal(line_end, discovered)
57
+ end
58
+
59
+ assert_equal("\n", FasterCSV.new("\n\r\n\r").instance_eval { @row_sep })
60
+
61
+ assert_equal($/, FasterCSV.new("").instance_eval { @row_sep })
62
+ end
63
+
64
+ def test_unknown_options
65
+ assert_raise(ArgumentError) do
66
+ FasterCSV.new(String.new, :unknown => :error)
67
+ end
68
+ end
69
+
52
70
  def test_bug_fixes
53
71
  # failing to escape <tt>:col_sep</tt> (reported by Kev Jackson)
54
72
  assert_nothing_raised(Exception) do
@@ -0,0 +1,125 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # tc_headers.rb
4
+ #
5
+ # Created by James Edward Gray II on 2006-02-25.
6
+ # Copyright 2006 Gray Productions. All rights reserved.
7
+
8
+ require "test/unit"
9
+
10
+ require "faster_csv"
11
+
12
+ class TestFasterCSVHeaders < Test::Unit::TestCase
13
+ def setup
14
+ @data = <<-END_CSV.gsub(/^\s+/, "")
15
+ first,second,third
16
+ A,B,C
17
+ 1,2,3
18
+ END_CSV
19
+ end
20
+
21
+ def test_first_row
22
+ [:first_row, true].each do |setting| # two names for the same setting
23
+ # activate headers
24
+ csv = nil
25
+ assert_nothing_raised(Exception) do
26
+ csv = FasterCSV.parse(@data, :headers => setting)
27
+ end
28
+
29
+ # first data row - skipping headers
30
+ row = csv.shift
31
+ assert_not_nil(row)
32
+ assert_instance_of(FasterCSV::Row, row)
33
+ assert_equal([%w{first A}, %w{second B}, %w{third C}], row.to_a)
34
+
35
+ # second data row
36
+ row = csv.shift
37
+ assert_not_nil(row)
38
+ assert_instance_of(FasterCSV::Row, row)
39
+ assert_equal([%w{first 1}, %w{second 2}, %w{third 3}], row.to_a)
40
+
41
+ # empty
42
+ assert_nil(csv.shift)
43
+ end
44
+ end
45
+
46
+ def test_return_headers
47
+ # activate headers and request they are returned
48
+ csv = nil
49
+ assert_nothing_raised(Exception) do
50
+ csv = FasterCSV.parse(@data, :headers => true, :return_headers => true)
51
+ end
52
+
53
+ # header row
54
+ row = csv.shift
55
+ assert_not_nil(row)
56
+ assert_instance_of(FasterCSV::Row, row)
57
+ assert_equal( [%w{first first}, %w{second second}, %w{third third}],
58
+ row.to_a )
59
+
60
+ # first data row - skipping headers
61
+ row = csv.shift
62
+ assert_not_nil(row)
63
+ assert_instance_of(FasterCSV::Row, row)
64
+ assert_equal([%w{first A}, %w{second B}, %w{third C}], row.to_a)
65
+
66
+ # second data row
67
+ row = csv.shift
68
+ assert_not_nil(row)
69
+ assert_instance_of(FasterCSV::Row, row)
70
+ assert_equal([%w{first 1}, %w{second 2}, %w{third 3}], row.to_a)
71
+
72
+ # empty
73
+ assert_nil(csv.shift)
74
+ end
75
+
76
+ def test_converters
77
+ # create test data where headers and fields look alike
78
+ data = <<-END_MATCHING_CSV.gsub(/^\s+/, "")
79
+ 1,2,3
80
+ 1,2,3
81
+ END_MATCHING_CSV
82
+
83
+ # normal converters do not affect headers
84
+ csv = FasterCSV.parse( data, :headers => true,
85
+ :return_headers => true,
86
+ :converters => :numeric )
87
+ assert_equal([%w{1 1}, %w{2 2}, %w{3 3}], csv.shift.to_a)
88
+ assert_equal([["1", 1], ["2", 2], ["3", 3]], csv.shift.to_a)
89
+ assert_nil(csv.shift)
90
+
91
+ # header converters do affect headers (only)
92
+ assert_nothing_raised(Exception) do
93
+ csv = FasterCSV.parse( data, :headers => true,
94
+ :return_headers => true,
95
+ :converters => :numeric,
96
+ :header_converters => :symbol )
97
+ end
98
+ assert_equal([[:"1", :"1"], [:"2", :"2"], [:"3", :"3"]], csv.shift.to_a)
99
+ assert_equal([[:"1", 1], [:"2", 2], [:"3", 3]], csv.shift.to_a)
100
+ assert_nil(csv.shift)
101
+ end
102
+
103
+ def test_builtin_downcase_converter
104
+ csv = FasterCSV.parse( "One,TWO Three", :headers => true,
105
+ :return_headers => true,
106
+ :header_converters => :downcase )
107
+ assert_equal(%w{one two\ three}, csv.shift.headers)
108
+ end
109
+
110
+ def test_builtin_symbol_converter
111
+ csv = FasterCSV.parse( "One,TWO Three", :headers => true,
112
+ :return_headers => true,
113
+ :header_converters => :symbol )
114
+ assert_equal([:one, :two_three], csv.shift.headers)
115
+ end
116
+
117
+ def test_custom_converter
118
+ converter = lambda { |header| header.tr(" ", "_") }
119
+ csv = FasterCSV.parse( "One,TWO Three",
120
+ :headers => true,
121
+ :return_headers => true,
122
+ :header_converters => converter )
123
+ assert_equal(%w{One TWO_Three}, csv.shift.headers)
124
+ end
125
+ end
data/test/tc_interface.rb CHANGED
@@ -64,6 +64,12 @@ class TestFasterCSVInterface < Test::Unit::TestCase
64
64
  assert_not_nil(row)
65
65
  assert_instance_of(Array, row)
66
66
  assert_equal(%w{1 2 3}, row)
67
+
68
+ # shortcut interface
69
+ row = "1;2;3".parse_csv(:col_sep => ";")
70
+ assert_not_nil(row)
71
+ assert_instance_of(Array, row)
72
+ assert_equal(%w{1 2 3}, row)
67
73
  end
68
74
 
69
75
  def test_read_and_readlines
@@ -115,6 +121,12 @@ class TestFasterCSVInterface < Test::Unit::TestCase
115
121
  assert_not_nil(line)
116
122
  assert_instance_of(String, line)
117
123
  assert_equal("1;2;3\n", line)
124
+
125
+ # shortcut interface
126
+ line = %w{1 2 3}.to_csv(:col_sep => ";")
127
+ assert_not_nil(line)
128
+ assert_instance_of(String, line)
129
+ assert_equal("1;2;3\n", line)
118
130
  end
119
131
 
120
132
  def test_append # aliased add_row() and puts()
@@ -126,4 +138,20 @@ class TestFasterCSVInterface < Test::Unit::TestCase
126
138
 
127
139
  test_shift
128
140
  end
141
+
142
+ ### Test Read and Write Interface ###
143
+
144
+ def test_filter
145
+ assert_respond_to(FasterCSV, :filter)
146
+
147
+ expected = [[1, 2, 3], [4, 5]]
148
+ FasterCSV.filter( "1;2;3\n4;5\n", (result = String.new),
149
+ :in_col_sep => ";", :out_col_sep => ",",
150
+ :converters => :all ) do |row|
151
+ assert_equal(row, expected.shift)
152
+ row.map! { |n| n * 2 }
153
+ row << "Added\r"
154
+ end
155
+ assert_equal("2,4,6,\"Added\r\"\n8,10,\"Added\r\"\n", result)
156
+ end
129
157
  end
data/test/tc_row.rb ADDED
@@ -0,0 +1,264 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # tc_row.rb
4
+ #
5
+ # Created by James Edward Gray II on 2006-02-24.
6
+ # Copyright 2006 Gray Productions. All rights reserved.
7
+
8
+ require "test/unit"
9
+
10
+ require "faster_csv"
11
+
12
+ class TestFasterCSVRow < Test::Unit::TestCase
13
+ def setup
14
+ @row = FasterCSV::Row.new(%w{A B C A A}, [1, 2, 3, 4])
15
+ end
16
+
17
+ def test_initialize
18
+ # basic
19
+ row = FasterCSV::Row.new(%w{A B C}, [1, 2, 3])
20
+ assert_not_nil(row)
21
+ assert_instance_of(FasterCSV::Row, row)
22
+ assert_equal([["A", 1], ["B", 2], ["C", 3]], row.to_a)
23
+
24
+ # missing headers
25
+ row = FasterCSV::Row.new(%w{A}, [1, 2, 3])
26
+ assert_not_nil(row)
27
+ assert_instance_of(FasterCSV::Row, row)
28
+ assert_equal([["A", 1], [nil, 2], [nil, 3]], row.to_a)
29
+
30
+ # missing fields
31
+ row = FasterCSV::Row.new(%w{A B C}, [1, 2])
32
+ assert_not_nil(row)
33
+ assert_instance_of(FasterCSV::Row, row)
34
+ assert_equal([["A", 1], ["B", 2], ["C", nil]], row.to_a)
35
+ end
36
+
37
+ def test_headers
38
+ assert_equal(%w{A B C A A}, @row.headers)
39
+ end
40
+
41
+ def test_field
42
+ # by name
43
+ assert_equal(2, @row.field("B"))
44
+ assert_equal(2, @row["B"]) # alias
45
+
46
+ # by index
47
+ assert_equal(3, @row.field(2))
48
+
49
+ # missing
50
+ assert_nil(@row.field("Missing"))
51
+ assert_nil(@row.field(10))
52
+
53
+ # minimum index
54
+ assert_equal(1, @row.field("A"))
55
+ assert_equal(1, @row.field("A", 0))
56
+ assert_equal(4, @row.field("A", 1))
57
+ assert_equal(4, @row.field("A", 2))
58
+ assert_equal(4, @row.field("A", 3))
59
+ assert_equal(nil, @row.field("A", 4))
60
+ assert_equal(nil, @row.field("A", 5))
61
+ end
62
+
63
+ def test_set_field
64
+ # set field by name
65
+ assert_equal(100, @row["A"] = 100)
66
+
67
+ # set field by index
68
+ assert_equal(300, @row[3] = 300)
69
+
70
+ # set field by name and minimum index
71
+ assert_equal([:a, :b, :c], @row["A", 4] = [:a, :b, :c])
72
+
73
+ # verify the changes
74
+ assert_equal( [ ["A", 100],
75
+ ["B", 2],
76
+ ["C", 3],
77
+ ["A", 300],
78
+ ["A", [:a, :b, :c]] ], @row.to_a )
79
+
80
+ # assigning an index past the end
81
+ assert_equal("End", @row[10] = "End")
82
+ assert_equal( [ ["A", 100],
83
+ ["B", 2],
84
+ ["C", 3],
85
+ ["A", 300],
86
+ ["A", [:a, :b, :c]],
87
+ [nil, nil],
88
+ [nil, nil],
89
+ [nil, nil],
90
+ [nil, nil],
91
+ [nil, nil],
92
+ [nil, "End"] ], @row.to_a )
93
+
94
+ # assigning a new field by header
95
+ assert_equal("New", @row[:new] = "New")
96
+ assert_equal( [ ["A", 100],
97
+ ["B", 2],
98
+ ["C", 3],
99
+ ["A", 300],
100
+ ["A", [:a, :b, :c]],
101
+ [nil, nil],
102
+ [nil, nil],
103
+ [nil, nil],
104
+ [nil, nil],
105
+ [nil, nil],
106
+ [nil, "End"],
107
+ [:new, "New"] ], @row.to_a )
108
+ end
109
+
110
+ def test_append
111
+ # add a value
112
+ assert_equal(@row, @row << "Value")
113
+ assert_equal( [ ["A", 1],
114
+ ["B", 2],
115
+ ["C", 3],
116
+ ["A", 4],
117
+ ["A", nil],
118
+ [nil, "Value"] ], @row.to_a )
119
+
120
+ # add a pair
121
+ assert_equal(@row, @row << %w{Header Field})
122
+ assert_equal( [ ["A", 1],
123
+ ["B", 2],
124
+ ["C", 3],
125
+ ["A", 4],
126
+ ["A", nil],
127
+ [nil, "Value"],
128
+ %w{Header Field} ], @row.to_a )
129
+
130
+ # a pair with Hash syntax
131
+ assert_equal(@row, @row << {:key => :value})
132
+ assert_equal( [ ["A", 1],
133
+ ["B", 2],
134
+ ["C", 3],
135
+ ["A", 4],
136
+ ["A", nil],
137
+ [nil, "Value"],
138
+ %w{Header Field},
139
+ [:key, :value] ], @row.to_a )
140
+
141
+ # multiple fields at once
142
+ assert_equal(@row, @row.push(100, 200, [:last, 300]))
143
+ assert_equal( [ ["A", 1],
144
+ ["B", 2],
145
+ ["C", 3],
146
+ ["A", 4],
147
+ ["A", nil],
148
+ [nil, "Value"],
149
+ %w{Header Field},
150
+ [:key, :value],
151
+ [nil, 100],
152
+ [nil, 200],
153
+ [:last, 300] ], @row.to_a )
154
+ end
155
+
156
+ def test_delete
157
+ # by index
158
+ assert_equal(["B", 2], @row.delete(1))
159
+
160
+ # by header
161
+ assert_equal(["C", 3], @row.delete("C"))
162
+
163
+ # using a block
164
+ assert_equal(@row, @row.delete_if { |h, f| h == "A" and not f.nil? })
165
+ assert_equal([["A", nil]], @row.to_a)
166
+ end
167
+
168
+ def test_fields
169
+ # all fields
170
+ assert_equal([1, 2, 3, 4, nil], @row.fields)
171
+
172
+ # by header
173
+ assert_equal([1, 3], @row.fields("A", "C"))
174
+
175
+ # by index
176
+ assert_equal([2, 3, nil], @row.fields(1, 2, 10))
177
+
178
+ # by both
179
+ assert_equal([2, 3, 4], @row.fields("B", "C", 3))
180
+
181
+ # with minimum indices
182
+ assert_equal([2, 3, 4], @row.fields("B", "C", ["A", 3]))
183
+ end
184
+
185
+ def test_index
186
+ # basic usage
187
+ assert_equal(0, @row.index("A"))
188
+ assert_equal(1, @row.index("B"))
189
+ assert_equal(2, @row.index("C"))
190
+ assert_equal(nil, @row.index("Z"))
191
+
192
+ # with minimum index
193
+ assert_equal(0, @row.index("A"))
194
+ assert_equal(0, @row.index("A", 0))
195
+ assert_equal(3, @row.index("A", 1))
196
+ assert_equal(3, @row.index("A", 2))
197
+ assert_equal(3, @row.index("A", 3))
198
+ assert_equal(4, @row.index("A", 4))
199
+ assert_equal(nil, @row.index("A", 5))
200
+ end
201
+
202
+ def test_queries
203
+ # headers
204
+ assert(@row.header?("A"))
205
+ assert(@row.header?("C"))
206
+ assert(!@row.header?("Z"))
207
+ assert(@row.include?("A")) # alias
208
+
209
+ # fields
210
+ assert(@row.field?(4))
211
+ assert(@row.field?(nil))
212
+ assert(!@row.field?(10))
213
+ end
214
+
215
+ def test_each
216
+ # array style
217
+ ary = @row.to_a
218
+ @row.each do |pair|
219
+ assert_equal(ary.first.first, pair.first)
220
+ assert_equal(ary.shift.last, pair.last)
221
+ end
222
+
223
+ # hash style
224
+ ary = @row.to_a
225
+ @row.each do |header, field|
226
+ assert_equal(ary.first.first, header)
227
+ assert_equal(ary.shift.last, field)
228
+ end
229
+
230
+ # verify that we can chain the call
231
+ assert_equal(@row, @row.each { })
232
+ end
233
+
234
+ def test_enumerable
235
+ assert_equal( [["A", 1], ["A", 4], ["A", nil]],
236
+ @row.select { |pair| pair.first == "A" } )
237
+
238
+ assert_equal(10, @row.inject(0) { |sum, (header, n)| sum + (n || 0) })
239
+ end
240
+
241
+ def test_to_a
242
+ row = FasterCSV::Row.new(%w{A B C}, [1, 2, 3]).to_a
243
+ assert_instance_of(Array, row)
244
+ row.each do |pair|
245
+ assert_instance_of(Array, pair)
246
+ assert_equal(2, pair.size)
247
+ end
248
+ assert_equal([["A", 1], ["B", 2], ["C", 3]], row)
249
+ end
250
+
251
+ def test_to_hash
252
+ assert_equal({"A" => nil, "B" => 2, "C" => 3}, @row.to_hash)
253
+ end
254
+
255
+ def test_to_csv
256
+ # normal conversion
257
+ assert_equal("1,2,3,4,\n", @row.to_csv)
258
+ assert_equal("1,2,3,4,\n", @row.to_s) # alias
259
+
260
+ # with options
261
+ assert_equal( "1|2|3|4|\r\n",
262
+ @row.to_csv(:col_sep => "|", :row_sep => "\r\n") )
263
+ end
264
+ end