csv 3.1.4 → 3.1.5
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 +18 -0
- data/doc/col_sep.rdoc +45 -0
- data/doc/converters.rdoc +45 -0
- data/doc/empty_value.rdoc +13 -0
- data/doc/field_size_limit.rdoc +39 -0
- data/doc/force_quotes.rdoc +17 -0
- data/doc/header_converters.rdoc +31 -0
- data/doc/headers.rdoc +63 -0
- data/doc/liberal_parsing.rdoc +19 -0
- data/doc/nil_value.rdoc +12 -0
- data/doc/quote_char.rdoc +32 -0
- data/doc/quote_empty.rdoc +12 -0
- data/doc/return_headers.rdoc +22 -0
- data/doc/row_sep.rdoc +91 -0
- data/doc/skip_blanks.rdoc +31 -0
- data/doc/skip_lines.rdoc +37 -0
- data/doc/strip.rdoc +15 -0
- data/doc/unconverted_fields.rdoc +27 -0
- data/doc/write_converters.rdoc +31 -0
- data/doc/write_empty_value.rdoc +15 -0
- data/doc/write_headers.rdoc +29 -0
- data/doc/write_nil_value.rdoc +14 -0
- data/lib/csv.rb +100 -26
- data/lib/csv/version.rb +1 -1
- metadata +29 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eec352a246dc1189213c78e35541e9903f172889792b92a23d6b8d7215d9ae37
|
4
|
+
data.tar.gz: 63754025784b9d6d26686b48efe8627b18c1aaa26e14f1261d14a09a4921612e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1b9895d4735d3f7a1376765d8e71a03388d4b8f52ace5a8eab3126e1f3167f77fcfd312212fdbdbda496d4a2f837a966bf33b871bee96f633c536b566ce0a9f
|
7
|
+
data.tar.gz: 9347baa988315b544d41ec23ded72a812dec09b7c0832c72bc4ff3be950e25d0f2184f9ed43967113ddb63e56e29c847bffb469b7883ad4207b913368057b58c
|
data/NEWS.md
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
# News
|
2
2
|
|
3
|
+
## 3.1.5 - 2020-05-18
|
4
|
+
|
5
|
+
### Improvements
|
6
|
+
|
7
|
+
* Improved document.
|
8
|
+
[GitHub#124][Patch by Burdette Lamar]
|
9
|
+
|
10
|
+
### Fixes
|
11
|
+
|
12
|
+
* Added missing document files.
|
13
|
+
[GitHub#125][Reported by joast]
|
14
|
+
|
15
|
+
### Thanks
|
16
|
+
|
17
|
+
* Burdette Lamar
|
18
|
+
|
19
|
+
* joast
|
20
|
+
|
3
21
|
## 3.1.4 - 2020-05-17
|
4
22
|
|
5
23
|
### Improvements
|
data/doc/col_sep.rdoc
ADDED
@@ -0,0 +1,45 @@
|
|
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
ADDED
@@ -0,0 +1,45 @@
|
|
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)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
====== Option +empty_value+
|
2
|
+
|
3
|
+
Specifies the object that is to be substituted
|
4
|
+
for each field that has an empty \String.
|
5
|
+
|
6
|
+
Default value:
|
7
|
+
CSV::DEFAULT_OPTIONS.fetch(:empty_value) # => "" (empty string)
|
8
|
+
|
9
|
+
With the default, <tt>""</tt>:
|
10
|
+
CSV.parse_line('a,"",b,"",c') # => ["a", "", "b", "", "c"]
|
11
|
+
|
12
|
+
With a different object:
|
13
|
+
CSV.parse_line('a,"",b,"",c', empty_value: 'x') # => ["a", "x", "b", "x", "c"]
|
@@ -0,0 +1,39 @@
|
|
1
|
+
====== Option +field_size_limit+
|
2
|
+
|
3
|
+
Specifies the \Integer field size limit.
|
4
|
+
|
5
|
+
Default value:
|
6
|
+
CSV::DEFAULT_OPTIONS.fetch(:field_size_limit) # => nil
|
7
|
+
|
8
|
+
This is a maximum size CSV will read ahead looking for the closing quote for a field.
|
9
|
+
(In truth, it reads to the first line ending beyond this size.)
|
10
|
+
If a quote cannot be found within the limit CSV will raise a MalformedCSVError,
|
11
|
+
assuming the data is faulty.
|
12
|
+
You can use this limit to prevent what are effectively DoS attacks on the parser.
|
13
|
+
However, this limit can cause a legitimate parse to fail;
|
14
|
+
therefore the default value is +nil+ (no limit).
|
15
|
+
|
16
|
+
For the examples in this section:
|
17
|
+
str = <<~EOT
|
18
|
+
"a","b"
|
19
|
+
"
|
20
|
+
2345
|
21
|
+
",""
|
22
|
+
EOT
|
23
|
+
str # => "\"a\",\"b\"\n\"\n2345\n\",\"\"\n"
|
24
|
+
|
25
|
+
Using the default +nil+:
|
26
|
+
ary = CSV.parse(str)
|
27
|
+
ary # => [["a", "b"], ["\n2345\n", ""]]
|
28
|
+
|
29
|
+
Using <tt>50</tt>:
|
30
|
+
field_size_limit = 50
|
31
|
+
ary = CSV.parse(str, field_size_limit: field_size_limit)
|
32
|
+
ary # => [["a", "b"], ["\n2345\n", ""]]
|
33
|
+
|
34
|
+
---
|
35
|
+
|
36
|
+
Raises an exception if a field is too long:
|
37
|
+
big_str = "123456789\n" * 1024
|
38
|
+
# Raises CSV::MalformedCSVError (Field size exceeded in line 1.)
|
39
|
+
CSV.parse('valid,fields,"' + big_str + '"', field_size_limit: 2048)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
====== Option +force_quotes+
|
2
|
+
|
3
|
+
Specifies the boolean that determines whether each output field is to be double-quoted.
|
4
|
+
|
5
|
+
Default value:
|
6
|
+
CSV::DEFAULT_OPTIONS.fetch(:force_quotes) # => false
|
7
|
+
|
8
|
+
For examples in this section:
|
9
|
+
ary = ['foo', 0, nil]
|
10
|
+
|
11
|
+
Using the default, +false+:
|
12
|
+
str = CSV.generate_line(ary)
|
13
|
+
str # => "foo,0,\n"
|
14
|
+
|
15
|
+
Using +true+:
|
16
|
+
str = CSV.generate_line(ary, force_quotes: true)
|
17
|
+
str # => "\"foo\",\"0\",\"\"\n"
|
@@ -0,0 +1,31 @@
|
|
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/headers.rdoc
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
====== Option +headers+
|
2
|
+
|
3
|
+
Specifies a boolean, \Symbol, \Array, or \String to be used
|
4
|
+
to define column headers.
|
5
|
+
|
6
|
+
Default value:
|
7
|
+
CSV::DEFAULT_OPTIONS.fetch(:headers) # => false
|
8
|
+
|
9
|
+
---
|
10
|
+
|
11
|
+
Without +headers+:
|
12
|
+
str = <<-EOT
|
13
|
+
Name,Count
|
14
|
+
foo,0
|
15
|
+
bar,1
|
16
|
+
bax,2
|
17
|
+
EOT
|
18
|
+
csv = CSV.new(str)
|
19
|
+
csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
|
20
|
+
csv.headers # => nil
|
21
|
+
csv.shift # => ["Name", "Count"]
|
22
|
+
|
23
|
+
---
|
24
|
+
|
25
|
+
If set to +true+ or the \Symbol +:first_row+,
|
26
|
+
the first row of the data is treated as a row of headers:
|
27
|
+
str = <<-EOT
|
28
|
+
Name,Count
|
29
|
+
foo,0
|
30
|
+
bar,1
|
31
|
+
bax,2
|
32
|
+
EOT
|
33
|
+
csv = CSV.new(str, headers: true)
|
34
|
+
csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:2 col_sep:"," row_sep:"\n" quote_char:"\"" headers:["Name", "Count"]>
|
35
|
+
csv.headers # => ["Name", "Count"]
|
36
|
+
csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
|
37
|
+
|
38
|
+
---
|
39
|
+
|
40
|
+
If set to an \Array, the \Array elements are treated as headers:
|
41
|
+
str = <<-EOT
|
42
|
+
foo,0
|
43
|
+
bar,1
|
44
|
+
bax,2
|
45
|
+
EOT
|
46
|
+
csv = CSV.new(str, headers: ['Name', 'Count'])
|
47
|
+
csv
|
48
|
+
csv.headers # => ["Name", "Count"]
|
49
|
+
csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
|
50
|
+
|
51
|
+
---
|
52
|
+
|
53
|
+
If set to a \String +str+, method <tt>CSV::parse_line(str, options)</tt> is called
|
54
|
+
with the current +options+, and the returned \Array is treated as headers:
|
55
|
+
str = <<-EOT
|
56
|
+
foo,0
|
57
|
+
bar,1
|
58
|
+
bax,2
|
59
|
+
EOT
|
60
|
+
csv = CSV.new(str, headers: 'Name,Count')
|
61
|
+
csv
|
62
|
+
csv.headers # => ["Name", "Count"]
|
63
|
+
csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
|
@@ -0,0 +1,19 @@
|
|
1
|
+
====== Option +liberal_parsing+
|
2
|
+
|
3
|
+
Specifies the boolean value that determines whether
|
4
|
+
CSV will attempt to parse input not conformant with RFC 4180,
|
5
|
+
such as double quotes in unquoted fields.
|
6
|
+
|
7
|
+
Default value:
|
8
|
+
CSV::DEFAULT_OPTIONS.fetch(:liberal_parsing) # => false
|
9
|
+
|
10
|
+
For examples in this section:
|
11
|
+
str = 'is,this "three, or four",fields'
|
12
|
+
|
13
|
+
Without +liberal_parsing+:
|
14
|
+
# Raises CSV::MalformedCSVError (Illegal quoting in str 1.)
|
15
|
+
CSV.parse_line(str)
|
16
|
+
|
17
|
+
With +liberal_parsing+:
|
18
|
+
ary = CSV.parse_line(str, liberal_parsing: true)
|
19
|
+
ary # => ["is", "this \"three", " or four\"", "fields"]
|
data/doc/nil_value.rdoc
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
====== Option +nil_value+
|
2
|
+
|
3
|
+
Specifies the object that is to be substituted for each null (no-text) field.
|
4
|
+
|
5
|
+
Default value:
|
6
|
+
CSV::DEFAULT_OPTIONS.fetch(:nil_value) # => nil
|
7
|
+
|
8
|
+
With the default, +nil+:
|
9
|
+
CSV.parse_line('a,,b,,c') # => ["a", nil, "b", nil, "c"]
|
10
|
+
|
11
|
+
With a different object:
|
12
|
+
CSV.parse_line('a,,b,,c', nil_value: 0) # => ["a", 0, "b", 0, "c"]
|
data/doc/quote_char.rdoc
ADDED
@@ -0,0 +1,32 @@
|
|
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')
|
@@ -0,0 +1,12 @@
|
|
1
|
+
====== Option +quote_empty+
|
2
|
+
|
3
|
+
Specifies the boolean that determines whether an empty value is to be double-quoted.
|
4
|
+
|
5
|
+
Default value:
|
6
|
+
CSV::DEFAULT_OPTIONS.fetch(:quote_empty) # => true
|
7
|
+
|
8
|
+
With the default +true+:
|
9
|
+
CSV.generate_line(['"', ""]) # => "\"\"\"\",\"\"\n"
|
10
|
+
|
11
|
+
With +false+:
|
12
|
+
CSV.generate_line(['"', ""], quote_empty: false) # => "\"\"\"\",\n"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
====== Option +return_headers+
|
2
|
+
|
3
|
+
Specifies the boolean that determines whether method #shift
|
4
|
+
returns or ignores the header row.
|
5
|
+
|
6
|
+
Default value:
|
7
|
+
CSV::DEFAULT_OPTIONS.fetch(:return_headers) # => false
|
8
|
+
|
9
|
+
Examples:
|
10
|
+
str = <<-EOT
|
11
|
+
Name,Count
|
12
|
+
foo,0
|
13
|
+
bar,1
|
14
|
+
bax,2
|
15
|
+
EOT
|
16
|
+
# Without return_headers first row is str.
|
17
|
+
csv = CSV.new(str, headers: true)
|
18
|
+
csv.shift # => #<CSV::Row "Name":"foo" "Count":"0">
|
19
|
+
# With return_headers first row is headers.
|
20
|
+
csv = CSV.new(str, headers: true, return_headers: true)
|
21
|
+
csv.shift # => #<CSV::Row "Name":"Name" "Count":"Count">
|
22
|
+
|
data/doc/row_sep.rdoc
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
====== Option +row_sep+
|
2
|
+
|
3
|
+
Specifies the row separator, a \String or the \Symbol <tt>:auto</tt> (see below),
|
4
|
+
to be used for both parsing and generating.
|
5
|
+
|
6
|
+
Default value:
|
7
|
+
CSV::DEFAULT_OPTIONS.fetch(:row_sep) # => :auto
|
8
|
+
|
9
|
+
---
|
10
|
+
|
11
|
+
When +row_sep+ is a \String, that \String becomes the row separator.
|
12
|
+
The String will be transcoded into the data's Encoding before use.
|
13
|
+
|
14
|
+
Using <tt>"\n"</tt>:
|
15
|
+
str = CSV.generate do |csv|
|
16
|
+
csv << [:foo, 0]
|
17
|
+
csv << [:bar, 1]
|
18
|
+
csv << [:baz, 2]
|
19
|
+
end
|
20
|
+
str # => "foo,0\nbar,1\nbaz,2\n"
|
21
|
+
ary = CSV.parse(str)
|
22
|
+
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
|
23
|
+
|
24
|
+
Using <tt>|</tt> (pipe):
|
25
|
+
row_sep = '|'
|
26
|
+
str = CSV.generate(row_sep: row_sep) do |csv|
|
27
|
+
csv << [:foo, 0]
|
28
|
+
csv << [:bar, 1]
|
29
|
+
csv << [:baz, 2]
|
30
|
+
end
|
31
|
+
str # => "foo,0|bar,1|baz,2|"
|
32
|
+
ary = CSV.parse(str, row_sep: row_sep)
|
33
|
+
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
|
34
|
+
|
35
|
+
Using <tt>--</tt> (two hyphens):
|
36
|
+
row_sep = '--'
|
37
|
+
str = CSV.generate(row_sep: row_sep) do |csv|
|
38
|
+
csv << [:foo, 0]
|
39
|
+
csv << [:bar, 1]
|
40
|
+
csv << [:baz, 2]
|
41
|
+
end
|
42
|
+
str # => "foo,0--bar,1--baz,2--"
|
43
|
+
ary = CSV.parse(str, row_sep: row_sep)
|
44
|
+
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
|
45
|
+
|
46
|
+
Using <tt>''</tt> (empty string):
|
47
|
+
row_sep = ''
|
48
|
+
str = CSV.generate(row_sep: row_sep) do |csv|
|
49
|
+
csv << [:foo, 0]
|
50
|
+
csv << [:bar, 1]
|
51
|
+
csv << [:baz, 2]
|
52
|
+
end
|
53
|
+
str # => "foo,0bar,1baz,2"
|
54
|
+
ary = CSV.parse(str, row_sep: row_sep)
|
55
|
+
ary # => [["foo", "0bar", "1baz", "2"]]
|
56
|
+
|
57
|
+
---
|
58
|
+
|
59
|
+
When +row_sep+ is the \Symbol +:auto+ (the default),
|
60
|
+
invokes auto-discovery of the row separator.
|
61
|
+
|
62
|
+
Auto-discovery reads ahead in the data looking for the next <tt>\r\n</tt>, +\n+, or +\r+ sequence.
|
63
|
+
The sequence will be selected even if it occurs in a quoted field,
|
64
|
+
assuming that you would have the same line endings there.
|
65
|
+
|
66
|
+
row_sep = :auto
|
67
|
+
str = CSV.generate(row_sep: row_sep) do |csv|
|
68
|
+
csv << [:foo, 0]
|
69
|
+
csv << [:bar, 1]
|
70
|
+
csv << [:baz, 2]
|
71
|
+
end
|
72
|
+
str # => "foo,0\nbar,1\nbaz,2\n"
|
73
|
+
ary = CSV.parse(str, row_sep: row_sep)
|
74
|
+
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
|
75
|
+
|
76
|
+
The default <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>) is used
|
77
|
+
if any of the following is true:
|
78
|
+
* None of those sequences is found.
|
79
|
+
* Data is +ARGF+, +STDIN+, +STDOUT+, or +STDERR+.
|
80
|
+
* The stream is only available for output.
|
81
|
+
|
82
|
+
Obviously, discovery takes a little time. Set manually if speed is important. Also note that IO objects should be opened in binary mode on Windows if this feature will be used as the line-ending translation can cause problems with resetting the document position to where it was before the read ahead.
|
83
|
+
|
84
|
+
---
|
85
|
+
|
86
|
+
Raises an exception if the given value is not String-convertible:
|
87
|
+
row_sep = BasicObject.new
|
88
|
+
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
|
89
|
+
CSV.generate_line(ary, row_sep: row_sep)
|
90
|
+
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
|
91
|
+
CSV.parse(str, row_sep: row_sep)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
====== Option +skip_blanks+
|
2
|
+
|
3
|
+
Specifies a boolean that determines whether blank lines in the input will be ignored;
|
4
|
+
a line that contains a column separator is not considered to be blank.
|
5
|
+
|
6
|
+
Default value:
|
7
|
+
CSV::DEFAULT_OPTIONS.fetch(:skip_blanks) # => false
|
8
|
+
|
9
|
+
See also option {skiplines}[#class-CSV-label-Option+skip_lines].
|
10
|
+
|
11
|
+
For examples in this section:
|
12
|
+
str = <<-EOT
|
13
|
+
foo,0
|
14
|
+
|
15
|
+
bar,1
|
16
|
+
baz,2
|
17
|
+
|
18
|
+
,
|
19
|
+
EOT
|
20
|
+
|
21
|
+
Using the default, +false+:
|
22
|
+
ary = CSV.parse(str)
|
23
|
+
ary # => [["foo", "0"], [], ["bar", "1"], ["baz", "2"], [], [nil, nil]]
|
24
|
+
|
25
|
+
Using +true+:
|
26
|
+
ary = CSV.parse(str, skip_blanks: true)
|
27
|
+
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
|
28
|
+
|
29
|
+
Using a truthy value:
|
30
|
+
ary = CSV.parse(str, skip_blanks: :foo)
|
31
|
+
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
|
data/doc/skip_lines.rdoc
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
====== Option +skip_lines+
|
2
|
+
|
3
|
+
Specifies an object to use in identifying comment lines in the input that are to be ignored:
|
4
|
+
* If a \Regexp, ignores lines that match it.
|
5
|
+
* If a \String, converts it to a \Regexp, ignores lines that match it.
|
6
|
+
* If +nil+, no lines are considered to be comments.
|
7
|
+
|
8
|
+
Default value:
|
9
|
+
CSV::DEFAULT_OPTIONS.fetch(:skip_lines) # => nil
|
10
|
+
|
11
|
+
For examples in this section:
|
12
|
+
str = <<-EOT
|
13
|
+
# Comment
|
14
|
+
foo,0
|
15
|
+
bar,1
|
16
|
+
baz,2
|
17
|
+
# Another comment
|
18
|
+
EOT
|
19
|
+
str # => "# Comment\nfoo,0\nbar,1\nbaz,2\n# Another comment\n"
|
20
|
+
|
21
|
+
Using the default, +nil+:
|
22
|
+
ary = CSV.parse(str)
|
23
|
+
ary # => [["# Comment"], ["foo", "0"], ["bar", "1"], ["baz", "2"], ["# Another comment"]]
|
24
|
+
|
25
|
+
Using a \Regexp:
|
26
|
+
ary = CSV.parse(str, skip_lines: /^#/)
|
27
|
+
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
|
28
|
+
|
29
|
+
Using a \String:
|
30
|
+
ary = CSV.parse(str, skip_lines: '#')
|
31
|
+
ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
|
32
|
+
|
33
|
+
---
|
34
|
+
|
35
|
+
Raises an exception if given an object that is not a \Regexp, a \String, or +nil+:
|
36
|
+
# Raises ArgumentError (:skip_lines has to respond to #match: 0)
|
37
|
+
CSV.parse(str, skip_lines: 0)
|
data/doc/strip.rdoc
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
====== Option +strip+
|
2
|
+
|
3
|
+
Specifies the boolean value that determines whether
|
4
|
+
whitespace is stripped from each input field.
|
5
|
+
|
6
|
+
Default value:
|
7
|
+
CSV::DEFAULT_OPTIONS.fetch(:strip) # => false
|
8
|
+
|
9
|
+
With default value +false+:
|
10
|
+
ary = CSV.parse_line(' a , b ')
|
11
|
+
ary # => [" a ", " b "]
|
12
|
+
|
13
|
+
With value +true+:
|
14
|
+
ary = CSV.parse_line(' a , b ', strip: true)
|
15
|
+
ary # => ["a", "b"]
|
@@ -0,0 +1,27 @@
|
|
1
|
+
====== Option +unconverted_fields+
|
2
|
+
|
3
|
+
Specifies the boolean that determines whether unconverted field values are to be available.
|
4
|
+
|
5
|
+
Default value:
|
6
|
+
CSV::DEFAULT_OPTIONS.fetch(:unconverted_fields) # => nil
|
7
|
+
|
8
|
+
The unconverted field values are those found in the source data,
|
9
|
+
prior to any conversions performed via option +converters+.
|
10
|
+
|
11
|
+
When option +unconverted_fields+ is +true+,
|
12
|
+
each returned row (\Array or \CSV::Row) has an added method,
|
13
|
+
+unconverted_fields+, that returns the unconverted field values:
|
14
|
+
str = <<-EOT
|
15
|
+
foo,0
|
16
|
+
bar,1
|
17
|
+
baz,2
|
18
|
+
EOT
|
19
|
+
# Without unconverted_fields
|
20
|
+
csv = CSV.parse(str, converters: :integer)
|
21
|
+
csv # => [["foo", 0], ["bar", 1], ["baz", 2]]
|
22
|
+
csv.first.respond_to?(:unconverted_fields) # => false
|
23
|
+
# With unconverted_fields
|
24
|
+
csv = CSV.parse(str, converters: :integer, unconverted_fields: true)
|
25
|
+
csv # => [["foo", 0], ["bar", 1], ["baz", 2]]
|
26
|
+
csv.first.respond_to?(:unconverted_fields) # => true
|
27
|
+
csv.first.unconverted_fields # => ["foo", "0"]
|
@@ -0,0 +1,31 @@
|
|
1
|
+
====== Option +write_converters+
|
2
|
+
|
3
|
+
Specifies the \Proc or \Array of Procs that are to be called
|
4
|
+
for converting each output field.
|
5
|
+
|
6
|
+
Default value:
|
7
|
+
CSV::DEFAULT_OPTIONS.fetch(:write_converters) # => nil
|
8
|
+
|
9
|
+
With no write converter:
|
10
|
+
str = CSV.generate_line(["\na\n", "\tb\t", " c "])
|
11
|
+
str # => "\"\na\n\",\tb\t, c \n"
|
12
|
+
|
13
|
+
With a write converter:
|
14
|
+
strip_converter = lambda {|field| field.strip }
|
15
|
+
str = CSV.generate_line(["\na\n", "\tb\t", " c "], write_converters: strip_converter)
|
16
|
+
str # => "a,b,c\n"
|
17
|
+
|
18
|
+
With two write converters (called in order):
|
19
|
+
upcase_converter = lambda {|field| field.upcase }
|
20
|
+
downcase_converter = lambda {|field| field.downcase }
|
21
|
+
write_converters = [upcase_converter, downcase_converter]
|
22
|
+
str = CSV.generate_line(['a', 'b', 'c'], write_converters: write_converters)
|
23
|
+
str # => "a,b,c\n"
|
24
|
+
|
25
|
+
---
|
26
|
+
|
27
|
+
Raises an exception if the converter returns a value that is neither +nil+
|
28
|
+
nor \String-convertible:
|
29
|
+
bad_converter = lambda {|field| BasicObject.new }
|
30
|
+
# Raises NoMethodError (undefined method `is_a?' for #<BasicObject:>)
|
31
|
+
CSV.generate_line(['a', 'b', 'c'], write_converters: bad_converter)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
====== Option +write_empty_value+
|
2
|
+
|
3
|
+
Specifies the object that is to be substituted for each field
|
4
|
+
that has an empty \String.
|
5
|
+
|
6
|
+
Default value:
|
7
|
+
CSV::DEFAULT_OPTIONS.fetch(:write_empty_value) # => ""
|
8
|
+
|
9
|
+
Without the option:
|
10
|
+
str = CSV.generate_line(['a', '', 'c', ''])
|
11
|
+
str # => "a,\"\",c,\"\"\n"
|
12
|
+
|
13
|
+
With the option:
|
14
|
+
str = CSV.generate_line(['a', '', 'c', ''], write_empty_value: "x")
|
15
|
+
str # => "a,x,c,x\n"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
====== Option +write_headers+
|
2
|
+
|
3
|
+
Specifies the boolean that determines whether a header row is included in the output;
|
4
|
+
ignored if there are no headers.
|
5
|
+
|
6
|
+
Default value:
|
7
|
+
CSV::DEFAULT_OPTIONS.fetch(:write_headers) # => nil
|
8
|
+
|
9
|
+
Without +write_headers+:
|
10
|
+
file_path = 't.csv'
|
11
|
+
CSV.open(file_path,'w',
|
12
|
+
:headers => ['Name','Value']
|
13
|
+
) do |csv|
|
14
|
+
csv << ['foo', '0']
|
15
|
+
end
|
16
|
+
CSV.open(file_path) do |csv|
|
17
|
+
csv.shift
|
18
|
+
end # => ["foo", "0"]
|
19
|
+
|
20
|
+
With +write_headers+":
|
21
|
+
CSV.open(file_path,'w',
|
22
|
+
:write_headers=> true,
|
23
|
+
:headers => ['Name','Value']
|
24
|
+
) do |csv|
|
25
|
+
csv << ['foo', '0']
|
26
|
+
end
|
27
|
+
CSV.open(file_path) do |csv|
|
28
|
+
csv.shift
|
29
|
+
end # => ["Name", "Value"]
|
@@ -0,0 +1,14 @@
|
|
1
|
+
====== Option +write_nil_value+
|
2
|
+
|
3
|
+
Specifies the object that is to be substituted for each +nil+ field.
|
4
|
+
|
5
|
+
Default value:
|
6
|
+
CSV::DEFAULT_OPTIONS.fetch(:write_nil_value) # => nil
|
7
|
+
|
8
|
+
Without the option:
|
9
|
+
str = CSV.generate_line(['a', nil, 'c', nil])
|
10
|
+
str # => "a,,c,\n"
|
11
|
+
|
12
|
+
With the option:
|
13
|
+
str = CSV.generate_line(['a', nil, 'c', nil], write_nil_value: "x")
|
14
|
+
str # => "a,x,c,x\n"
|
data/lib/csv.rb
CHANGED
@@ -109,7 +109,7 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
|
|
109
109
|
#
|
110
110
|
# The most generic interface of the library is:
|
111
111
|
#
|
112
|
-
# csv = CSV.new(
|
112
|
+
# csv = CSV.new(io, **options)
|
113
113
|
#
|
114
114
|
# # Reading: IO object should be open for read
|
115
115
|
# csv.read # => array of rows
|
@@ -809,19 +809,37 @@ class CSV
|
|
809
809
|
csv.string # return final String
|
810
810
|
end
|
811
811
|
|
812
|
+
# :call-seq:
|
813
|
+
# CSV.generate_line(ary)
|
814
|
+
# CSV.generate_line(ary, **options)
|
812
815
|
#
|
813
|
-
#
|
814
|
-
#
|
816
|
+
# Returns the \String created by generating \CSV from +ary+
|
817
|
+
# using the specified +options+.
|
815
818
|
#
|
816
|
-
#
|
819
|
+
# Argument +ary+ must be an \Array.
|
820
|
+
#
|
821
|
+
# Special options:
|
822
|
+
# * Option <tt>:row_sep</tt> defaults to <tt>$INPUT_RECORD_SEPARATOR</tt>
|
823
|
+
# (<tt>$/</tt>).:
|
824
|
+
# $INPUT_RECORD_SEPARATOR # => "\n"
|
825
|
+
# * This method accepts an additional option, <tt>:encoding</tt>, which sets the base
|
826
|
+
# Encoding for the output. This method will try to guess your Encoding from
|
827
|
+
# the first non-+nil+ field in +row+, if possible, but you may need to use
|
828
|
+
# this parameter as a backup plan.
|
829
|
+
#
|
830
|
+
# For other +options+,
|
831
|
+
# see {Options for Generating}[#class-CSV-label-Options+for+Generating].
|
817
832
|
#
|
818
|
-
#
|
819
|
-
# Encoding for the output. This method will try to guess your Encoding from
|
820
|
-
# the first non-+nil+ field in +row+, if possible, but you may need to use
|
821
|
-
# this parameter as a backup plan.
|
833
|
+
# ---
|
822
834
|
#
|
823
|
-
#
|
824
|
-
#
|
835
|
+
# Returns the \String generated from an \Array:
|
836
|
+
# CSV.generate_line(['foo', '0']) # => "foo,0\n"
|
837
|
+
#
|
838
|
+
# ---
|
839
|
+
#
|
840
|
+
# Raises an exception if +ary+ is not an \Array:
|
841
|
+
# # Raises NoMethodError (undefined method `find' for :foo:Symbol)
|
842
|
+
# CSV.generate_line(:foo)
|
825
843
|
#
|
826
844
|
def generate_line(row, **options)
|
827
845
|
options = {row_sep: $INPUT_RECORD_SEPARATOR}.merge(options)
|
@@ -955,12 +973,41 @@ class CSV
|
|
955
973
|
end
|
956
974
|
end
|
957
975
|
|
976
|
+
# :call-seq:
|
977
|
+
# CSV.parse_line(string)
|
978
|
+
# CSV.parse_line(io)
|
979
|
+
# CSV.parse_line(string, **options)
|
980
|
+
# CSV.parse_line(io, **options)
|
958
981
|
#
|
959
|
-
#
|
960
|
-
#
|
961
|
-
# first row is ignored.
|
982
|
+
# Returns the new \Array created by parsing the first line of +string+ or +io+
|
983
|
+
# using the specified +options+.
|
962
984
|
#
|
963
|
-
#
|
985
|
+
# Argument +string+ should be a \String object;
|
986
|
+
# it will be put into a new \StringIO object positioned at the beginning.
|
987
|
+
#
|
988
|
+
# Argument +io+ should be an \IO object; it will be positioned at the beginning.
|
989
|
+
#
|
990
|
+
# For +options+, see {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
|
991
|
+
#
|
992
|
+
# ---
|
993
|
+
# Returns data from the first line from a String object:
|
994
|
+
# CSV.parse_line('foo,0') # => ["foo", "0"]
|
995
|
+
#
|
996
|
+
# Returns data from the first line from a File object:
|
997
|
+
# File.write('t.csv', 'foo,0')
|
998
|
+
# CSV.parse_line(File.open('t.csv')) # => ["foo", "0"]
|
999
|
+
#
|
1000
|
+
# Ignores lines after the first:
|
1001
|
+
# CSV.parse_line("foo,0\nbar,1\nbaz,2") # => ["foo", "0"]
|
1002
|
+
#
|
1003
|
+
# Returns +nil+ if the argument is an empty \String:
|
1004
|
+
# CSV.parse_line('') # => nil
|
1005
|
+
#
|
1006
|
+
# ---
|
1007
|
+
#
|
1008
|
+
# Raises an exception if the argument is +nil+:
|
1009
|
+
# # Raises ArgumentError (Cannot parse nil as CSV):
|
1010
|
+
# CSV.parse_line(nil)
|
964
1011
|
#
|
965
1012
|
def parse_line(line, **options)
|
966
1013
|
new(line, **options).each.first
|
@@ -1008,22 +1055,49 @@ class CSV
|
|
1008
1055
|
end
|
1009
1056
|
end
|
1010
1057
|
|
1058
|
+
# :call-seq:
|
1059
|
+
# CSV.new(string)
|
1060
|
+
# CSV.new(io)
|
1061
|
+
# CSV.new(string, **options)
|
1062
|
+
# CSV.new(io, **options)
|
1063
|
+
#
|
1064
|
+
# Returns the new \CSV object created using +string+ or +io+
|
1065
|
+
# and the specified +options+.
|
1066
|
+
#
|
1067
|
+
# Argument +string+ should be a \String object;
|
1068
|
+
# it will be put into a new \StringIO object positioned at the beginning.
|
1069
|
+
#
|
1070
|
+
# Argument +io+ should be an \IO object; it will be positioned at the beginning.
|
1071
|
+
#
|
1072
|
+
# To position at the end, for appending, use method CSV.generate.
|
1073
|
+
# For any other positioning, pass a preset StringIO object instead.
|
1074
|
+
#
|
1075
|
+
# In addition to the \CSV instance methods, several \IO
|
1076
|
+
# methods are delegated. See CSV::open for a complete list.
|
1077
|
+
#
|
1078
|
+
# For +options+, see:
|
1079
|
+
# * {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
|
1080
|
+
# * {Options for Generating}[#class-CSV-label-Options+for+Generating]
|
1081
|
+
#
|
1082
|
+
# For performance reasons, the options cannot be overridden
|
1083
|
+
# in a \CSV object, so the options specified here will endure.
|
1084
|
+
#
|
1085
|
+
# ---
|
1011
1086
|
#
|
1012
|
-
#
|
1013
|
-
#
|
1014
|
-
#
|
1015
|
-
# a String for +data+, you can later retrieve it (after writing to it, for
|
1016
|
-
# example) with CSV.string().
|
1087
|
+
# Create a \CSV object from a \String object:
|
1088
|
+
# csv = CSV.new('foo,0')
|
1089
|
+
# csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
|
1017
1090
|
#
|
1018
|
-
#
|
1019
|
-
#
|
1020
|
-
#
|
1091
|
+
# Create a \CSV object from a \File object:
|
1092
|
+
# File.write('t.csv', 'foo,0')
|
1093
|
+
# csv = CSV.new(File.open('t.csv'))
|
1094
|
+
# csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
|
1021
1095
|
#
|
1022
|
-
#
|
1023
|
-
# and {Options for Generating}[#class-CSV-label-Options+for+Generating].
|
1096
|
+
# ---
|
1024
1097
|
#
|
1025
|
-
#
|
1026
|
-
#
|
1098
|
+
# Raises an exception if the argument is +nil+:
|
1099
|
+
# # Raises ArgumentError (Cannot parse nil as CSV):
|
1100
|
+
# CSV.new(nil)
|
1027
1101
|
#
|
1028
1102
|
def initialize(data,
|
1029
1103
|
col_sep: ",",
|
data/lib/csv/version.rb
CHANGED
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.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Edward Gray II
|
@@ -75,11 +75,35 @@ email:
|
|
75
75
|
- kou@cozmixng.org
|
76
76
|
executables: []
|
77
77
|
extensions: []
|
78
|
-
extra_rdoc_files:
|
78
|
+
extra_rdoc_files:
|
79
|
+
- LICENSE.txt
|
80
|
+
- NEWS.md
|
81
|
+
- README.md
|
79
82
|
files:
|
80
83
|
- LICENSE.txt
|
81
84
|
- NEWS.md
|
82
85
|
- 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
|
83
107
|
- lib/csv.rb
|
84
108
|
- lib/csv/core_ext/array.rb
|
85
109
|
- lib/csv/core_ext/string.rb
|
@@ -96,7 +120,9 @@ licenses:
|
|
96
120
|
- BSD-2-Clause
|
97
121
|
metadata: {}
|
98
122
|
post_install_message:
|
99
|
-
rdoc_options:
|
123
|
+
rdoc_options:
|
124
|
+
- "--main"
|
125
|
+
- README.md
|
100
126
|
require_paths:
|
101
127
|
- lib
|
102
128
|
required_ruby_version: !ruby/object:Gem::Requirement
|