fastercsv 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +9 -0
- data/TODO +1 -1
- data/examples/csv_converters.rb +28 -0
- data/lib/faster_csv.rb +47 -10
- data/test/tc_features.rb +23 -9
- data/test/tc_headers.rb +35 -0
- data/test/tc_row.rb +6 -0
- data/test/tc_table.rb +6 -0
- metadata +3 -2
data/CHANGELOG
CHANGED
@@ -2,6 +2,15 @@
|
|
2
2
|
|
3
3
|
Below is a complete listing of changes for each revision of FasterCSV.
|
4
4
|
|
5
|
+
== 1.1.0
|
6
|
+
|
7
|
+
* Added empty?(), length(), and size() methods to FasterCSV::Row and
|
8
|
+
FasterCSV::Table.
|
9
|
+
* Cleaned up bug fix regression tests.
|
10
|
+
* Fixed bug causing Arrays to be returned for blank rows when header processing
|
11
|
+
is active.
|
12
|
+
* Added a <tt>:skip_blanks</tt> option for ignoring empty rows.
|
13
|
+
|
5
14
|
== 1.0.0
|
6
15
|
|
7
16
|
* Fixed FasterCSV.rewind() to reset the FasterCSV.lineno() counter.
|
data/TODO
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
# csv_converters.rb
|
4
|
+
#
|
5
|
+
# Created by James Edward Gray II on 2006-11-05.
|
6
|
+
# Copyright 2006 Gray Productions. All rights reserved.
|
7
|
+
|
8
|
+
require "faster_csv"
|
9
|
+
|
10
|
+
# convert a specific column
|
11
|
+
options = {
|
12
|
+
:headers => true,
|
13
|
+
:header_converters => :symbol,
|
14
|
+
:converters => [
|
15
|
+
lambda { |f, info| info.index.zero? ? f.to_i : f },
|
16
|
+
lambda { |f, info| info.header == :floats ? f.to_f : f }
|
17
|
+
]
|
18
|
+
}
|
19
|
+
table = FCSV(DATA, options) { |csv| csv.read }
|
20
|
+
|
21
|
+
table[:ints] # => [1, 2, 3]
|
22
|
+
table[:floats] # => [1.0, 2.0, 3.0]
|
23
|
+
|
24
|
+
__END__
|
25
|
+
ints,floats
|
26
|
+
1,1.000
|
27
|
+
2,2
|
28
|
+
3,3.0
|
data/lib/faster_csv.rb
CHANGED
@@ -75,7 +75,7 @@ require "stringio"
|
|
75
75
|
#
|
76
76
|
class FasterCSV
|
77
77
|
# The version of the installed library.
|
78
|
-
VERSION = "1.
|
78
|
+
VERSION = "1.1.0".freeze
|
79
79
|
|
80
80
|
#
|
81
81
|
# A FasterCSV::Row is part Array and part Hash. It retains an order for the
|
@@ -95,6 +95,13 @@ class FasterCSV
|
|
95
95
|
# FasterCSV::Row.header_row?() and FasterCSV::Row.field_row?(), that this is
|
96
96
|
# a header row. Otherwise, the row is assumes to be a field row.
|
97
97
|
#
|
98
|
+
# A FasterCSV::Row object supports the following Array methods through
|
99
|
+
# delegation:
|
100
|
+
#
|
101
|
+
# * empty?()
|
102
|
+
# * length()
|
103
|
+
# * size()
|
104
|
+
#
|
98
105
|
def initialize(headers, fields, header_row = false)
|
99
106
|
@header_row = header_row
|
100
107
|
|
@@ -109,6 +116,11 @@ class FasterCSV
|
|
109
116
|
# Internal data format used to compare equality.
|
110
117
|
attr_reader :row
|
111
118
|
protected :row
|
119
|
+
|
120
|
+
### Array Delegation ###
|
121
|
+
|
122
|
+
extend Forwardable
|
123
|
+
def_delegators :@row, :empty?, :length, :size
|
112
124
|
|
113
125
|
# Returns +true+ if this is a header row.
|
114
126
|
def header_row?
|
@@ -367,6 +379,13 @@ class FasterCSV
|
|
367
379
|
# to be FasterCSV::Row objects. All rows are assumed to have the same
|
368
380
|
# headers.
|
369
381
|
#
|
382
|
+
# A FasterCSV::Table object supports the following Array methods through
|
383
|
+
# delegation:
|
384
|
+
#
|
385
|
+
# * empty?()
|
386
|
+
# * length()
|
387
|
+
# * size()
|
388
|
+
#
|
370
389
|
def initialize(array_of_rows)
|
371
390
|
@table = array_of_rows
|
372
391
|
@mode = :col_or_row
|
@@ -378,6 +397,11 @@ class FasterCSV
|
|
378
397
|
# Internal data format used to compare equality.
|
379
398
|
attr_reader :table
|
380
399
|
protected :table
|
400
|
+
|
401
|
+
### Array Delegation ###
|
402
|
+
|
403
|
+
extend Forwardable
|
404
|
+
def_delegators :@table, :empty?, :length, :size
|
381
405
|
|
382
406
|
#
|
383
407
|
# Returns a duplicate table object, in column mode. This is handy for
|
@@ -749,6 +773,7 @@ class FasterCSV
|
|
749
773
|
# <b><tt>:headers</tt></b>:: +false+
|
750
774
|
# <b><tt>:return_headers</tt></b>:: +false+
|
751
775
|
# <b><tt>:header_converters</tt></b>:: +nil+
|
776
|
+
# <b><tt>:skip_blanks</tt></b>:: +false+
|
752
777
|
#
|
753
778
|
DEFAULT_OPTIONS = { :col_sep => ",",
|
754
779
|
:row_sep => :auto,
|
@@ -756,7 +781,8 @@ class FasterCSV
|
|
756
781
|
:unconverted_fields => nil,
|
757
782
|
:headers => false,
|
758
783
|
:return_headers => false,
|
759
|
-
:header_converters => nil
|
784
|
+
:header_converters => nil,
|
785
|
+
:skip_blanks => false }.freeze
|
760
786
|
|
761
787
|
#
|
762
788
|
# This method will build a drop-in replacement for many of the standard CSV
|
@@ -1263,6 +1289,9 @@ class FasterCSV
|
|
1263
1289
|
# <tt>:converters</tt> save that the
|
1264
1290
|
# conversions are only made to header
|
1265
1291
|
# rows.
|
1292
|
+
# <b><tt>:skip_blanks</tt></b>:: When set to a +true+ value, FasterCSV
|
1293
|
+
# will skip over any rows with no
|
1294
|
+
# content.
|
1266
1295
|
#
|
1267
1296
|
# See FasterCSV::DEFAULT_OPTIONS for the default settings.
|
1268
1297
|
#
|
@@ -1289,14 +1318,14 @@ class FasterCSV
|
|
1289
1318
|
@lineno = 0
|
1290
1319
|
end
|
1291
1320
|
|
1292
|
-
### IO and StringIO Delegation ###
|
1293
|
-
|
1294
1321
|
#
|
1295
1322
|
# The line number of the last row read from this file. Fields with nested
|
1296
1323
|
# line-end characters will not affect this count.
|
1297
1324
|
#
|
1298
1325
|
attr_reader :lineno
|
1299
1326
|
|
1327
|
+
### IO and StringIO Delegation ###
|
1328
|
+
|
1300
1329
|
extend Forwardable
|
1301
1330
|
def_delegators :@io, :binmode, :close, :close_read, :close_write, :closed?,
|
1302
1331
|
:eof, :eof?, :fcntl, :fileno, :flush, :fsync, :ioctl,
|
@@ -1432,11 +1461,11 @@ class FasterCSV
|
|
1432
1461
|
# handle headers not based on document content
|
1433
1462
|
if header_row? and @return_headers and
|
1434
1463
|
[Array, String].include? @use_headers.class
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1464
|
+
if @unconverted_fields
|
1465
|
+
return add_unconverted_fields(parse_headers, Array.new)
|
1466
|
+
else
|
1467
|
+
return parse_headers
|
1468
|
+
end
|
1440
1469
|
end
|
1441
1470
|
|
1442
1471
|
# begin with a blank line, so we can always add to it
|
@@ -1459,8 +1488,13 @@ class FasterCSV
|
|
1459
1488
|
#
|
1460
1489
|
if parse.empty?
|
1461
1490
|
@lineno += 1
|
1462
|
-
if @
|
1491
|
+
if @skip_blanks
|
1492
|
+
line = ""
|
1493
|
+
next
|
1494
|
+
elsif @unconverted_fields
|
1463
1495
|
return add_unconverted_fields(Array.new, Array.new)
|
1496
|
+
elsif @use_headers
|
1497
|
+
return FasterCSV::Row.new(Array.new, Array.new)
|
1464
1498
|
else
|
1465
1499
|
return Array.new
|
1466
1500
|
end
|
@@ -1581,6 +1615,9 @@ class FasterCSV
|
|
1581
1615
|
|
1582
1616
|
# Pre-compiles parsers and stores them by name for access during reads.
|
1583
1617
|
def init_parsers(options)
|
1618
|
+
# store the parser behaviors
|
1619
|
+
@skip_blanks = options.delete(:skip_blanks)
|
1620
|
+
|
1584
1621
|
# prebuild Regexps for faster parsing
|
1585
1622
|
@parsers = {
|
1586
1623
|
:leading_fields =>
|
data/test/tc_features.rb
CHANGED
@@ -98,23 +98,37 @@ class TestFasterCSVFeatures < Test::Unit::TestCase
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
-
def
|
102
|
-
|
101
|
+
def test_skip_blanks
|
102
|
+
assert_equal(4, @csv.to_a.size)
|
103
|
+
|
104
|
+
@csv = FasterCSV.new(@sample_data, :skip_blanks => true)
|
105
|
+
|
106
|
+
count = 0
|
107
|
+
@csv.each do |row|
|
108
|
+
count += 1
|
109
|
+
assert_equal("line", row.first)
|
110
|
+
end
|
111
|
+
assert_equal(3, count)
|
112
|
+
end
|
113
|
+
|
114
|
+
# reported by Kev Jackson
|
115
|
+
def test_failing_to_escape_col_sep_bug_fix
|
103
116
|
assert_nothing_raised(Exception) do
|
104
117
|
FasterCSV.new(String.new, :col_sep => "|")
|
105
118
|
end
|
106
|
-
|
107
|
-
|
119
|
+
end
|
120
|
+
|
121
|
+
# reported by Chris Roos
|
122
|
+
def test_failing_to_reset_headers_in_rewind_bug_fix
|
108
123
|
csv = FasterCSV.new( "forename,surname", :headers => true,
|
109
124
|
:return_headers => true )
|
110
125
|
csv.each { |row| assert row.header_row? }
|
111
126
|
csv.rewind
|
112
127
|
csv.each { |row| assert row.header_row? }
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
#
|
128
|
+
end
|
129
|
+
|
130
|
+
# reported by Dave Burt
|
131
|
+
def test_leading_empty_fields_with_multibyte_col_sep_bug_fix
|
118
132
|
data = <<-END_DATA.gsub(/^\s+/, "")
|
119
133
|
<=><=>A<=>B<=>C
|
120
134
|
1<=>2<=>3
|
data/test/tc_headers.rb
CHANGED
@@ -224,4 +224,39 @@ class TestFasterCSVHeaders < Test::Unit::TestCase
|
|
224
224
|
|
225
225
|
assert_instance_of(FasterCSV::Table, csv)
|
226
226
|
end
|
227
|
+
|
228
|
+
def test_skip_blanks
|
229
|
+
@data = <<-END_CSV.gsub(/^ +/, "")
|
230
|
+
|
231
|
+
|
232
|
+
A,B,C
|
233
|
+
|
234
|
+
1,2,3
|
235
|
+
|
236
|
+
|
237
|
+
|
238
|
+
END_CSV
|
239
|
+
|
240
|
+
expected = [%w[1 2 3]]
|
241
|
+
FasterCSV.parse(@data, :headers => true, :skip_blanks => true) do |row|
|
242
|
+
assert_equal(expected.shift, row.fields)
|
243
|
+
end
|
244
|
+
|
245
|
+
expected = [%w[A B C], %w[1 2 3]]
|
246
|
+
FasterCSV.parse( @data,
|
247
|
+
:headers => true,
|
248
|
+
:return_headers => true,
|
249
|
+
:skip_blanks => true ) do |row|
|
250
|
+
assert_equal(expected.shift, row.fields)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def test_blank_row_bug_fix
|
255
|
+
@data += "\n#{@data}" # add a blank row
|
256
|
+
|
257
|
+
# ensure that everything returned is a Row object
|
258
|
+
FasterCSV.parse(@data, :headers => true) do |row|
|
259
|
+
assert_instance_of(FasterCSV::Row, row)
|
260
|
+
end
|
261
|
+
end
|
227
262
|
end
|
data/test/tc_row.rb
CHANGED
@@ -279,4 +279,10 @@ class TestFasterCSVRow < Test::Unit::TestCase
|
|
279
279
|
assert_equal( "1|2|3|4|\r\n",
|
280
280
|
@row.to_csv(:col_sep => "|", :row_sep => "\r\n") )
|
281
281
|
end
|
282
|
+
|
283
|
+
def test_array_delegation
|
284
|
+
assert(!@row.empty?, "Row was empty.")
|
285
|
+
|
286
|
+
assert_equal([@row.headers.size, @row.fields.size].max, @row.size)
|
287
|
+
end
|
282
288
|
end
|
data/test/tc_table.rb
CHANGED
@@ -382,4 +382,10 @@ class TestFasterCSVTable < Test::Unit::TestCase
|
|
382
382
|
assert_equal([[1, 3], [4, 6], [7, 9]], @table.by_col.values_at(0, 2))
|
383
383
|
assert_equal(@rows.values_at(0, 2), @table.values_at(0, 2))
|
384
384
|
end
|
385
|
+
|
386
|
+
def test_array_delegation
|
387
|
+
assert(!@table.empty?, "Table was empty.")
|
388
|
+
|
389
|
+
assert_equal(@rows.size, @table.size)
|
390
|
+
end
|
385
391
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: fastercsv
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.
|
7
|
-
date: 2006-
|
6
|
+
version: 1.1.0
|
7
|
+
date: 2006-12-12 00:00:00 -06:00
|
8
8
|
summary: FasterCSV is CSV, but faster, smaller, and cleaner.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -41,6 +41,7 @@ files:
|
|
41
41
|
- test/tc_speed.rb
|
42
42
|
- test/tc_table.rb
|
43
43
|
- test/ts_all.rb
|
44
|
+
- examples/csv_converters.rb
|
44
45
|
- examples/csv_filter.rb
|
45
46
|
- examples/csv_reading.rb
|
46
47
|
- examples/csv_table.rb
|