csv 3.1.3 → 3.1.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 287ad200c61c1756e9386a9d910c9e16c3f876e3860d7a147d82ef3d2017ca72
4
- data.tar.gz: 98d1b16dfad00c08f5b07e0beb0d535c3e1777d9e01ecca9a2d21c2e5665eefb
3
+ metadata.gz: dad2154faebc0d08b471d1f5624752997374f8472dc2408756d7a78efb87d9c9
4
+ data.tar.gz: 9c6e071bcf07ab25aa0ff068030b42dbb47968d9f9e7aa5b04a1ff33ed12c2ea
5
5
  SHA512:
6
- metadata.gz: f0d55f65f559d083f570a3f72f27d5123c961cad244ea6b0b098c9f3e806474a5a8fc4335ada22f9031fa37664c05229428c6630ecc800709a7e0c90b72514ab
7
- data.tar.gz: 97f936a5e13547f9c362c66617f36ae9e3e84c7e611b105ea40b0f59442cec165d9382aa34a6c9eebb16b365c2fa12620d839396a2041ad0a97c878ed86a1da3
6
+ metadata.gz: 4da5b31e15b5c215d1f346c330a3d86ebea640cc4af4c33bd0aa238ac4b9b5cde2c72fc7edcd045de60f4cacb49a5ed8cbbf8a963a1a0750d16f5472faa95c1c
7
+ data.tar.gz: 83ee56fae5acb6afdb8d722e0c0182f17112a157a2ab6ad0b30a60d524fd146850a1afe360217c2e2b5af36335668716289612ae1817d98c77b2ea2c5d610240
data/NEWS.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # News
2
2
 
