csv 3.1.9 → 3.3.2

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.
@@ -45,6 +45,7 @@ All code snippets on this page assume that the following has been executed:
45
45
  - {Recipe: Convert Fields to Numerics}[#label-Recipe-3A+Convert+Fields+to+Numerics]
46
46
  - {Recipe: Convert Fields to Dates}[#label-Recipe-3A+Convert+Fields+to+Dates]
47
47
  - {Recipe: Convert Fields to DateTimes}[#label-Recipe-3A+Convert+Fields+to+DateTimes]
48
+ - {Recipe: Convert Fields to Times}[#label-Recipe-3A+Convert+Fields+to+Times]
48
49
  - {Recipe: Convert Assorted Fields to Objects}[#label-Recipe-3A+Convert+Assorted+Fields+to+Objects]
49
50
  - {Recipe: Convert Fields to Other Objects}[#label-Recipe-3A+Convert+Fields+to+Other+Objects]
50
51
  - {Recipe: Filter Field Strings}[#label-Recipe-3A+Filter+Field+Strings]
@@ -83,7 +84,7 @@ Use instance method CSV#each with option +headers+ to read a source \String one
83
84
  CSV.new(string, headers: true).each do |row|
84
85
  p row
85
86
  end
86
- Ouput:
87
+ Output:
87
88
  #<CSV::Row "Name":"foo" "Value":"0">
88
89
  #<CSV::Row "Name":"bar" "Value":"1">
89
90
  #<CSV::Row "Name":"baz" "Value":"2">
@@ -110,7 +111,7 @@ You can parse \CSV data from a \File, with or without headers.
110
111
 
111
112
  ===== Recipe: Parse from \File with Headers
112
113
 
113
- Use instance method CSV#read with option +headers+ to read a file all at once:
114
+ Use class method CSV.read with option +headers+ to read a file all at once:
114
115
  string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
115
116
  path = 't.csv'
116
117
  File.write(path, string)
@@ -191,7 +192,7 @@ Output:
191
192
  === RFC 4180 Compliance
192
193
 
193
194
  By default, \CSV parses data that is compliant with
194
- {RFC 4180}[https://tools.ietf.org/html/rfc4180]
195
+ {RFC 4180}[https://www.rfc-editor.org/rfc/rfc4180]
195
196
  with respect to:
196
197
  - Row separator.
197
198
  - Column separator.
@@ -339,6 +340,7 @@ There are built-in field converters for converting to objects of certain classes
339
340
  - \Integer
340
341
  - \Date
341
342
  - \DateTime
343
+ - \Time
342
344
 
343
345
  Other built-in field converters include:
344
346
  - +:numeric+: converts to \Integer and \Float.
@@ -381,6 +383,13 @@ Convert fields to \DateTime objects using built-in converter +:date_time+:
381
383
  parsed = CSV.parse(source, headers: true, converters: :date_time)
382
384
  parsed.map {|row| row['DateTime'].class} # => [DateTime, DateTime, DateTime]
383
385
 
386
+ ===== Recipe: Convert Fields to Times
387
+
388
+ Convert fields to \Time objects using built-in converter +:time+:
389
+ source = "Name,Time\nfoo,2001-02-03\nbar,2001-02-04\nbaz,2020-05-07T14:59:00-05:00\n"
390
+ parsed = CSV.parse(source, headers: true, converters: :time)
391
+ parsed.map {|row| row['Time'].class} # => [Time, Time, Time]
392
+
384
393
  ===== Recipe: Convert Assorted Fields to Objects
385
394
 
386
395
  Convert assorted fields to objects using built-in converter +:all+:
@@ -431,7 +440,7 @@ You can use multiple field converters in either of these ways:
431
440
 
432
441
  ===== Recipe: Specify Multiple Field Converters in Option +:converters+
433
442
 
434
- Apply multiple field converters by specifying them in option +:conveters+:
443
+ Apply multiple field converters by specifying them in option +:converters+:
435
444
  source = "Name,Value\nfoo,0\nbar,1.0\nbaz,2.0\n"
436
445
  parsed = CSV.parse(source, headers: true, converters: [:integer, :float])
437
446
  parsed['Value'] # => [0, 1.0, 2.0]
@@ -500,7 +509,7 @@ You can use multiple header converters in either of these ways:
500
509
 
501
510
  ===== Recipe: Specify Multiple Header Converters in Option :header_converters
502
511
 
503
- Apply multiple header converters by specifying them in option +:header_conveters+:
512
+ Apply multiple header converters by specifying them in option +:header_converters+:
504
513
  source = "Name,Value\nfoo,0\nbar,1.0\nbaz,2.0\n"
505
514
  parsed = CSV.parse(source, headers: true, header_converters: [:downcase, :symbol])
506
515
  parsed.headers # => [:name, :value]
@@ -520,7 +529,7 @@ Apply multiple header converters by defining and registering a custom header con
520
529
  To capture unconverted field values, use option +:unconverted_fields+:
521
530
  source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
522
531
  parsed = CSV.parse(source, converters: :integer, unconverted_fields: true)
523
- parsed # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
532
+ parsed # => [["Name", "Value"], ["foo", 0], ["bar", 1], ["baz", 2]]
524
533
  parsed.each {|row| p row.unconverted_fields }
525
534
  Output:
526
535
  ["Name", "Value"]
@@ -542,4 +551,4 @@ Output:
542
551
  #<struct CSV::FieldInfo index=0, line=2, header=nil>
543
552
  #<struct CSV::FieldInfo index=1, line=2, header=nil>
544
553
  #<struct CSV::FieldInfo index=0, line=3, header=nil>
545
- #<struct CSV::FieldInfo index=1, line=3, header=nil>
554
+ #<struct CSV::FieldInfo index=1, line=3, header=nil>
@@ -1,4 +1,4 @@
1
- class Array # :nodoc:
1
+ class Array
2
2
  # Equivalent to CSV::generate_line(self, options)
3
3
  #
4
4
  # ["CSV", "data"].to_csv
@@ -1,4 +1,4 @@
1
- class String # :nodoc:
1
+ class String
2
2
  # Equivalent to CSV::parse_line(self, options)
3
3
  #
4
4
  # "CSV,data".parse_csv
@@ -4,6 +4,13 @@ class CSV
4
4
  # Note: Don't use this class directly. This is an internal class.
5
5
  class FieldsConverter
6
6
  include Enumerable
7
+
8
+ NO_QUOTED_FIELDS = [] # :nodoc:
9
+ def NO_QUOTED_FIELDS.[](_index)
10
+ false
11
+ end
12
+ NO_QUOTED_FIELDS.freeze
13
+
7
14
  #
8
15
  # A CSV::FieldsConverter is a data structure for storing the
9
16
  # fields converter properties to be passed as a parameter
@@ -16,7 +23,7 @@ class CSV
16
23
  @empty_value = options[:empty_value]
17
24
  @empty_value_is_empty_string = (@empty_value == "")
18
25
  @accept_nil = options[:accept_nil]
19
- @builtin_converters = options[:builtin_converters]
26
+ @builtin_converters_name = options[:builtin_converters_name]
20
27
  @need_static_convert = need_static_convert?
21
28
  end
22
29
 
@@ -24,7 +31,7 @@ class CSV
24
31
  if name.nil? # custom converter
25
32
  @converters << converter
26
33
  else # named converter
27
- combo = @builtin_converters[name]
34
+ combo = builtin_converters[name]
28
35
  case combo
29
36
  when Array # combo converter
30
37
  combo.each do |sub_name|
@@ -44,7 +51,7 @@ class CSV
44
51
  @converters.empty?
45
52
  end
46
53
 
47
- def convert(fields, headers, lineno)
54
+ def convert(fields, headers, lineno, quoted_fields=NO_QUOTED_FIELDS)
48
55
  return fields unless need_convert?
49
56
 
50
57
  fields.collect.with_index do |field, index|
@@ -63,7 +70,8 @@ class CSV
63
70
  else
64
71
  header = nil
65
72
  end
66
- field = converter[field, FieldInfo.new(index, lineno, header)]
73
+ quoted = quoted_fields[index]
74
+ field = converter[field, FieldInfo.new(index, lineno, header, quoted)]
67
75
  end
68
76
  break unless field.is_a?(String) # short-circuit pipeline for speed
69
77
  end
@@ -80,5 +88,9 @@ class CSV
80
88
  @need_static_convert or
81
89
  (not @converters.empty?)
82
90
  end
91
+
92
+ def builtin_converters
93
+ @builtin_converters ||= ::CSV.const_get(@builtin_converters_name)
94
+ end
83
95
  end
84
96
  end
@@ -0,0 +1,18 @@
1
+ require "English"
2
+ require "stringio"
3
+
4
+ class CSV
5
+ module InputRecordSeparator
6
+ class << self
7
+ if RUBY_VERSION >= "3.0.0"
8
+ def value
9
+ "\n"
10
+ end
11
+ else
12
+ def value
13
+ $INPUT_RECORD_SEPARATOR
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end