csv 3.1.7 → 3.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/NEWS.md +11 -0
- data/README.md +5 -0
- data/doc/csv/options/common/col_sep.rdoc +1 -7
- data/doc/csv/options/common/row_sep.rdoc +0 -9
- data/doc/csv/options/generating/write_converters.rdoc +0 -8
- 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 +67 -26
- data/lib/csv/row.rb +477 -132
- data/lib/csv/table.rb +486 -65
- data/lib/csv/version.rb +1 -1
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a9f965a5db6ac6d07f525f513e212f082c137b487d73328373d0afef7bb8312
|
4
|
+
data.tar.gz: 5184ad5878a6dee8603e3b48fc820b50e3687eafb96cbcec152a8d621ceaffd6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 422a1a8751e4e8c21884848e7f465e39090b946c3febff711bb756c98e61b7e6aebf0e552adee851d653f89e9ef2772984db2b05a243c7fac8060c64def34ae0
|
7
|
+
data.tar.gz: 9d85fa756cd744e74da2ae1e89650768370566a5fd8ce1830337d528f9875d07422508eb007522ae3e7ec9c20c9ec055983f09c9b951e78441706bb2d33fdd59
|
data/NEWS.md
CHANGED
data/README.md
CHANGED
@@ -31,6 +31,11 @@ CSV.foreach("path/to/file.csv") do |row|
|
|
31
31
|
end
|
32
32
|
```
|
33
33
|
|
34
|
+
## Documentation
|
35
|
+
|
36
|
+
- {API}[CSV.html]: all classes, methods, and constants.
|
37
|
+
- {Recipes}[doc/csv/recipes/recipes_rdoc.html]: specific code for specific tasks.
|
38
|
+
|
34
39
|
## Development
|
35
40
|
|
36
41
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -1,6 +1,6 @@
|
|
1
1
|
====== Option +col_sep+
|
2
2
|
|
3
|
-
Specifies the \String
|
3
|
+
Specifies the \String column separator to be used
|
4
4
|
for both parsing and generating.
|
5
5
|
The \String will be transcoded into the data's \Encoding before use.
|
6
6
|
|
@@ -55,9 +55,3 @@ Raises an exception if parsing with the empty \String:
|
|
55
55
|
# Raises ArgumentError (:col_sep must be 1 or more characters: "")
|
56
56
|
CSV.parse("foo0\nbar1\nbaz2\n", col_sep: col_sep)
|
57
57
|
|
58
|
-
Raises an exception if the given value is not String-convertible:
|
59
|
-
col_sep = BasicObject.new
|
60
|
-
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
|
61
|
-
CSV.generate(line, col_sep: col_sep)
|
62
|
-
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
|
63
|
-
CSV.parse(str, col_sep: col_sep)
|
@@ -89,12 +89,3 @@ if any of the following is true:
|
|
89
89
|
* The stream is only available for output.
|
90
90
|
|
91
91
|
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.
|
92
|
-
|
93
|
-
---
|
94
|
-
|
95
|
-
Raises an exception if the given value is not String-convertible:
|
96
|
-
row_sep = BasicObject.new
|
97
|
-
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
|
98
|
-
CSV.generate(ary, row_sep: row_sep)
|
99
|
-
# Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
|
100
|
-
CSV.parse(str, row_sep: row_sep)
|
@@ -23,11 +23,3 @@ With two write converters (called in order):
|
|
23
23
|
str # => "a,b,c\n"
|
24
24
|
|
25
25
|
See also {Write Converters}[#class-CSV-label-Write+Converters]
|
26
|
-
|
27
|
-
---
|
28
|
-
|
29
|
-
Raises an exception if the converter returns a value that is neither +nil+
|
30
|
-
nor \String-convertible:
|
31
|
-
bad_converter = proc {|field| BasicObject.new }
|
32
|
-
# Raises NoMethodError (undefined method `is_a?' for #<BasicObject:>)
|
33
|
-
CSV.generate_line(['a', 'b', 'c'], write_converters: bad_converter)
|
@@ -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"
|
@@ -0,0 +1,298 @@
|
|
1
|
+
== Recipes for Generating \CSV
|
2
|
+
|
3
|
+
These recipes are specific code examples for specific \CSV generating 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
|
+
- {Output Formats}[#label-Output+Formats]
|
13
|
+
- {Generating to a String}[#label-Generating+to+a+String]
|
14
|
+
- {Recipe: Generate to String with Headers}[#label-Recipe-3A+Generate+to+String+with+Headers]
|
15
|
+
- {Recipe: Generate to String Without Headers}[#label-Recipe-3A+Generate+to+String+Without+Headers]
|
16
|
+
- {Generating to a File}[#label-Generating+to+a+File]
|
17
|
+
- {Recipe: Generate to File with Headers}[#label-Recipe-3A+Generate+to+File+with+Headers]
|
18
|
+
- {Recipe: Generate to File Without Headers}[#label-Recipe-3A+Generate+to+File+Without+Headers]
|
19
|
+
- {Generating to IO an Stream}[#label-Generating+to+an+IO+Stream]
|
20
|
+
- {Recipe: Generate to IO Stream with Headers}[#label-Recipe-3A+Generate+to+IO+Stream+with+Headers]
|
21
|
+
- {Recipe: Generate to IO Stream Without Headers}[#label-Recipe-3A+Generate+to+IO+Stream+Without+Headers]
|
22
|
+
- {Converting Fields}[#label-Converting+Fields]
|
23
|
+
- {Recipe: Filter Generated Field Strings}[#label-Recipe-3A+Filter+Generated+Field+Strings]
|
24
|
+
- {Recipe: Specify Multiple Write Converters}[#label-Recipe-3A+Specify+Multiple+Write+Converters]
|
25
|
+
- {RFC 4180 Compliance}[#label-RFC+4180+Compliance]
|
26
|
+
- {Row Separator}[#label-Row+Separator]
|
27
|
+
- {Recipe: Generate Compliant Row Separator}[#label-Recipe-3A+Generate+Compliant+Row+Separator]
|
28
|
+
- {Recipe: Generate Non-Compliant Row Separator}[#label-Recipe-3A+Generate+Non-Compliant+Row+Separator]
|
29
|
+
- {Column Separator}[#label-Column+Separator]
|
30
|
+
- {Recipe: Generate Compliant Column Separator}[#label-Recipe-3A+Generate+Compliant+Column+Separator]
|
31
|
+
- {Recipe: Generate Non-Compliant Column Separator}[#label-Recipe-3A+Generate+Non-Compliant+Column+Separator]
|
32
|
+
- {Quotes}[#label-Quotes]
|
33
|
+
- {Recipe: Quote All Fields}[#label-Recipe-3A+Quote+All+Fields]
|
34
|
+
- {Recipe: Quote Empty Fields}[#label-Recipe-3A+Quote+Empty+Fields]
|
35
|
+
- {Recipe: Generate Compliant Quote Character}[#label-Recipe-3A+Generate+Compliant+Quote+Character]
|
36
|
+
- {Recipe: Generate Non-Compliant Quote Character}[#label-Recipe-3A+Generate+Non-Compliant+Quote+Character]
|
37
|
+
|
38
|
+
=== Output Formats
|
39
|
+
|
40
|
+
You can generate \CSV output to a \String, to a \File (via its path), or to an \IO stream.
|
41
|
+
|
42
|
+
==== Generating to a \String
|
43
|
+
|
44
|
+
You can generate \CSV output to a \String, with or without headers.
|
45
|
+
|
46
|
+
===== Recipe: Generate to \String with Headers
|
47
|
+
|
48
|
+
Use class method CSV.generate with option +headers+ to generate to a \String.
|
49
|
+
|
50
|
+
This example uses method CSV#<< to append the rows
|
51
|
+
that are to be generated:
|
52
|
+
output_string = CSV.generate('', headers: ['Name', 'Value'], write_headers: true) do |csv|
|
53
|
+
csv << ['Foo', 0]
|
54
|
+
csv << ['Bar', 1]
|
55
|
+
csv << ['Baz', 2]
|
56
|
+
end
|
57
|
+
output_string # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n"
|
58
|
+
|
59
|
+
===== Recipe: Generate to \String Without Headers
|
60
|
+
|
61
|
+
Use class method CSV.generate without option +headers+ to generate to a \String.
|
62
|
+
|
63
|
+
This example uses method CSV#<< to append the rows
|
64
|
+
that are to be generated:
|
65
|
+
output_string = CSV.generate do |csv|
|
66
|
+
csv << ['Foo', 0]
|
67
|
+
csv << ['Bar', 1]
|
68
|
+
csv << ['Baz', 2]
|
69
|
+
end
|
70
|
+
output_string # => "Foo,0\nBar,1\nBaz,2\n"
|
71
|
+
|
72
|
+
==== Generating to a \File
|
73
|
+
|
74
|
+
You can generate /CSV data to a \File, with or without headers.
|
75
|
+
|
76
|
+
===== Recipe: Generate to \File with Headers
|
77
|
+
|
78
|
+
Use class method CSV.open with option +headers+ generate to a \File.
|
79
|
+
|
80
|
+
This example uses method CSV#<< to append the rows
|
81
|
+
that are to be generated:
|
82
|
+
path = 't.csv'
|
83
|
+
CSV.open(path, 'w', headers: ['Name', 'Value'], write_headers: true) do |csv|
|
84
|
+
csv << ['Foo', 0]
|
85
|
+
csv << ['Bar', 1]
|
86
|
+
csv << ['Baz', 2]
|
87
|
+
end
|
88
|
+
p File.read(path) # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n"
|
89
|
+
|
90
|
+
===== Recipe: Generate to \File Without Headers
|
91
|
+
|
92
|
+
Use class method CSV.open without option +headers+ to generate to a \File.
|
93
|
+
|
94
|
+
This example uses method CSV#<< to append the rows
|
95
|
+
that are to be generated:
|
96
|
+
path = 't.csv'
|
97
|
+
CSV.open(path, 'w') do |csv|
|
98
|
+
csv << ['Foo', 0]
|
99
|
+
csv << ['Bar', 1]
|
100
|
+
csv << ['Baz', 2]
|
101
|
+
end
|
102
|
+
p File.read(path) # => "Foo,0\nBar,1\nBaz,2\n"
|
103
|
+
|
104
|
+
==== Generating to an \IO Stream
|
105
|
+
|
106
|
+
You can generate \CSV data to an \IO stream, with or without headers.
|
107
|
+
|
108
|
+
==== Recipe: Generate to \IO Stream with Headers
|
109
|
+
|
110
|
+
Use class method CSV.new with option +headers+ to generate \CSV data to an \IO stream:
|
111
|
+
path = 't.csv'
|
112
|
+
File.open(path, 'w') do |file|
|
113
|
+
csv = CSV.new(file, headers: ['Name', 'Value'], write_headers: true)
|
114
|
+
csv << ['Foo', 0]
|
115
|
+
csv << ['Bar', 1]
|
116
|
+
csv << ['Baz', 2]
|
117
|
+
end
|
118
|
+
p File.read(path) # => "Name,Value\nFoo,0\nBar,1\nBaz,2\n"
|
119
|
+
|
120
|
+
===== Recipe: Generate to \IO Stream Without Headers
|
121
|
+
|
122
|
+
Use class method CSV.new without option +headers+ to generate \CSV data to an \IO stream:
|
123
|
+
path = 't.csv'
|
124
|
+
File.open(path, 'w') do |file|
|
125
|
+
csv = CSV.new(file)
|
126
|
+
csv << ['Foo', 0]
|
127
|
+
csv << ['Bar', 1]
|
128
|
+
csv << ['Baz', 2]
|
129
|
+
end
|
130
|
+
p File.read(path) # => "Foo,0\nBar,1\nBaz,2\n"
|
131
|
+
|
132
|
+
=== Converting Fields
|
133
|
+
|
134
|
+
You can use _write_ _converters_ to convert fields when generating \CSV.
|
135
|
+
|
136
|
+
==== Recipe: Filter Generated Field Strings
|
137
|
+
|
138
|
+
Use option <tt>:write_converters</tt> and a custom converter to convert field values when generating \CSV.
|
139
|
+
|
140
|
+
This example defines and uses a custom write converter to strip whitespace from generated fields:
|
141
|
+
strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field }
|
142
|
+
output_string = CSV.generate(write_converters: strip_converter) do |csv|
|
143
|
+
csv << [' foo ', 0]
|
144
|
+
csv << [' bar ', 1]
|
145
|
+
csv << [' baz ', 2]
|
146
|
+
end
|
147
|
+
output_string # => "foo,0\nbar,1\nbaz,2\n"
|
148
|
+
|
149
|
+
==== Recipe: Specify Multiple Write Converters
|
150
|
+
|
151
|
+
Use option <tt>:write_converters</tt> and multiple custom coverters
|
152
|
+
to convert field values when generating \CSV.
|
153
|
+
|
154
|
+
This example defines and uses two custom write converters to strip and upcase generated fields:
|
155
|
+
strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field }
|
156
|
+
upcase_converter = proc {|field| field.respond_to?(:upcase) ? field.upcase : field }
|
157
|
+
converters = [strip_converter, upcase_converter]
|
158
|
+
output_string = CSV.generate(write_converters: converters) do |csv|
|
159
|
+
csv << [' foo ', 0]
|
160
|
+
csv << [' bar ', 1]
|
161
|
+
csv << [' baz ', 2]
|
162
|
+
end
|
163
|
+
output_string # => "FOO,0\nBAR,1\nBAZ,2\n"
|
164
|
+
|
165
|
+
=== RFC 4180 Compliance
|
166
|
+
|
167
|
+
By default, \CSV generates data that is compliant with
|
168
|
+
{RFC 4180}[https://tools.ietf.org/html/rfc4180]
|
169
|
+
with respect to:
|
170
|
+
- Column separator.
|
171
|
+
- Quote character.
|
172
|
+
|
173
|
+
==== Row Separator
|
174
|
+
|
175
|
+
RFC 4180 specifies the row separator CRLF (Ruby <tt>"\r\n"</tt>).
|
176
|
+
|
177
|
+
===== Recipe: Generate Compliant Row Separator
|
178
|
+
|
179
|
+
For strict compliance, use option +:row_sep+ to specify row separator <tt>"\r\n"</tt>:
|
180
|
+
output_string = CSV.generate('', row_sep: "\r\n") do |csv|
|
181
|
+
csv << ['Foo', 0]
|
182
|
+
csv << ['Bar', 1]
|
183
|
+
csv << ['Baz', 2]
|
184
|
+
end
|
185
|
+
output_string # => "Foo,0\r\nBar,1\r\nBaz,2\r\n"
|
186
|
+
|
187
|
+
===== Recipe: Generate Non-Compliant Row Separator
|
188
|
+
|
189
|
+
For data with non-compliant row separators, use option +:row_sep+ with a different value:
|
190
|
+
This example source uses semicolon (<tt>";'</tt>) as its row separator:
|
191
|
+
output_string = CSV.generate('', row_sep: ";") do |csv|
|
192
|
+
csv << ['Foo', 0]
|
193
|
+
csv << ['Bar', 1]
|
194
|
+
csv << ['Baz', 2]
|
195
|
+
end
|
196
|
+
output_string # => "Foo,0;Bar,1;Baz,2;"
|
197
|
+
|
198
|
+
==== Column Separator
|
199
|
+
|
200
|
+
RFC 4180 specifies column separator COMMA (Ruby <tt>","</tt>).
|
201
|
+
|
202
|
+
===== Recipe: Generate Compliant Column Separator
|
203
|
+
|
204
|
+
Because the \CSV default comma separator is <tt>","</tt>,
|
205
|
+
you need not specify option +:col_sep+ for compliant data:
|
206
|
+
output_string = CSV.generate('') do |csv|
|
207
|
+
csv << ['Foo', 0]
|
208
|
+
csv << ['Bar', 1]
|
209
|
+
csv << ['Baz', 2]
|
210
|
+
end
|
211
|
+
output_string # => "Foo,0\nBar,1\nBaz,2\n"
|
212
|
+
|
213
|
+
===== Recipe: Generate Non-Compliant Column Separator
|
214
|
+
|
215
|
+
For data with non-compliant column separators, use option +:col_sep+.
|
216
|
+
This example source uses TAB (<tt>"\t"</tt>) as its column separator:
|
217
|
+
output_string = CSV.generate('', col_sep: "\t") do |csv|
|
218
|
+
csv << ['Foo', 0]
|
219
|
+
csv << ['Bar', 1]
|
220
|
+
csv << ['Baz', 2]
|
221
|
+
end
|
222
|
+
output_string # => "Foo\t0\nBar\t1\nBaz\t2\n"
|
223
|
+
|
224
|
+
==== Quotes
|
225
|
+
|
226
|
+
IFC 4180 allows most fields to be quoted or not.
|
227
|
+
By default, \CSV does not quote most fields.
|
228
|
+
|
229
|
+
However, a field containing the current row separator, column separator,
|
230
|
+
or quote character is automatically quoted, producing IFC 4180 compliance:
|
231
|
+
# Field contains row separator.
|
232
|
+
output_string = CSV.generate('') do |csv|
|
233
|
+
row_sep = csv.row_sep
|
234
|
+
csv << ["Foo#{row_sep}Foo", 0]
|
235
|
+
csv << ['Bar', 1]
|
236
|
+
csv << ['Baz', 2]
|
237
|
+
end
|
238
|
+
output_string # => "\"Foo\nFoo\",0\nBar,1\nBaz,2\n"
|
239
|
+
# Field contains column separator.
|
240
|
+
output_string = CSV.generate('') do |csv|
|
241
|
+
col_sep = csv.col_sep
|
242
|
+
csv << ["Foo#{col_sep}Foo", 0]
|
243
|
+
csv << ['Bar', 1]
|
244
|
+
csv << ['Baz', 2]
|
245
|
+
end
|
246
|
+
output_string # => "\"Foo,Foo\",0\nBar,1\nBaz,2\n"
|
247
|
+
# Field contains quote character.
|
248
|
+
output_string = CSV.generate('') do |csv|
|
249
|
+
quote_char = csv.quote_char
|
250
|
+
csv << ["Foo#{quote_char}Foo", 0]
|
251
|
+
csv << ['Bar', 1]
|
252
|
+
csv << ['Baz', 2]
|
253
|
+
end
|
254
|
+
output_string # => "\"Foo\"\"Foo\",0\nBar,1\nBaz,2\n"
|
255
|
+
|
256
|
+
===== Recipe: Quote All Fields
|
257
|
+
|
258
|
+
Use option +:force_quotes+ to force quoted fields:
|
259
|
+
output_string = CSV.generate('', force_quotes: true) do |csv|
|
260
|
+
csv << ['Foo', 0]
|
261
|
+
csv << ['Bar', 1]
|
262
|
+
csv << ['Baz', 2]
|
263
|
+
end
|
264
|
+
output_string # => "\"Foo\",\"0\"\n\"Bar\",\"1\"\n\"Baz\",\"2\"\n"
|
265
|
+
|
266
|
+
===== Recipe: Quote Empty Fields
|
267
|
+
|
268
|
+
Use option +:quote_empty+ to force quoting for empty fields:
|
269
|
+
output_string = CSV.generate('', quote_empty: true) do |csv|
|
270
|
+
csv << ['Foo', 0]
|
271
|
+
csv << ['Bar', 1]
|
272
|
+
csv << ['', 2]
|
273
|
+
end
|
274
|
+
output_string # => "Foo,0\nBar,1\n\"\",2\n"
|
275
|
+
|
276
|
+
===== Recipe: Generate Compliant Quote Character
|
277
|
+
|
278
|
+
RFC 4180 specifies quote character DQUOTE (Ruby <tt>"\""</tt>).
|
279
|
+
|
280
|
+
Because the \CSV default quote character is also <tt>"\""</tt>,
|
281
|
+
you need not specify option +:quote_char+ for compliant data:
|
282
|
+
output_string = CSV.generate('', force_quotes: true) do |csv|
|
283
|
+
csv << ['Foo', 0]
|
284
|
+
csv << ['Bar', 1]
|
285
|
+
csv << ['Baz', 2]
|
286
|
+
end
|
287
|
+
output_string # => "\"Foo\",\"0\"\n\"Bar\",\"1\"\n\"Baz\",\"2\"\n"
|
288
|
+
|
289
|
+
===== Recipe: Generate Non-Compliant Quote Character
|
290
|
+
|
291
|
+
For data with non-compliant quote characters, use option +:quote_char+.
|
292
|
+
This example source uses SQUOTE (<tt>"'"</tt>) as its quote character:
|
293
|
+
output_string = CSV.generate('', quote_char: "'", force_quotes: true) do |csv|
|
294
|
+
csv << ['Foo', 0]
|
295
|
+
csv << ['Bar', 1]
|
296
|
+
csv << ['Baz', 2]
|
297
|
+
end
|
298
|
+
output_string # => "'Foo','0'\n'Bar','1'\n'Baz','2'\n"
|