3
+ ## 3.1.4 - 2020-05-17
4
+
5
+ ### Improvements
6
+
7
+ * Improved document.
8
+ [GitHub#122][Patch by Burdette Lamar]
9
+
10
+ * Stopped to dropping stack trace for exception caused by
11
+ `CSV.parse_line`.
12
+ [GitHub#120][Reported by Kyle d'Oliveira]
13
+
14
+ ### Fixes
15
+
16
+ * Fixed a bug that `:write_nil_value` or `:write_empty_value` don't
17
+ work with non `String` objects.
18
+ [GitHub#123][Reported by asm256]
19
+
20
+ ### Thanks
21
+
22
+ * Burdette Lamar
23
+
24
+ * asm256
25
+
26
+ * Kyle d'Oliveira
27
+
3
28
  ## 3.1.3 - 2020-05-09
4
29
 
5
30
  ### Improvements
data/lib/csv.rb CHANGED
@@ -103,7 +103,6 @@ require_relative "csv/writer"
103
103
 
104
104
  using CSV::MatchP if CSV.const_defined?(:MatchP)
105
105
 
106
- #
107
106
  # This class provides a complete interface to CSV files and data. It offers
108
107
  # tools to enable you to read and write to and from Strings or IO objects, as
109
108
  # needed.
@@ -179,9 +178,89 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
179
178
  # CSV($stderr) { |csv_err| csv_err << %w{my data here} } # to $stderr
180
179
  # CSV($stdin) { |csv_in| csv_in.each { |row| p row } } # from $stdin
181
180
  #
182
- # == Data Conversion
181
+ # == Options
182
+ #
183
+ # The default values for options are:
184
+ # DEFAULT_OPTIONS = {
185
+ # # For both parsing and generating.
186
+ # col_sep: ",",
187
+ # row_sep: :auto,
188
+ # quote_char: '"',
189
+ # # For parsing.
190
+ # field_size_limit: nil,
191
+ # converters: nil,
192
+ # unconverted_fields: nil,
193
+ # headers: false,
194
+ # return_headers: false,
195
+ # header_converters: nil,
196
+ # skip_blanks: false,
197
+ # skip_lines: nil,
198
+ # liberal_parsing: false,
199
+ # nil_value: nil,
200
+ # empty_value: "",
201
+ # # For generating.
202
+ # write_headers: nil,
203
+ # quote_empty: true,
204
+ # force_quotes: false,
205
+ # write_converters: nil,
206
+ # write_nil_value: nil,
207
+ # write_empty_value: "",
208
+ # strip: false,
209
+ # }
210
+ #
211
+ # === Options for Parsing
212
+ #
213
+ # :include: ../doc/col_sep.rdoc
214
+ #
215
+ # :include: ../doc/row_sep.rdoc
216
+ #
217
+ # :include: ../doc/quote_char.rdoc
218
+ #
219
+ # :include: ../doc/field_size_limit.rdoc
220
+ #
221
+ # :include: ../doc/converters.rdoc
222
+ #
223
+ # :include: ../doc/unconverted_fields.rdoc
224
+ #
225
+ # :include: ../doc/headers.rdoc
226
+ #
227
+ # :include: ../doc/return_headers.rdoc
228
+ #
229
+ # :include: ../doc/header_converters.rdoc
230
+ #
231
+ # :include: ../doc/skip_blanks.rdoc
232
+ #
233
+ # :include: ../doc/skip_lines.rdoc
234
+ #
235
+ # :include: ../doc/liberal_parsing.rdoc
236
+ #
237
+ # :include: ../doc/nil_value.rdoc
238
+ #
239
+ # :include: ../doc/empty_value.rdoc
240
+ #
241
+ # === Options for Generating
242
+ #
243
+ # :include: ../doc/col_sep.rdoc
244
+ #
245
+ # :include: ../doc/row_sep.rdoc
246
+ #
247
+ # :include: ../doc/quote_char.rdoc
248
+ #
249
+ # :include: ../doc/write_headers.rdoc
250
+ #
251
+ # :include: ../doc/force_quotes.rdoc
183
252
  #
184
- # === CSV with headers
253
+ # :include: ../doc/quote_empty.rdoc
254
+ #
255
+ # :include: ../doc/write_converters.rdoc
256
+ #
257
+ # :include: ../doc/write_nil_value.rdoc
258
+ #
259
+ # :include: ../doc/write_empty_value.rdoc
260
+ #
261
+ # :include: ../doc/strip.rdoc
262
+ #
263
+ # == CSV with headers
185
264
  #
186
265
  # CSV allows to specify column names of CSV file, whether they are in data, or
187
266
  # provided separately. If headers are specified, reading methods return an instance
@@ -203,22 +282,205 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
203
282
  # data = CSV.parse('Bob,Engineering,1000', headers: %i[name department salary])
204
283
  # data.first #=> #<CSV::Row name:"Bob" department:"Engineering" salary:"1000">
205
284
  #
206
- # === Typed data reading
207
- #
208
- # CSV allows to provide a set of data _converters_ e.g. transformations to try on input
209
- # data. Converter could be a symbol from CSV::Converters constant's keys, or lambda.
210
- #
211
- # # Without any converters:
212
- # CSV.parse('Bob,2018-03-01,100')
213
- # #=> [["Bob", "2018-03-01", "100"]]
214
- #
215
- # # With built-in converters:
216
- # CSV.parse('Bob,2018-03-01,100', converters: %i[numeric date])
217
- # #=> [["Bob", #<Date: 2018-03-01>, 100]]
218
- #
219
- # # With custom converters:
220
- # CSV.parse('Bob,2018-03-01,100', converters: [->(v) { Time.parse(v) rescue v }])
221
- # #=> [["Bob", 2018-03-01 00:00:00 +0200, "100"]]
285
+ # == \CSV \Converters
286
+ #
287
+ # By default, each field parsed by \CSV is formed into a \String.
288
+ # You can use a _converter_ to convert certain fields into other Ruby objects.
289
+ #
290
+ # When you specify a converter for parsing,
291
+ # each parsed field is passed to the converter;
292
+ # its return value becomes the new value for the field.
293
+ # A converter might, for example, convert an integer embedded in a \String
294
+ # into a true \Integer.
295
+ # (In fact, that's what built-in field converter +:integer+ does.)
296
+ #
297
+ # There are additional built-in \converters, and custom \converters are also supported.
298
+ #
299
+ # All \converters try to transcode fields to UTF-8 before converting.
300
+ # The conversion will fail if the data cannot be transcoded, leaving the field unchanged.
301
+ #
302
+ # === Field \Converters
303
+ #
304
+ # There are three ways to use field \converters;
305
+ # these examples use built-in field converter +:integer+,
306
+ # which converts each parsed integer string to a true \Integer.
307
+ #
308
+ # Option +converters+ with a singleton parsing method:
309
+ # ary = CSV.parse_line('0,1,2', converters: :integer)
310
+ # ary # => [0, 1, 2]
311
+ #
312
+ # Option +converters+ with a new \CSV instance:
313
+ # csv = CSV.new('0,1,2', converters: :integer)
314
+ # # Field converters in effect:
315
+ # csv.converters # => [:integer]
316
+ # csv.shift # => [0, 1, 2]
317
+ #
318
+ # Method #convert adds a field converter to a \CSV instance:
319
+ # csv = CSV.new('0,1,2')
320
+ # # Add a converter.
321
+ # csv.convert(:integer)
322
+ # csv.converters # => [:integer]
323
+ # csv.shift # => [0, 1, 2]
324
+ #
325
+ # ---
326
+ #
327
+ # The built-in field \converters are in \Hash CSV::Converters.
328
+ # The \Symbol keys there are the names of the \converters:
329
+ #
330
+ # CSV::Converters.keys # => [:integer, :float, :numeric, :date, :date_time, :all]
331
+ #
332
+ # Converter +:integer+ converts each field that +Integer()+ accepts:
333
+ # data = '0,1,2,x'
334
+ # # Without the converter
335
+ # csv = CSV.parse_line(data)
336
+ # csv # => ["0", "1", "2", "x"]
337
+ # # With the converter
338
+ # csv = CSV.parse_line(data, converters: :integer)
339
+ # csv # => [0, 1, 2, "x"]
340
+ #
341
+ # Converter +:float+ converts each field that +Float()+ accepts:
342
+ # data = '1.0,3.14159,x'
343
+ # # Without the converter
344
+ # csv = CSV.parse_line(data)
345
+ # csv # => ["1.0", "3.14159", "x"]
346
+ # # With the converter
347
+ # csv = CSV.parse_line(data, converters: :float)
348
+ # csv # => [1.0, 3.14159, "x"]
349
+ #
350
+ # Converter +:numeric+ converts with both +:integer+ and +:float+..
351
+ #
352
+ # Converter +:date+ converts each field that +Date::parse()+ accepts:
353
+ # data = '2001-02-03,x'
354
+ # # Without the converter
355
+ # csv = CSV.parse_line(data)
356
+ # csv # => ["2001-02-03", "x"]
357
+ # # With the converter
358
+ # csv = CSV.parse_line(data, converters: :date)
359
+ # csv # => [#<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>, "x"]
360
+ #
361
+ # Converter +:date_time+ converts each field that +DateTime::parse() accepts:
362
+ # data = '2020-05-07T14:59:00-05:00,x'
363
+ # # Without the converter
364
+ # csv = CSV.parse_line(data)
365
+ # csv # => ["2020-05-07T14:59:00-05:00", "x"]
366
+ # # With the converter
367
+ # csv = CSV.parse_line(data, converters: :date_time)
368
+ # csv # => [#<DateTime: 2020-05-07T14:59:00-05:00 ((2458977j,71940s,0n),-18000s,2299161j)>, "x"]
369
+ #
370
+ # Converter +:numeric+ converts with both +:date_time+ and +:numeric+..
371
+ #
372
+ # As seen above, method #convert adds \converters to a \CSV instance,
373
+ # and method #converters returns an \Array of the \converters in effect:
374
+ # csv = CSV.new('0,1,2')
375
+ # csv.converters # => []
376
+ # csv.convert(:integer)
377
+ # csv.converters # => [:integer]
378
+ # csv.convert(:date)
379
+ # csv.converters # => [:integer, :date]
380
+ #
381
+ # You can add a custom field converter to \Hash CSV::Converters:
382
+ # strip_converter = proc {|field| field.strip}
383
+ # CSV::Converters[:strip] = strip_converter
384
+ # CSV::Converters.keys # => [:integer, :float, :numeric, :date, :date_time, :all, :strip]
385
+ #
386
+ # Then use it to convert fields:
387
+ # str = ' foo , 0 '
388
+ # ary = CSV.parse_line(str, converters: :strip)
389
+ # ary # => ["foo", "0"]
390
+ #
391
+ # See {Custom Converters}[#class-CSV-label-Custom+Converters].
392
+ #
393
+ # === Header \Converters
394
+ #
395
+ # Header converters operate only on headers (and not on other rows).
396
+ #
397
+ # There are three ways to use header \converters;
398
+ # these examples use built-in header converter +:dowhcase+,
399
+ # which downcases each parsed header.
400
+ #
401
+ # Option +header_converters+ with a singleton parsing method:
402
+ # str = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
403
+ # tbl = CSV.parse(str, headers: true, header_converters: :downcase)
404
+ # tbl.class # => CSV::Table
405
+ # tbl.headers # => ["name", "count"]
406
+ #
407
+ # Option +header_converters+ with a new \CSV instance:
408
+ # csv = CSV.new(str, header_converters: :downcase)
409
+ # # Header converters in effect:
410
+ # csv.header_converters # => [:downcase]
411
+ # tbl = CSV.parse(str, headers: true)
412
+ # tbl.headers # => ["Name", "Count"]
413
+ #
414
+ # Method #header_convert adds a header converter to a \CSV instance:
415
+ # csv = CSV.new(str)
416
+ # # Add a header converter.
417
+ # csv.header_convert(:downcase)
418
+ # csv.header_converters # => [:downcase]
419
+ # tbl = CSV.parse(str, headers: true)
420
+ # tbl.headers # => ["Name", "Count"]
421
+ #
422
+ # ---
423
+ #
424
+ # The built-in header \converters are in \Hash CSV::Converters.
425
+ # The \Symbol keys there are the names of the \converters:
426
+ #
427
+ # CSV::HeaderConverters.keys # => [:downcase, :symbol]
428
+ #
429
+ # Converter +:downcase+ converts each header by downcasing it:
430
+ # str = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
431
+ # tbl = CSV.parse(str, headers: true, header_converters: :downcase)
432
+ # tbl.class # => CSV::Table
433
+ # tbl.headers # => ["name", "count"]
434
+ #
435
+ # Converter +:symbol+ by making it into a \Symbol:
436
+ # str = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
437
+ # tbl = CSV.parse(str, headers: true, header_converters: :symbol)
438
+ # tbl.headers # => [:name, :count]
439
+ # Details:
440
+ # - Strips leading and trailing whitespace.
441
+ # - Downcases the header.
442
+ # - Replaces embedded spaces with underscores.
443
+ # - Removes non-word characters.
444
+ # - Makes the string into a \Symbol.
445
+ #
446
+ # You can add a custom header converter to \Hash CSV::HeaderConverters:
447
+ # strip_converter = proc {|field| field.strip}
448
+ # CSV::HeaderConverters[:strip] = strip_converter
449
+ # CSV::HeaderConverters.keys # => [:downcase, :symbol, :strip]
450
+ #
451
+ # Then use it to convert headers:
452
+ # str = " Name , Value \nfoo,0\nbar,1\nbaz,2"
453
+ # tbl = CSV.parse(str, headers: true, header_converters: :strip)
454
+ # tbl.headers # => ["Name", "Value"]
455
+ #
456
+ # See {Custom Converters}[#class-CSV-label-Custom+Converters].
457
+ #
458
+ # === Custom \Converters
459
+ #
460
+ # You can define custom \converters.
461
+ #
462
+ # The \converter is a \Proc that is called with two arguments,
463
+ # \String +field+ and CSV::FieldInfo +field_info+;
464
+ # it returns a \String that will become the field value:
465
+ # converter = proc {|field, field_info| <some_string> }
466
+ #
467
+ # To illustrate:
468
+ # converter = proc {|field, field_info| p [field, field_info]; field}
469
+ # ary = CSV.parse_line('foo,0', converters: converter)
470
+ #
471
+ # Produces:
472
+ # ["foo", #<struct CSV::FieldInfo index=0, line=1, header=nil>]
473
+ # ["0", #<struct CSV::FieldInfo index=1, line=1, header=nil>]
474
+ #
475
+ # In each of the output lines:
476
+ # - The first \Array element is the passed \String field.
477
+ # - The second is a \FieldInfo structure containing information about the field:
478
+ # - The 0-based column index.
479
+ # - The 1-based line number.
480
+ # - The header for the column, if available.
481
+ #
482
+ # If the \converter does not need +field_info+, it can be omitted:
483
+ # converter = proc {|field| ... }
222
484
  #
223
485
  # == CSV and Character Encodings (M17n or Multilingualization)
224
486
  #
@@ -380,29 +642,13 @@ class CSV
380
642
  gsub(/\s+/, "_").to_sym
381
643
  }
382
644
  }
383
-
384
- #
385
- # The options used when no overrides are given by calling code. They are:
386
- #
387
- # <b><tt>:col_sep</tt></b>:: <tt>","</tt>
388
- # <b><tt>:row_sep</tt></b>:: <tt>:auto</tt>
389
- # <b><tt>:quote_char</tt></b>:: <tt>'"'</tt>
390
- # <b><tt>:field_size_limit</tt></b>:: +nil+
391
- # <b><tt>:converters</tt></b>:: +nil+
392
- # <b><tt>:unconverted_fields</tt></b>:: +nil+
393
- # <b><tt>:headers</tt></b>:: +false+
394
- # <b><tt>:return_headers</tt></b>:: +false+
395
- # <b><tt>:header_converters</tt></b>:: +nil+
396
- # <b><tt>:skip_blanks</tt></b>:: +false+
397
- # <b><tt>:force_quotes</tt></b>:: +false+
398
- # <b><tt>:skip_lines</tt></b>:: +nil+
399
- # <b><tt>:liberal_parsing</tt></b>:: +false+
400
- # <b><tt>:quote_empty</tt></b>:: +true+
401
- #
645
+ # Default values for method options.
402
646
  DEFAULT_OPTIONS = {
647
+ # For both parsing and generating.
403
648
  col_sep: ",",
404
649
  row_sep: :auto,
405
650
  quote_char: '"',
651
+ # For parsing.
406
652
  field_size_limit: nil,
407
653
  converters: nil,
408
654
  unconverted_fields: nil,
@@ -410,10 +656,18 @@ class CSV
410
656
  return_headers: false,
411
657
  header_converters: nil,
412
658
  skip_blanks: false,
413
- force_quotes: false,
414
659
  skip_lines: nil,
415
660
  liberal_parsing: false,
661
+ nil_value: nil,
662
+ empty_value: "",
663
+ # For generating.
664
+ write_headers: nil,
416
665
  quote_empty: true,
666
+ force_quotes: false,
667
+ write_converters: nil,
668
+ write_nil_value: nil,
669
+ write_empty_value: "",
670
+ strip: false,
417
671
  }.freeze
418
672
 
419
673
  class << self
@@ -423,6 +677,9 @@ class CSV
423
677
  # the same +data+ object (tested by Object#object_id()) with the same
424
678
  # +options+.
425
679
  #
680
+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
681
+ # and {Options for Generating}[#class-CSV-label-Options+for+Generating].
682
+ #
426
683
  # If a block is given, the instance is passed to the block and the return
427
684
  # value becomes the return value of the block.
428
685
  #
@@ -463,6 +720,9 @@ class CSV
463
720
  # <tt>:out_</tt> or <tt>:output_</tt> affect only +output+. All other keys
464
721
  # are assigned to both objects.
465
722
  #
723
+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
724
+ # and {Options for Generating}[#class-CSV-label-Options+for+Generating].
725
+ #
466
726
  # The <tt>:output_row_sep</tt> +option+ defaults to
467
727
  # <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>).
468
728
  #
@@ -496,6 +756,8 @@ class CSV
496
756
  # pass a +path+ and any +options+ you wish to set for the read. Each row of
497
757
  # file will be passed to the provided +block+ in turn.
498
758
  #
759
+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
760
+ #
499
761
  # The +options+ parameter can be anything CSV::new() understands. This method
500
762
  # also understands an additional <tt>:encoding</tt> parameter that you can use
501
763
  # to specify the Encoding of the data in the file to be read. You must provide
@@ -525,10 +787,11 @@ class CSV
525
787
  # Note that a passed String *is* modified by this method. Call dup() before
526
788
  # passing if you need a new String.
527
789
  #
528
- # The +options+ parameter can be anything CSV::new() understands. This method
529
- # understands an additional <tt>:encoding</tt> parameter when not passed a
530
- # String to set the base Encoding for the output. CSV needs this hint if you
531
- # plan to output non-ASCII compatible data.
790
+ # See {Options for Generating}[#class-CSV-label-Options+for+Generating].
791
+ #
792
+ # This method has one additional option: <tt>:encoding</tt>,
793
+ # which sets the base Encoding for the output if no no +str+ is specified.
794
+ # CSV needs this hint if you plan to output non-ASCII compatible data.
532
795
  #
533
796
  def generate(str=nil, **options)
534
797
  encoding = options[:encoding]
@@ -550,8 +813,9 @@ class CSV
550
813
  # This method is a shortcut for converting a single row (Array) into a CSV
551
814
  # String.
552
815
  #
553
- # The +options+ parameter can be anything CSV::new() understands. This method
554
- # understands an additional <tt>:encoding</tt> parameter to set the base
816
+ # See {Options for Generating}[#class-CSV-label-Options+for+Generating].
817
+ #
818
+ # This method accepts an additional option, <tt>:encoding</tt>, which sets the base
555
819
  # Encoding for the output. This method will try to guess your Encoding from
556
820
  # the first non-+nil+ field in +row+, if possible, but you may need to use
557
821
  # this parameter as a backup plan.
@@ -581,8 +845,9 @@ class CSV
581
845
  # as the primary interface for writing a CSV file.
582
846
  #
583
847
  # You must pass a +filename+ and may optionally add a +mode+ for Ruby's
584
- # open(). You may also pass an optional Hash containing any +options+
585
- # CSV::new() understands as the final argument.
848
+ # open().
849
+ #
850
+ # See {Options for Generating}[#class-CSV-label-Options+for+Generating].
586
851
  #
587
852
  # This method works like Ruby's open() call, in that it will pass a CSV object
588
853
  # to a provided block and close it when the block terminates, or it will
@@ -674,8 +939,8 @@ class CSV
674
939
  # provide a +block+ which will be called with each row of the String in turn,
675
940
  # or just use the returned Array of Arrays (when no +block+ is given).
676
941
  #
677
- # You pass your +str+ to read from, and an optional +options+ containing
678
- # anything CSV::new() understands.
942
+ # You pass your +str+ to read from, and an optional +options+.
943
+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
679
944
  #
680
945
  def parse(str, **options, &block)
681
946
  csv = new(str, **options)
@@ -695,15 +960,18 @@ class CSV
695
960
  # an Array. Note that if +line+ contains multiple rows, anything beyond the
696
961
  # first row is ignored.
697
962
  #
698
- # The +options+ parameter can be anything CSV::new() understands.
963
+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
699
964
  #
700
965
  def parse_line(line, **options)
701
- new(line, **options).shift
966
+ new(line, **options).each.first
702
967
  end
703
968
 
704
969
  #
705
970
  # Use to slurp a CSV file into an Array of Arrays. Pass the +path+ to the
706
- # file and any +options+ CSV::new() understands. This method also understands
971
+ # file and +options+.
972
+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
973
+ #
974
+ # This method also understands
707
975
  # an additional <tt>:encoding</tt> parameter that you can use to specify the
708
976
  # Encoding of the data in the file to be read. You must provide this unless
709
977
  # your data is in Encoding::default_external(). CSV will use this to determine
@@ -728,6 +996,7 @@ class CSV
728
996
  # converters: :numeric,
729
997
  # header_converters: :symbol }.merge(options) )
730
998
  #
999
+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
731
1000
  def table(path, **options)
732
1001
  default_options = {
733
1002
  headers: true,
@@ -750,171 +1019,8 @@ class CSV
750
1019
  # reading). If you want it at the end (for writing), use CSV::generate().
751
1020
  # If you want any other positioning, pass a preset StringIO object instead.
752
1021
  #
753
- # You may set any reading and/or writing preferences in the +options+ Hash.
754
- # Available options are:
755
- #
756
- # <b><tt>:col_sep</tt></b>:: The String placed between each field.
757
- # This String will be transcoded into
758
- # the data's Encoding before parsing.
759
- # <b><tt>:row_sep</tt></b>:: The String appended to the end of each
760
- # row. This can be set to the special
761
- # <tt>:auto</tt> setting, which requests
762
- # that CSV automatically discover this
763
- # from the data. Auto-discovery reads
764
- # ahead in the data looking for the next
765
- # <tt>"\r\n"</tt>, <tt>"\n"</tt>, or
766
- # <tt>"\r"</tt> sequence. A sequence
767
- # will be selected even if it occurs in
768
- # a quoted field, assuming that you
769
- # would have the same line endings
770
- # there. If none of those sequences is
771
- # found, +data+ is <tt>ARGF</tt>,
772
- # <tt>STDIN</tt>, <tt>STDOUT</tt>, or
773
- # <tt>STDERR</tt>, or the stream is only
774
- # available for output, the default
775
- # <tt>$INPUT_RECORD_SEPARATOR</tt>
776
- # (<tt>$/</tt>) is used. Obviously,
777
- # discovery takes a little time. Set
778
- # manually if speed is important. Also
779
- # note that IO objects should be opened
780
- # in binary mode on Windows if this
781
- # feature will be used as the
782
- # line-ending translation can cause
783
- # problems with resetting the document
784
- # position to where it was before the
785
- # read ahead. This String will be
786
- # transcoded into the data's Encoding
787
- # before parsing.
788
- # <b><tt>:quote_char</tt></b>:: The character used to quote fields.
789
- # This has to be a single character
790
- # String. This is useful for
791
- # application that incorrectly use
792
- # <tt>'</tt> as the quote character
793
- # instead of the correct <tt>"</tt>.
794
- # CSV will always consider a double
795
- # sequence of this character to be an
796
- # escaped quote. This String will be
797
- # transcoded into the data's Encoding
798
- # before parsing.
799
- # <b><tt>:field_size_limit</tt></b>:: This is a maximum size CSV will read
800
- # ahead looking for the closing quote
801
- # for a field. (In truth, it reads to
802
- # the first line ending beyond this
803
- # size.) If a quote cannot be found
804
- # within the limit CSV will raise a
805
- # MalformedCSVError, assuming the data
806
- # is faulty. You can use this limit to
807
- # prevent what are effectively DoS
808
- # attacks on the parser. However, this
809
- # limit can cause a legitimate parse to
810
- # fail and thus is set to +nil+, or off,
811
- # by default.
812
- # <b><tt>:converters</tt></b>:: An Array of names from the Converters
813
- # Hash and/or lambdas that handle custom
814
- # conversion. A single converter
815
- # doesn't have to be in an Array. All
816
- # built-in converters try to transcode
817
- # fields to UTF-8 before converting.
818
- # The conversion will fail if the data
819
- # cannot be transcoded, leaving the
820
- # field unchanged.
821
- # <b><tt>:unconverted_fields</tt></b>:: If set to +true+, an
822
- # unconverted_fields() method will be
823
- # added to all returned rows (Array or
824
- # CSV::Row) that will return the fields
825
- # as they were before conversion. Note
826
- # that <tt>:headers</tt> supplied by
827
- # Array or String were not fields of the
828
- # document and thus will have an empty
829
- # Array attached.
830
- # <b><tt>:headers</tt></b>:: If set to <tt>:first_row</tt> or
831
- # +true+, the initial row of the CSV
832
- # file will be treated as a row of
833
- # headers. If set to an Array, the
834
- # contents will be used as the headers.
835
- # If set to a String, the String is run
836
- # through a call of CSV::parse_line()
837
- # with the same <tt>:col_sep</tt>,
838
- # <tt>:row_sep</tt>, and
839
- # <tt>:quote_char</tt> as this instance
840
- # to produce an Array of headers. This
841
- # setting causes CSV#shift() to return
842
- # rows as CSV::Row objects instead of
843
- # Arrays and CSV#read() to return
844
- # CSV::Table objects instead of an Array
845
- # of Arrays.
846
- # <b><tt>:return_headers</tt></b>:: When +false+, header rows are silently
847
- # swallowed. If set to +true+, header
848
- # rows are returned in a CSV::Row object
849
- # with identical headers and
850
- # fields (save that the fields do not go
851
- # through the converters).
852
- # <b><tt>:write_headers</tt></b>:: When +true+ and <tt>:headers</tt> is
853
- # set, a header row will be added to the
854
- # output.
855
- # <b><tt>:header_converters</tt></b>:: Identical in functionality to
856
- # <tt>:converters</tt> save that the
857
- # conversions are only made to header
858
- # rows. All built-in converters try to
859
- # transcode headers to UTF-8 before
860
- # converting. The conversion will fail
861
- # if the data cannot be transcoded,
862
- # leaving the header unchanged.
863
- # <b><tt>:skip_blanks</tt></b>:: When setting a +true+ value, CSV will
864
- # skip over any empty rows. Note that
865
- # this setting will not skip rows that
866
- # contain column separators, even if
867
- # the rows contain no actual data. If
868
- # you want to skip rows that contain
869
- # separators but no content, consider
870
- # using <tt>:skip_lines</tt>, or
871
- # inspecting fields.compact.empty? on
872
- # each row.
873
- # <b><tt>:force_quotes</tt></b>:: When setting a +true+ value, CSV will
874
- # quote all CSV fields it creates.
875
- # <b><tt>:skip_lines</tt></b>:: When setting an object responding to
876
- # <tt>match</tt>, every line matching
877
- # it is considered a comment and ignored
878
- # during parsing. When set to a String,
879
- # it is first converted to a Regexp.
880
- # When set to +nil+ no line is considered
881
- # a comment. If the passed object does
882
- # not respond to <tt>match</tt>,
883
- # <tt>ArgumentError</tt> is thrown.
884
- # <b><tt>:liberal_parsing</tt></b>:: When setting a +true+ value, CSV will
885
- # attempt to parse input not conformant
886
- # with RFC 4180, such as double quotes
887
- # in unquoted fields.
888
- # <b><tt>:nil_value</tt></b>:: When set an object, any values of an
889
- # empty field is replaced by the set
890
- # object, not nil.
891
- # <b><tt>:empty_value</tt></b>:: When setting an object, any values of a
892
- # blank string field is replaced by
893
- # the set object.
894
- # <b><tt>:quote_empty</tt></b>:: When setting a +true+ value, CSV will
895
- # quote empty values with double quotes.
896
- # When +false+, CSV will emit an
897
- # empty string for an empty field value.
898
- # <b><tt>:write_converters</tt></b>:: Converts values on each line with the
899
- # specified <tt>Proc</tt> object(s),
900
- # which receive a <tt>String</tt> value
901
- # and return a <tt>String</tt> or +nil+
902
- # value.
903
- # When an array is specified, each
904
- # converter will be applied in order.
905
- # <b><tt>:write_nil_value</tt></b>:: When a <tt>String</tt> value, +nil+
906
- # value(s) on each line will be replaced
907
- # with the specified value.
908
- # <b><tt>:write_empty_value</tt></b>:: When a <tt>String</tt> or +nil+ value,
909
- # empty value(s) on each line will be
910
- # replaced with the specified value.
911
- # <b><tt>:strip</tt></b>:: When setting a +true+ value, CSV will
912
- # strip " \t\f\v" around the values.
913
- # If you specify a string instead of
914
- # +true+, CSV will strip string. The
915
- # length of the string must be 1.
916
- #
917
- # See CSV::DEFAULT_OPTIONS for the default settings.
1022
+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
1023
+ # and {Options for Generating}[#class-CSV-label-Options+for+Generating].
918
1024
  #
919
1025
  # Options cannot be overridden in the instance methods for performance reasons,
920
1026
  # so be sure to set what you want here.
@@ -50,7 +50,7 @@ class CSV
50
50
  fields.collect.with_index do |field, index|
51
51
  if field.nil?
52
52
  field = @nil_value
53
- elsif field.empty?
53
+ elsif field.is_a?(String) and field.empty?
54
54
  field = @empty_value unless @empty_value_is_empty_string
55
55
  end
56
56
  @converters.each do |converter|
@@ -708,7 +708,7 @@ class CSV
708
708
  if SCANNER_TEST
709
709
  class UnoptimizedStringIO
710
710
  def initialize(string)
711
- @io = StringIO.new(string)
711
+ @io = StringIO.new(string, "rb:#{string.encoding}")
712
712
  end
713
713
 
714
714
  def gets(*args)
@@ -2,5 +2,5 @@
2
2
 
3
3
  class CSV
4
4
  # The version of the installed library.
5
- VERSION = "3.1.3"
5
+ VERSION = "3.1.4"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: csv
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.3
4
+ version: 3.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Edward Gray II
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-05-08 00:00:00.000000000 Z
12
+ date: 2020-05-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler