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 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
@@ -3,4 +3,4 @@
3
3
  The following is a list of planned expansions for FasterCSV, in no particular
4
4
  order.
5
5
 
6
- * Rent this space!
6
+ * Rent this space...
@@ -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.0.0".freeze
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 }.freeze
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
- if @unconverted_fields
1436
- return add_unconverted_fields(parse_headers, Array.new)
1437
- else
1438
- return parse_headers
1439
- end
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 @unconverted_fields
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 test_bug_fixes
102
- # failing to escape <tt>:col_sep</tt> (reported by Kev Jackson)
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
- # failing to reset header behavior on rewind() (reported by Chris Roos)
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
- # leading empty fields with multibyte col_sep raises MalformedCSVError
116
- # (reported by Dave Burt)
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.0.0
7
- date: 2006-11-05 00:00:00 -06:00
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