fastercsv 1.0.0 → 1.1.0
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/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
|