csv 3.1.5 → 3.1.6

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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS.md +36 -0
  3. data/doc/arguments/io.rdoc +5 -0
  4. data/doc/options/common/col_sep.rdoc +63 -0
  5. data/doc/options/common/quote_char.rdoc +42 -0
  6. data/doc/{row_sep.rdoc → options/common/row_sep.rdoc} +15 -6
  7. data/doc/{force_quotes.rdoc → options/generating/force_quotes.rdoc} +0 -0
  8. data/doc/{quote_empty.rdoc → options/generating/quote_empty.rdoc} +0 -0
  9. data/doc/{write_converters.rdoc → options/generating/write_converters.rdoc} +8 -6
  10. data/doc/{write_empty_value.rdoc → options/generating/write_empty_value.rdoc} +0 -0
  11. data/doc/{write_headers.rdoc → options/generating/write_headers.rdoc} +0 -0
  12. data/doc/{write_nil_value.rdoc → options/generating/write_nil_value.rdoc} +1 -1
  13. data/doc/options/parsing/converters.rdoc +46 -0
  14. data/doc/{empty_value.rdoc → options/parsing/empty_value.rdoc} +0 -0
  15. data/doc/{field_size_limit.rdoc → options/parsing/field_size_limit.rdoc} +0 -0
  16. data/doc/options/parsing/header_converters.rdoc +43 -0
  17. data/doc/{headers.rdoc → options/parsing/headers.rdoc} +0 -0
  18. data/doc/{liberal_parsing.rdoc → options/parsing/liberal_parsing.rdoc} +0 -0
  19. data/doc/{nil_value.rdoc → options/parsing/nil_value.rdoc} +0 -0
  20. data/doc/{return_headers.rdoc → options/parsing/return_headers.rdoc} +0 -0
  21. data/doc/{skip_blanks.rdoc → options/parsing/skip_blanks.rdoc} +0 -0
  22. data/doc/{skip_lines.rdoc → options/parsing/skip_lines.rdoc} +0 -0
  23. data/doc/{strip.rdoc → options/parsing/strip.rdoc} +0 -0
  24. data/doc/{unconverted_fields.rdoc → options/parsing/unconverted_fields.rdoc} +0 -0
  25. data/lib/csv.rb +1334 -495
  26. data/lib/csv/version.rb +1 -1
  27. data/lib/csv/writer.rb +45 -4
  28. metadata +38 -23
  29. data/doc/col_sep.rdoc +0 -45
  30. data/doc/converters.rdoc +0 -45
  31. data/doc/header_converters.rdoc +0 -31
  32. data/doc/quote_char.rdoc +0 -32
@@ -2,5 +2,5 @@
2
2
 
3
3
  class CSV
4
4
  # The version of the installed library.
5
- VERSION = "3.1.5"
5
+ VERSION = "3.1.6"
6
6
  end
@@ -43,8 +43,10 @@ class CSV
43
43
 
44
44
  row = @fields_converter.convert(row, nil, lineno) if @fields_converter
45
45
 
46
+ i = -1
46
47
  converted_row = row.collect do |field|
47
- quote(field)
48
+ i += 1
49
+ quote(field, i)
48
50
  end
49
51
  line = converted_row.join(@column_separator) + @row_separator
50
52
  if @output_encoding
@@ -100,6 +102,33 @@ class CSV
100
102
  end
101
103
  end
102
104
 
