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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c834580f6d364830ddcd85b07edcb44fc91520fd594492a835cb57f43f145c94
4
- data.tar.gz: 989310760b22148eeb70be9181a39c2d08c8040f7e79fd6a06dc7586409c4e7f
3
+ metadata.gz: 9a9f965a5db6ac6d07f525f513e212f082c137b487d73328373d0afef7bb8312
4
+ data.tar.gz: 5184ad5878a6dee8603e3b48fc820b50e3687eafb96cbcec152a8d621ceaffd6
5
5
  SHA512:
6
- metadata.gz: 75859dd4eff126ab15bf372305da6eeb638ce1927186931f3ea87fe00c0a769c8adb38cb786b8ee3f7fd418de720d26fe01fba9ca28ac565bbd761431057cec8
7
- data.tar.gz: 56b5de70961f3e9792296e6b68941fa1ea1e1eaa5ad2811ae47954a775c986d8f9455af50e5e6d25deb797794b697cef0e0c4a87695dc3a42d9fa477008d85dc
6
+ metadata.gz: 422a1a8751e4e8c21884848e7f465e39090b946c3febff711bb756c98e61b7e6aebf0e552adee851d653f89e9ef2772984db2b05a243c7fac8060c64def34ae0
7
+ data.tar.gz: 9d85fa756cd744e74da2ae1e89650768370566a5fd8ce1830337d528f9875d07422508eb007522ae3e7ec9c20c9ec055983f09c9b951e78441706bb2d33fdd59
data/NEWS.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # News
2
2
 
3
+ ## 3.1.8 - 2020-11-18
4
+
5
+ ### Improvements
6
+
7
+ * Improved documentation.
8
+ [Patch by Burdette Lamar]
9
+
10
+ ### Thanks
11
+
12
+ * Burdette Lamar
13
+
3
14
  ## 3.1.7 - 2020-08-04
4
15
 
5
16
  ### Improvements
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 field separator to be used
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"