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.
- checksums.yaml +4 -4
- data/NEWS.md +36 -0
- data/doc/arguments/io.rdoc +5 -0
- data/doc/options/common/col_sep.rdoc +63 -0
- data/doc/options/common/quote_char.rdoc +42 -0
- data/doc/{row_sep.rdoc → options/common/row_sep.rdoc} +15 -6
- data/doc/{force_quotes.rdoc → options/generating/force_quotes.rdoc} +0 -0
- data/doc/{quote_empty.rdoc → options/generating/quote_empty.rdoc} +0 -0
- data/doc/{write_converters.rdoc → options/generating/write_converters.rdoc} +8 -6
- data/doc/{write_empty_value.rdoc → options/generating/write_empty_value.rdoc} +0 -0
- data/doc/{write_headers.rdoc → options/generating/write_headers.rdoc} +0 -0
- data/doc/{write_nil_value.rdoc → options/generating/write_nil_value.rdoc} +1 -1
- data/doc/options/parsing/converters.rdoc +46 -0
- data/doc/{empty_value.rdoc → options/parsing/empty_value.rdoc} +0 -0
- data/doc/{field_size_limit.rdoc → options/parsing/field_size_limit.rdoc} +0 -0
- data/doc/options/parsing/header_converters.rdoc +43 -0
- data/doc/{headers.rdoc → options/parsing/headers.rdoc} +0 -0
- data/doc/{liberal_parsing.rdoc → options/parsing/liberal_parsing.rdoc} +0 -0
- data/doc/{nil_value.rdoc → options/parsing/nil_value.rdoc} +0 -0
- data/doc/{return_headers.rdoc → options/parsing/return_headers.rdoc} +0 -0
- data/doc/{skip_blanks.rdoc → options/parsing/skip_blanks.rdoc} +0 -0
- data/doc/{skip_lines.rdoc → options/parsing/skip_lines.rdoc} +0 -0
- data/doc/{strip.rdoc → options/parsing/strip.rdoc} +0 -0
- data/doc/{unconverted_fields.rdoc → options/parsing/unconverted_fields.rdoc} +0 -0
- data/lib/csv.rb +1334 -495
- data/lib/csv/version.rb +1 -1
- data/lib/csv/writer.rb +45 -4
- metadata +38 -23
- data/doc/col_sep.rdoc +0 -45
- data/doc/converters.rdoc +0 -45
- data/doc/header_converters.rdoc +0 -31
- data/doc/quote_char.rdoc +0 -32
data/lib/csv/version.rb
CHANGED
data/lib/csv/writer.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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.
|
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-
|
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/
|
87
|
-
- doc/
|
88
|
-
- doc/
|
89
|
-
- doc/
|
90
|
-
- doc/force_quotes.rdoc
|
91
|
-
- doc/
|
92
|
-
- doc/
|
93
|
-
- doc/
|
94
|
-
- doc/
|
95
|
-
- doc/
|
96
|
-
- doc/
|
97
|
-
- doc/
|
98
|
-
- doc/
|
99
|
-
- doc/
|
100
|
-
- doc/
|
101
|
-
- doc/
|
102
|
-
- doc/
|
103
|
-
- doc/
|
104
|
-
- doc/
|
105
|
-
- doc/
|
106
|
-
- doc/
|
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
|
data/doc/col_sep.rdoc
DELETED
@@ -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)
|
data/doc/converters.rdoc
DELETED
@@ -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)
|
data/doc/header_converters.rdoc
DELETED
@@ -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]
|
data/doc/quote_char.rdoc
DELETED
@@ -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')
|