105
+ def prepare_force_quotes_fields(force_quotes)
106
+ @force_quotes_fields = {}
107
+ force_quotes.each do |name_or_index|
108
+ case name_or_index
109
+ when Integer
110
+ index = name_or_index
111
+ @force_quotes_fields[index] = true
112
+ when String, Symbol
113
+ name = name_or_index.to_s
114
+ if @headers.nil?
115
+ message = ":headers is required when you use field name " +
116
+ "in :force_quotes: " +
117
+ "#{name_or_index.inspect}: #{force_quotes.inspect}"
118
+ raise ArgumentError, message
119
+ end
120
+ index = @headers.index(name)
121
+ next if index.nil?
122
+ @force_quotes_fields[index] = true
123
+ else
124
+ message = ":force_quotes element must be " +
125
+ "field index or field name: " +
126
+ "#{name_or_index.inspect}: #{force_quotes.inspect}"
127
+ raise ArgumentError, message
128
+ end
129
+ end
130
+ end
131
+
103
132
  def prepare_format
104
133
  @column_separator = @options[:column_separator].to_s.encode(@encoding)
105
134
  row_separator = @options[:row_separator]
@@ -109,7 +138,17 @@ class CSV
109
138
  @row_separator = row_separator.to_s.encode(@encoding)
110
139
  end
111
140
  @quote_character = @options[:quote_character]
112
- @force_quotes = @options[:force_quotes]
141
+ force_quotes = @options[:force_quotes]
142
+ if force_quotes.is_a?(Array)
143
+ prepare_force_quotes_fields(force_quotes)
144
+ @force_quotes = false
145
+ elsif force_quotes
146
+ @force_quotes_fields = nil
147
+ @force_quotes = true
148
+ else
149
+ @force_quotes_fields = nil
150
+ @force_quotes = false
151
+ end
113
152
  unless @force_quotes
114
153
  @quotable_pattern =
