csv 3.1.3 → 3.1.8
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 +110 -0
- data/README.md +5 -0
- data/doc/csv/arguments/io.rdoc +5 -0
- data/doc/csv/options/common/col_sep.rdoc +57 -0
- data/doc/csv/options/common/quote_char.rdoc +42 -0
- data/doc/csv/options/common/row_sep.rdoc +91 -0
- data/doc/csv/options/generating/force_quotes.rdoc +17 -0
- data/doc/csv/options/generating/quote_empty.rdoc +12 -0
- data/doc/csv/options/generating/write_converters.rdoc +25 -0
- data/doc/csv/options/generating/write_empty_value.rdoc +15 -0
- data/doc/csv/options/generating/write_headers.rdoc +29 -0
- data/doc/csv/options/generating/write_nil_value.rdoc +14 -0
- data/doc/csv/options/parsing/converters.rdoc +46 -0
- data/doc/csv/options/parsing/empty_value.rdoc +13 -0
- data/doc/csv/options/parsing/field_size_limit.rdoc +39 -0
- data/doc/csv/options/parsing/header_converters.rdoc +43 -0
- data/doc/csv/options/parsing/headers.rdoc +63 -0
- data/doc/csv/options/parsing/liberal_parsing.rdoc +19 -0
- data/doc/csv/options/parsing/nil_value.rdoc +12 -0
- data/doc/csv/options/parsing/return_headers.rdoc +22 -0
- data/doc/csv/options/parsing/skip_blanks.rdoc +31 -0
- data/doc/csv/options/parsing/skip_lines.rdoc +37 -0
- data/doc/csv/options/parsing/strip.rdoc +15 -0
- data/doc/csv/options/parsing/unconverted_fields.rdoc +27 -0
- data/doc/csv/recipes/filtering.rdoc +158 -0
- data/doc/csv/recipes/generating.rdoc +298 -0
- data/doc/csv/recipes/parsing.rdoc +545 -0
- data/doc/csv/recipes/recipes.rdoc +6 -0
- data/lib/csv.rb +1724 -568
- data/lib/csv/fields_converter.rb +1 -1
- data/lib/csv/parser.rb +1 -1
- data/lib/csv/row.rb +477 -132
- data/lib/csv/table.rb +750 -108
- data/lib/csv/version.rb +1 -1
- data/lib/csv/writer.rb +45 -4
- metadata +41 -6
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
====== Option +write_nil_value+
|
|
2
|
+
|
|
3
|
+
Specifies the object that is to be substituted for each +nil+-valued 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"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
====== Option +converters+
|
|
2
|
+
|
|
3
|
+
Specifies converters to be used in parsing fields.
|
|
4
|
+
See {Field Converters}[#class-CSV-label-Field+Converters]
|
|
5
|
+
|
|
6
|
+
Default value:
|
|
7
|
+
CSV::DEFAULT_OPTIONS.fetch(:converters) # => nil
|
|
8
|
+
|
|
9
|
+
The value may be a field converter name
|
|
10
|
+
(see {Stored Converters}[#class-CSV-label-Stored+Converters]):
|
|
11
|
+
str = '1,2,3'
|
|
12
|
+
# Without a converter
|
|
13
|
+
array = CSV.parse_line(str)
|
|
14
|
+
array # => ["1", "2", "3"]
|
|
15
|
+
# With built-in converter :integer
|
|
16
|
+
array = CSV.parse_line(str, converters: :integer)
|
|
17
|
+
array # => [1, 2, 3]
|
|
18
|
+
|
|
19
|
+
The value may be a converter list
|
|
20
|
+
(see {Converter Lists}[#class-CSV-label-Converter+Lists]):
|
|
21
|
+
str = '1,3.14159'
|
|
22
|
+
# Without converters
|
|
23
|
+
array = CSV.parse_line(str)
|
|
24
|
+
array # => ["1", "3.14159"]
|
|
25
|
+
# With built-in converters
|
|
26
|
+
array = CSV.parse_line(str, converters: [:integer, :float])
|
|
27
|
+
array # => [1, 3.14159]
|
|
28
|
+
|
|
29
|
+
The value may be a \Proc custom converter:
|
|
30
|
+
(see {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters]):
|
|
31
|
+
str = ' foo , bar , baz '
|
|
32
|
+
# Without a converter
|
|
33
|
+
array = CSV.parse_line(str)
|
|
34
|
+
array # => [" foo ", " bar ", " baz "]
|
|
35
|
+
# With a custom converter
|
|
36
|
+
array = CSV.parse_line(str, converters: proc {|field| field.strip })
|
|
37
|
+
array # => ["foo", "bar", "baz"]
|
|
38
|
+
|
|
39
|
+
See also {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters]
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
Raises an exception if the converter is not a converter name or a \Proc:
|
|
44
|
+
str = 'foo,0'
|
|
45
|
+
# Raises NoMethodError (undefined method `arity' for nil:NilClass)
|
|
46
|
+
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,43 @@
|
|
|
1
|
+
====== Option +header_converters+
|
|
2
|
+
|
|
3
|
+
Specifies converters to be used in parsing headers.
|
|
4
|
+
See {Header Converters}[#class-CSV-label-Header+Converters]
|
|
5
|
+
|
|
6
|
+
Default value:
|
|
7
|
+
CSV::DEFAULT_OPTIONS.fetch(:header_converters) # => nil
|
|
8
|
+
|
|
9
|
+
Identical in functionality to option {converters}[#class-CSV-label-Option+converters]
|
|
10
|
+
except that:
|
|
11
|
+
- The converters apply only to the header row.
|
|
12
|
+
- The built-in header converters are +:downcase+ and +:symbol+.
|
|
13
|
+
|
|
14
|
+
This section assumes prior execution of:
|
|
15
|
+
str = <<-EOT
|
|
16
|
+
Name,Value
|
|
17
|
+
foo,0
|
|
18
|
+
bar,1
|
|
19
|
+
baz,2
|
|
20
|
+
EOT
|
|
21
|
+
# With no header converter
|
|
22
|
+
table = CSV.parse(str, headers: true)
|
|
23
|
+
table.headers # => ["Name", "Value"]
|
|
24
|
+
|
|
25
|
+
The value may be a header converter name
|
|
26
|
+
(see {Stored Converters}[#class-CSV-label-Stored+Converters]):
|
|
27
|
+
table = CSV.parse(str, headers: true, header_converters: :downcase)
|
|
28
|
+
table.headers # => ["name", "value"]
|
|
29
|
+
|
|
30
|
+
The value may be a converter list
|
|
31
|
+
(see {Converter Lists}[#class-CSV-label-Converter+Lists]):
|
|
32
|
+
header_converters = [:downcase, :symbol]
|
|
33
|
+
table = CSV.parse(str, headers: true, header_converters: header_converters)
|
|
34
|
+
table.headers # => [:name, :value]
|
|
35
|
+
|
|
36
|
+
The value may be a \Proc custom converter
|
|
37
|
+
(see {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters]):
|
|
38
|
+
upcase_converter = proc {|field| field.upcase }
|
|
39
|
+
table = CSV.parse(str, headers: true, header_converters: upcase_converter)
|
|
40
|
+
table.headers # => ["NAME", "VALUE"]
|
|
41
|
+
|
|
42
|
+
See also {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters]
|
|
43
|
+
|
|
@@ -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"]
|
|
@@ -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"]
|
|
@@ -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
|
+
|
|
@@ -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]]
|
|
@@ -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)
|
|
@@ -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,158 @@
|
|
|
1
|
+
== Recipes for Filtering \CSV
|
|
2
|
+
|
|
3
|
+
These recipes are specific code examples for specific \CSV filtering tasks.
|
|
4
|
+
|
|
5
|
+
For other recipes, see {Recipes for CSV}[./recipes_rdoc.html].
|
|
6
|
+
|
|
7
|
+
All code snippets on this page assume that the following has been executed:
|
|
8
|
+
require 'csv'
|
|
9
|
+
|
|
10
|
+
=== Contents
|
|
11
|
+
|
|
12
|
+
- {Source and Output Formats}[#label-Source+and+Output+Formats]
|
|
13
|
+
- {Filtering String to String}[#label-Filtering+String+to+String]
|
|
14
|
+
- {Recipe: Filter String to String with Headers}[#label-Recipe-3A+Filter+String+to+String+with+Headers]
|
|
15
|
+
- {Recipe: Filter String to String Without Headers}[#label-Recipe-3A+Filter+String+to+String+Without+Headers]
|
|
16
|
+
- {Filtering String to IO Stream}[#label-Filtering+String+to+IO+Stream]
|
|
17
|
+
- {Recipe: Filter String to IO Stream with Headers}[#label-Recipe-3A+Filter+String+to+IO+Stream+with+Headers]
|
|
18
|
+
- {Recipe: Filter String to IO Stream Without Headers}[#label-Recipe-3A+Filter+String+to+IO+Stream+Without+Headers]
|
|
19
|
+
- {Filtering IO Stream to String}[#label-Filtering+IO+Stream+to+String]
|
|
20
|
+
- {Recipe: Filter IO Stream to String with Headers}[#label-Recipe-3A+Filter+IO+Stream+to+String+with+Headers]
|
|
21
|
+
- {Recipe: Filter IO Stream to String Without Headers}[#label-Recipe-3A+Filter+IO+Stream+to+String+Without+Headers]
|
|
22
|
+
- {Filtering IO Stream to IO Stream}[#label-Filtering+IO+Stream+to+IO+Stream]
|
|
23
|
+
- {Recipe: Filter IO Stream to IO Stream with Headers}[#label-Recipe-3A+Filter+IO+Stream+to+IO+Stream+with+Headers]
|
|
24
|
+
- {Recipe: Filter IO Stream to IO Stream Without Headers}[#label-Recipe-3A+Filter+IO+Stream+to+IO+Stream+Without+Headers]
|
|
25
|
+
|
|
26
|
+
=== Source and Output Formats
|
|
27
|
+
|
|
28
|
+
You can use a Unix-style "filter" for \CSV data.
|
|
29
|
+
The filter reads source \CSV data and writes output \CSV data as modified by the filter.
|
|
30
|
+
The input and output \CSV data may be any mixture of \Strings and \IO streams.
|
|
31
|
+
|
|
32
|
+
==== Filtering \String to \String
|
|
33
|
+
|
|
34
|
+
You can filter one \String to another, with or without headers.
|
|
35
|
+
|
|
36
|
+
===== Recipe: Filter \String to \String with Headers
|
|
37
|
+
|
|
38
|
+
Use class method CSV.filter with option +headers+ to filter a \String to another \String:
|
|
39
|
+
in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
|
|
40
|
+
out_string = ''
|
|
41
|
+
CSV.filter(in_string, out_string, headers: true) do |row|
|
|
42
|
+
row[0] = row[0].upcase
|
|
43
|
+
row[1] *= 4
|
|
44
|
+
end
|
|
45
|
+
out_string # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
|
|
46
|
+
|
|
47
|
+
===== Recipe: Filter \String to \String Without Headers
|
|
48
|
+
|
|
49
|
+
Use class method CSV.filter without option +headers+ to filter a \String to another \String:
|
|
50
|
+
in_string = "foo,0\nbar,1\nbaz,2\n"
|
|
51
|
+
out_string = ''
|
|
52
|
+
CSV.filter(in_string, out_string) do |row|
|
|
53
|
+
row[0] = row[0].upcase
|
|
54
|
+
row[1] *= 4
|
|
55
|
+
end
|
|
56
|
+
out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
|
|
57
|
+
|
|
58
|
+
==== Filtering \String to \IO Stream
|
|
59
|
+
|
|
60
|
+
You can filter a \String to an \IO stream, with or without headers.
|
|
61
|
+
|
|
62
|
+
===== Recipe: Filter \String to \IO Stream with Headers
|
|
63
|
+
|
|
64
|
+
Use class method CSV.filter with option +headers+ to filter a \String to an \IO stream:
|
|
65
|
+
in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
|
|
66
|
+
path = 't.csv'
|
|
67
|
+
File.open(path, 'w') do |out_io|
|
|
68
|
+
CSV.filter(in_string, out_io, headers: true) do |row|
|
|
69
|
+
row[0] = row[0].upcase
|
|
70
|
+
row[1] *= 4
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
p File.read(path) # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
|
|
74
|
+
|
|
75
|
+
===== Recipe: Filter \String to \IO Stream Without Headers
|
|
76
|
+
|
|
77
|
+
Use class method CSV.filter without option +headers+ to filter a \String to an \IO stream:
|
|
78
|
+
in_string = "foo,0\nbar,1\nbaz,2\n"
|
|
79
|
+
path = 't.csv'
|
|
80
|
+
File.open(path, 'w') do |out_io|
|
|
81
|
+
CSV.filter(in_string, out_io) do |row|
|
|
82
|
+
row[0] = row[0].upcase
|
|
83
|
+
row[1] *= 4
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
p File.read(path) # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
|
|
87
|
+
|
|
88
|
+
==== Filtering \IO Stream to \String
|
|
89
|
+
|
|
90
|
+
You can filter an \IO stream to a \String, with or without headers.
|
|
91
|
+
|
|
92
|
+
===== Recipe: Filter \IO Stream to \String with Headers
|
|
93
|
+
|
|
94
|
+
Use class method CSV.filter with option +headers+ to filter an \IO stream to a \String:
|
|
95
|
+
in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
|
|
96
|
+
path = 't.csv'
|
|
97
|
+
File.write(path, in_string)
|
|
98
|
+
out_string = ''
|
|
99
|
+
File.open(path, headers: true) do |in_io|
|
|
100
|
+
CSV.filter(in_io, out_string, headers: true) do |row|
|
|
101
|
+
row[0] = row[0].upcase
|
|
102
|
+
row[1] *= 4
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
out_string # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
|
|
106
|
+
|
|
107
|
+
===== Recipe: Filter \IO Stream to \String Without Headers
|
|
108
|
+
|
|
109
|
+
Use class method CSV.filter without option +headers+ to filter an \IO stream to a \String:
|
|
110
|
+
in_string = "foo,0\nbar,1\nbaz,2\n"
|
|
111
|
+
path = 't.csv'
|
|
112
|
+
File.write(path, in_string)
|
|
113
|
+
out_string = ''
|
|
114
|
+
File.open(path) do |in_io|
|
|
115
|
+
CSV.filter(in_io, out_string) do |row|
|
|
116
|
+
row[0] = row[0].upcase
|
|
117
|
+
row[1] *= 4
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
|
|
121
|
+
|
|
122
|
+
==== Filtering \IO Stream to \IO Stream
|
|
123
|
+
|
|
124
|
+
You can filter an \IO stream to another \IO stream, with or without headers.
|
|
125
|
+
|
|
126
|
+
===== Recipe: Filter \IO Stream to \IO Stream with Headers
|
|
127
|
+
|
|
128
|
+
Use class method CSV.filter with option +headers+ to filter an \IO stream to another \IO stream:
|
|
129
|
+
in_path = 't.csv'
|
|
130
|
+
in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
|
|
131
|
+
File.write(in_path, in_string)
|
|
132
|
+
out_path = 'u.csv'
|
|
133
|
+
File.open(in_path) do |in_io|
|
|
134
|
+
File.open(out_path, 'w') do |out_io|
|
|
135
|
+
CSV.filter(in_io, out_io, headers: true) do |row|
|
|
136
|
+
row[0] = row[0].upcase
|
|
137
|
+
row[1] *= 4
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
p File.read(out_path) # => "Name,Value\nFOO,0000\nBAR,1111\nBAZ,2222\n"
|
|
142
|
+
|
|
143
|
+
===== Recipe: Filter \IO Stream to \IO Stream Without Headers
|
|
144
|
+
|
|
145
|
+
Use class method CSV.filter without option +headers+ to filter an \IO stream to another \IO stream:
|
|
146
|
+
in_path = 't.csv'
|
|
147
|
+
in_string = "foo,0\nbar,1\nbaz,2\n"
|
|
148
|
+
File.write(in_path, in_string)
|
|
149
|
+
out_path = 'u.csv'
|
|
150
|
+
File.open(in_path) do |in_io|
|
|
151
|
+
File.open(out_path, 'w') do |out_io|
|
|
152
|
+
CSV.filter(in_io, out_io) do |row|
|
|
153
|
+
row[0] = row[0].upcase
|
|
154
|
+
row[1] *= 4
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
p File.read(out_path) # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
|