115
154
  Regexp.new("[\r\n".encode(@encoding) +
@@ -147,16 +186,18 @@ class CSV
147
186
  encoded_quote_character
148
187
  end
149
188
 
150
- def quote(field)
189
+ def quote(field, i)
151
190
  if @force_quotes
152
191
  quote_field(field)
192
+ elsif @force_quotes_fields and @force_quotes_fields[i]
193
+ quote_field(field)
153
194
  else
154
195
  if field.nil? # represent +nil+ fields as empty unquoted fields
155
196
  ""
156
197
  else
157
198
  field = String(field) # Stringify fields
158
199
  # represent empty fields as empty quoted fields
159
- if (@quote_empty and field.empty?) or @quotable_pattern.match?(field)
200
+ if (@quote_empty and field.empty?) or (field.valid_encoding? and @quotable_pattern.match?(field))
160
201
  quote_field(field)
161
202
  else
162
203
  field # unquoted field
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.5
4
+ version: 3.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Edward Gray II
@@ -9,8 +9,22 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-05-17 00:00:00.000000000 Z
12
+ date: 2020-07-19 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: stringio
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 0.1.3
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 0.1.3
14
28
  - !ruby/object:Gem::Dependency
15
29
  name: bundler
16
30
  requirement: !ruby/object:Gem::Requirement
@@ -83,27 +97,28 @@ files:
83
97
  - LICENSE.txt
84
98
  - NEWS.md
85
99
  - README.md
86
- - doc/col_sep.rdoc
87
- - doc/converters.rdoc
88
- - doc/empty_value.rdoc
89
- - doc/field_size_limit.rdoc
90
- - doc/force_quotes.rdoc
91
- - doc/header_converters.rdoc
92
- - doc/headers.rdoc
93
- - doc/liberal_parsing.rdoc
94
- - doc/nil_value.rdoc
95
- - doc/quote_char.rdoc
96
- - doc/quote_empty.rdoc
97
- - doc/return_headers.rdoc
98
- - doc/row_sep.rdoc
99
- - doc/skip_blanks.rdoc
100
- - doc/skip_lines.rdoc
101
- - doc/strip.rdoc
102
- - doc/unconverted_fields.rdoc
103
- - doc/write_converters.rdoc
104
- - doc/write_empty_value.rdoc
105
- - doc/write_headers.rdoc
106
- - doc/write_nil_value.rdoc
100
+ - doc/arguments/io.rdoc
101
+ - doc/options/common/col_sep.rdoc
102
+ - doc/options/common/quote_char.rdoc
103
+ - doc/options/common/row_sep.rdoc
104
+ - doc/options/generating/force_quotes.rdoc
105
+ - doc/options/generating/quote_empty.rdoc
106
+ - doc/options/generating/write_converters.rdoc
107
+ - doc/options/generating/write_empty_value.rdoc
108
+ - doc/options/generating/write_headers.rdoc
109
+ - doc/options/generating/write_nil_value.rdoc
110
+ - doc/options/parsing/converters.rdoc
111
+ - doc/options/parsing/empty_value.rdoc
112
+ - doc/options/parsing/field_size_limit.rdoc
113
+ - doc/options/parsing/header_converters.rdoc
114
+ - doc/options/parsing/headers.rdoc
115
+ - doc/options/parsing/liberal_parsing.rdoc
116
+ - doc/options/parsing/nil_value.rdoc
117
+ - doc/options/parsing/return_headers.rdoc
118
+ - doc/options/parsing/skip_blanks.rdoc
119
+ - doc/options/parsing/skip_lines.rdoc
120
+ - doc/options/parsing/strip.rdoc
121
+ - doc/options/parsing/unconverted_fields.rdoc
107
122
  - lib/csv.rb
108
123
  - lib/csv/core_ext/array.rb
109
124
  - lib/csv/core_ext/string.rb
@@ -1,45 +0,0 @@
1
- ====== Option +col_sep+
2
-
3
- Specifies the \String field separator to be used
4
- for both parsing and generating.
5
- The \String will be transcoded into the data's \Encoding before use.
6
-
7
- Default value:
8
- CSV::DEFAULT_OPTIONS.fetch(:col_sep) # => "," (comma)
9
-
10
- For examples in this section:
11
- ary = ['a', 'b', 'c']
12
-
13
- Using the default:
14
- str = CSV.generate_line(line)
15
- str # => "a,b,c\n"
16
- ary = CSV.parse_line(str)
17
- ary # => ["a", "b", "c"]
18
-
19
- Using +:+ (colon):
20
- col_sep = ':'
21
- str = CSV.generate_line(ary, col_sep: col_sep)
22
- str # => "a:b:c\n"
23
- ary = CSV.parse_line(str, col_sep: col_sep)
24
- ary # => [["a", "b", "c"]]
25
-
26
- Using +::+ (two colons):
27
- col_sep = '::'
28
- str = CSV.generate_line(ary, col_sep: col_sep)
29
- str # => "a::b::c\n"
30
- ary = CSV.parse_line(str, col_sep: col_sep)
31
- ary # => [["a", "b", "c"]]
32
-
33
- ---
34
-
35
- Raises an exception if given the empty \String:
36
- col_sep = ''
37
- # Raises ArgumentError (:col_sep must be 1 or more characters: "")
38
- CSV.parse_line("a:b:c\n", col_sep: col_sep)
39
-
40
- Raises an exception if the given value is not String-convertible:
41
- col_sep = BasicObject.new
42
- # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
43
- CSV.generate_line(line, col_sep: col_sep)
44
- # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
45
- CSV.parse(str, col_sep: col_sep)
@@ -1,45 +0,0 @@
1
- ====== Option +converters+
2
-
3
- Specifies a single field converter name or \Proc,
4
- or an \Array of field converter names and Procs.
5
-
6
- See {Field Converters}[#class-CSV-label-Field+Converters]
7
-
8
- Default value:
9
- CSV::DEFAULT_OPTIONS.fetch(:converters) # => nil
10
-
11
- The value may be a single field converter name:
12
- str = '1,2,3'
13
- # Without a converter
14
- ary = CSV.parse_line(str)
15
- ary # => ["1", "2", "3"]
16
- # With built-in converter :integer
17
- ary = CSV.parse_line(str, converters: :integer)
18
- ary # => [1, 2, 3]
19
-
20
- The value may be an \Array of field converter names:
21
- str = '1,3.14159'
22
- # Without converters
23
- ary = CSV.parse_line(str)
24
- ary # => ["1", "3.14159"]
25
- # With built-in converters
26
- ary = CSV.parse_line(str, converters: [:integer, :float])
27
- ary # => [1, 3.14159]
28
-
29
- The value may be a \Proc custom converter:
30
- str = ' foo , bar , baz '
31
- # Without a converter
32
- ary = CSV.parse_line(str)
33
- ary # => [" foo ", " bar ", " baz "]
34
- # With a custom converter
35
- ary = CSV.parse_line(str, converters: proc {|field| field.strip })
36
- ary # => ["foo", "bar", "baz"]
37
-
38
- See also {Custom Converters}[#class-CSV-label-Custom+Converters]
39
-
40
- ---
41
-
42
- Raises an exception if the converter is not a converter name or a \Proc:
43
- str = 'foo,0'
44
- # Raises NoMethodError (undefined method `arity' for nil:NilClass)
45
- CSV.parse(str, converters: :foo)
@@ -1,31 +0,0 @@
1
- ====== Option +header_converters+
2
-
3
- Specifies a \String converter name or an \Array of converter names.
4
-
5
- Default value:
6
- CSV::DEFAULT_OPTIONS.fetch(:header_converters) # => nil
7
-
8
- Identical in functionality to option {converters}[#class-CSV-label-Option+converters]
9
- except that:
10
- - The converters apply only to the header row.
11
- - The built-in header converters are +:downcase+ and +:symbol+.
12
-
13
- Examples:
14
- str = <<-EOT
15
- foo,0
16
- bar,1
17
- baz,2
18
- EOT
19
- headers = ['Name', 'Value']
20
- # With no header converter
21
- csv = CSV.parse(str, headers: headers)
22
- csv.headers # => ["Name", "Value"]
23
- # With header converter :downcase
24
- csv = CSV.parse(str, headers: headers, header_converters: :downcase)
25
- csv.headers # => ["name", "value"]
26
- # With header converter :symbol
27
- csv = CSV.parse(str, headers: headers, header_converters: :symbol)
28
- csv.headers # => [:name, :value]
29
- # With both
30
- csv = CSV.parse(str, headers: headers, header_converters: [:downcase, :symbol])
31
- csv.headers # => [:name, :value]
@@ -1,32 +0,0 @@
1
- ====== Option +quote_char+
2
-
3
- Specifies the character (\String of length 1) used used to quote fields
4
- in both parsing and generating.
5
- This String will be transcoded into the data's \Encoding before use.
6
-
7
- Default value:
8
- CSV::DEFAULT_OPTIONS.fetch(:quote_char) # => "\"" (backslash)
9
-
10
- This is useful for an application that incorrectly uses <tt>'</tt> (single-quote)
11
- to quote fields, instead of the correct <tt>"</tt> (double-quote).
12
-
13
- Using the default:
14
- ary = ['a', 'b', '"c"', 'd']
15
- str = CSV.generate_line(ary)
16
- str # => "a,b,\"\"\"c\"\"\",d\n"
17
- ary = CSV.parse_line(str)
18
- ary # => ["a", "b", "\"c\"", "d"]
19
-
20
- Using <tt>'</tt> (single-quote):
21
- quote_char = "'"
22
- ary = ['a', 'b', '\'c\'', 'd']
23
- str = CSV.generate_line(ary, quote_char: quote_char)
24
- str # => "a,b,'''c''',d\n"
25
- ary = CSV.parse_line(str, quote_char: quote_char)
26
- ary # => [["a", "b", "'c'", "d"]]
27
-
28
- ---
29
-
30
- Raises an exception if the \String length is greater than 1:
31
- # Raises ArgumentError (:quote_char has to be nil or a single character String)
32
- CSV.new('', quote_char: 'xx')