rbs 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +5 -0
  3. data/CHANGELOG.md +23 -0
  4. data/README.md +6 -1
  5. data/core/array.rbs +2866 -1086
  6. data/core/basic_object.rbs +150 -30
  7. data/core/binding.rbs +33 -0
  8. data/core/builtin.rbs +4 -4
  9. data/core/class.rbs +43 -5
  10. data/core/comparable.rbs +57 -0
  11. data/core/complex.rbs +170 -4
  12. data/core/constants.rbs +51 -0
  13. data/core/deprecated.rbs +7 -0
  14. data/core/dir.rbs +305 -20
  15. data/core/encoding.rbs +472 -77
  16. data/core/enumerable.rbs +2173 -234
  17. data/core/enumerator.rbs +448 -182
  18. data/core/env.rbs +448 -1
  19. data/core/errno.rbs +1 -10
  20. data/core/errors.rbs +152 -2
  21. data/core/exception.rbs +201 -127
  22. data/core/false_class.rbs +27 -0
  23. data/core/fiber.rbs +118 -37
  24. data/core/fiber_error.rbs +8 -9
  25. data/core/file.rbs +1059 -139
  26. data/core/file_test.rbs +287 -32
  27. data/core/float.rbs +776 -300
  28. data/core/gc.rbs +185 -34
  29. data/core/global_variables.rbs +5 -1
  30. data/core/hash.rbs +1582 -649
  31. data/core/integer.rbs +974 -204
  32. data/core/io/buffer.rbs +710 -0
  33. data/core/io/wait.rbs +29 -8
  34. data/core/io.rbs +2438 -417
  35. data/core/kernel.rbs +2315 -316
  36. data/core/marshal.rbs +37 -2
  37. data/core/match_data.rbs +123 -6
  38. data/core/math.rbs +126 -6
  39. data/core/method.rbs +226 -102
  40. data/core/module.rbs +421 -45
  41. data/core/nil_class.rbs +64 -0
  42. data/core/numeric.rbs +620 -142
  43. data/core/object.rbs +453 -81
  44. data/core/object_space.rbs +92 -2
  45. data/core/proc.rbs +482 -285
  46. data/core/process.rbs +443 -34
  47. data/core/ractor.rbs +232 -9
  48. data/core/random.rbs +151 -52
  49. data/core/range.rbs +885 -160
  50. data/core/rational.rbs +122 -6
  51. data/core/rb_config.rbs +14 -4
  52. data/core/refinement.rbs +44 -0
  53. data/core/regexp.rbs +156 -14
  54. data/core/ruby_vm.rbs +42 -3
  55. data/core/signal.rbs +78 -39
  56. data/core/string.rbs +2123 -567
  57. data/core/string_io.rbs +204 -0
  58. data/core/struct.rbs +283 -28
  59. data/core/symbol.rbs +304 -30
  60. data/core/thread.rbs +1288 -688
  61. data/core/thread_group.rbs +66 -10
  62. data/core/time.rbs +643 -217
  63. data/core/trace_point.rbs +100 -12
  64. data/core/true_class.rbs +24 -0
  65. data/core/unbound_method.rbs +73 -7
  66. data/core/warning.rbs +37 -12
  67. data/docs/CONTRIBUTING.md +40 -34
  68. data/docs/stdlib.md +3 -102
  69. data/lib/rbs/annotate/annotations.rb +197 -0
  70. data/lib/rbs/annotate/formatter.rb +80 -0
  71. data/lib/rbs/annotate/rdoc_annotator.rb +398 -0
  72. data/lib/rbs/annotate/rdoc_source.rb +120 -0
  73. data/lib/rbs/annotate.rb +6 -0
  74. data/lib/rbs/cli.rb +45 -1
  75. data/lib/rbs/definition_builder.rb +5 -1
  76. data/lib/rbs/location_aux.rb +12 -0
  77. data/lib/rbs/prototype/rb.rb +12 -0
  78. data/lib/rbs/version.rb +1 -1
  79. data/sig/annotate/annotations.rbs +102 -0
  80. data/sig/annotate/formatter.rbs +24 -0
  81. data/sig/annotate/rdoc_annotater.rbs +82 -0
  82. data/sig/annotate/rdoc_source.rbs +30 -0
  83. data/sig/cli.rbs +2 -0
  84. data/sig/collection/{collections.rbs → sources.rbs} +0 -0
  85. data/sig/location.rbs +6 -0
  86. data/sig/method_types.rbs +5 -1
  87. data/sig/polyfill.rbs +78 -0
  88. data/stdlib/abbrev/0/abbrev.rbs +6 -0
  89. data/stdlib/abbrev/0/array.rbs +26 -0
  90. data/stdlib/base64/0/base64.rbs +31 -0
  91. data/stdlib/benchmark/0/benchmark.rbs +74 -3
  92. data/stdlib/bigdecimal/0/big_decimal.rbs +614 -165
  93. data/stdlib/bigdecimal-math/0/big_math.rbs +41 -64
  94. data/stdlib/cgi/0/core.rbs +59 -0
  95. data/stdlib/coverage/0/coverage.rbs +164 -2
  96. data/stdlib/csv/0/csv.rbs +2862 -398
  97. data/stdlib/date/0/date.rbs +483 -25
  98. data/stdlib/date/0/date_time.rbs +187 -12
  99. data/stdlib/dbm/0/dbm.rbs +152 -17
  100. data/stdlib/digest/0/digest.rbs +146 -0
  101. data/stdlib/erb/0/erb.rbs +65 -245
  102. data/stdlib/fiber/0/fiber.rbs +73 -91
  103. data/stdlib/fileutils/0/fileutils.rbs +301 -1
  104. data/stdlib/find/0/find.rbs +9 -0
  105. data/stdlib/forwardable/0/forwardable.rbs +65 -1
  106. data/stdlib/io-console/0/io-console.rbs +227 -15
  107. data/stdlib/ipaddr/0/ipaddr.rbs +161 -0
  108. data/stdlib/json/0/json.rbs +1146 -144
  109. data/stdlib/logger/0/formatter.rbs +24 -0
  110. data/stdlib/logger/0/log_device.rbs +64 -0
  111. data/stdlib/logger/0/logger.rbs +165 -13
  112. data/stdlib/logger/0/period.rbs +10 -0
  113. data/stdlib/logger/0/severity.rbs +26 -0
  114. data/stdlib/monitor/0/monitor.rbs +163 -0
  115. data/stdlib/mutex_m/0/mutex_m.rbs +35 -6
  116. data/stdlib/net-http/0/net-http.rbs +1492 -683
  117. data/stdlib/nkf/0/nkf.rbs +372 -0
  118. data/stdlib/objspace/0/objspace.rbs +149 -90
  119. data/stdlib/openssl/0/openssl.rbs +8108 -71
  120. data/stdlib/optparse/0/optparse.rbs +487 -19
  121. data/stdlib/pathname/0/pathname.rbs +425 -124
  122. data/stdlib/prettyprint/0/prettyprint.rbs +120 -99
  123. data/stdlib/prime/0/integer-extension.rbs +20 -2
  124. data/stdlib/prime/0/prime.rbs +88 -21
  125. data/stdlib/pstore/0/pstore.rbs +102 -0
  126. data/stdlib/pty/0/pty.rbs +64 -14
  127. data/stdlib/resolv/0/resolv.rbs +420 -31
  128. data/stdlib/rubygems/0/basic_specification.rbs +4 -1
  129. data/stdlib/rubygems/0/config_file.rbs +33 -1
  130. data/stdlib/rubygems/0/dependency_installer.rbs +4 -3
  131. data/stdlib/rubygems/0/installer.rbs +13 -1
  132. data/stdlib/rubygems/0/path_support.rbs +4 -1
  133. data/stdlib/rubygems/0/platform.rbs +5 -1
  134. data/stdlib/rubygems/0/request_set.rbs +44 -2
  135. data/stdlib/rubygems/0/requirement.rbs +65 -2
  136. data/stdlib/rubygems/0/rubygems.rbs +407 -0
  137. data/stdlib/rubygems/0/source_list.rbs +13 -0
  138. data/stdlib/rubygems/0/specification.rbs +21 -1
  139. data/stdlib/rubygems/0/stream_ui.rbs +3 -1
  140. data/stdlib/rubygems/0/uninstaller.rbs +8 -1
  141. data/stdlib/rubygems/0/version.rbs +60 -157
  142. data/stdlib/securerandom/0/securerandom.rbs +44 -0
  143. data/stdlib/set/0/set.rbs +420 -106
  144. data/stdlib/shellwords/0/shellwords.rbs +55 -77
  145. data/stdlib/singleton/0/singleton.rbs +20 -0
  146. data/stdlib/socket/0/addrinfo.rbs +210 -9
  147. data/stdlib/socket/0/basic_socket.rbs +103 -11
  148. data/stdlib/socket/0/ip_socket.rbs +31 -9
  149. data/stdlib/socket/0/socket.rbs +586 -38
  150. data/stdlib/socket/0/tcp_server.rbs +22 -2
  151. data/stdlib/socket/0/tcp_socket.rbs +12 -1
  152. data/stdlib/socket/0/udp_socket.rbs +25 -2
  153. data/stdlib/socket/0/unix_server.rbs +22 -2
  154. data/stdlib/socket/0/unix_socket.rbs +45 -5
  155. data/stdlib/strscan/0/string_scanner.rbs +210 -9
  156. data/stdlib/tempfile/0/tempfile.rbs +58 -10
  157. data/stdlib/time/0/time.rbs +208 -116
  158. data/stdlib/timeout/0/timeout.rbs +10 -0
  159. data/stdlib/tmpdir/0/tmpdir.rbs +13 -4
  160. data/stdlib/tsort/0/cyclic.rbs +1 -0
  161. data/stdlib/tsort/0/interfaces.rbs +1 -0
  162. data/stdlib/tsort/0/tsort.rbs +42 -0
  163. data/stdlib/uri/0/common.rbs +57 -8
  164. data/stdlib/uri/0/file.rbs +55 -109
  165. data/stdlib/uri/0/ftp.rbs +6 -3
  166. data/stdlib/uri/0/generic.rbs +556 -327
  167. data/stdlib/uri/0/http.rbs +26 -115
  168. data/stdlib/uri/0/https.rbs +8 -102
  169. data/stdlib/uri/0/ldap.rbs +143 -137
  170. data/stdlib/uri/0/ldaps.rbs +8 -102
  171. data/stdlib/uri/0/mailto.rbs +3 -0
  172. data/stdlib/uri/0/rfc2396_parser.rbs +66 -26
  173. data/stdlib/uri/0/ws.rbs +6 -3
  174. data/stdlib/uri/0/wss.rbs +5 -3
  175. data/stdlib/yaml/0/dbm.rbs +151 -87
  176. data/stdlib/yaml/0/store.rbs +6 -0
  177. data/stdlib/zlib/0/zlib.rbs +90 -31
  178. metadata +17 -5
  179. data/lib/rbs/location.rb +0 -221
data/stdlib/csv/0/csv.rbs CHANGED
@@ -1,122 +1,1611 @@
1
- # This class provides a complete interface to CSV files and data. It offers
2
- # tools to enable you to read and write to and from Strings or IO objects, as
3
- # needed.
1
+ # <!-- rdoc-file=lib/csv.rb -->
2
+ # ## CSV
3
+ # CSV (comma-separated variables) data is a text representation of a table:
4
+ # * A *row* *separator* delimits table rows. A common row separator is the
5
+ # newline character `"\n"`.
6
+ # * A *column* *separator* delimits fields in a row. A common column separator
7
+ # is the comma character `","`.
4
8
  #
5
- # The most generic interface of the library is:
6
9
  #
7
- # csv = CSV.new(string_or_io, **options)
10
+ # This CSV String, with row separator `"\n"` and column separator `","`, has
11
+ # three rows and two columns:
12
+ # "foo,0\nbar,1\nbaz,2\n"
8
13
  #
9
- # # Reading: IO object should be open for read
10
- # csv.read # => array of rows
11
- # # or
12
- # csv.each do |row|
13
- # # ...
14
+ # Despite the name CSV, a CSV representation can use different separators.
15
+ #
16
+ # For more about tables, see the Wikipedia article "[Table
17
+ # (information)](https://en.wikipedia.org/wiki/Table_(information))", especially
18
+ # its section "[Simple
19
+ # table](https://en.wikipedia.org/wiki/Table_(information)#Simple_table)"
20
+ #
21
+ # ## Class CSV
22
+ #
23
+ # Class CSV provides methods for:
24
+ # * Parsing CSV data from a String object, a File (via its file path), or an
25
+ # IO object.
26
+ # * Generating CSV data to a String object.
27
+ #
28
+ #
29
+ # To make CSV available:
30
+ # require 'csv'
31
+ #
32
+ # All examples here assume that this has been done.
33
+ #
34
+ # ## Keeping It Simple
35
+ #
36
+ # A CSV object has dozens of instance methods that offer fine-grained control of
37
+ # parsing and generating CSV data. For many needs, though, simpler approaches
38
+ # will do.
39
+ #
40
+ # This section summarizes the singleton methods in CSV that allow you to parse
41
+ # and generate without explicitly creating CSV objects. For details, follow the
42
+ # links.
43
+ #
44
+ # ### Simple Parsing
45
+ #
46
+ # Parsing methods commonly return either of:
47
+ # * An Array of Arrays of Strings:
48
+ # * The outer Array is the entire "table".
49
+ # * Each inner Array is a row.
50
+ # * Each String is a field.
51
+ #
52
+ # * A CSV::Table object. For details, see [\CSV with
53
+ # Headers](#class-CSV-label-CSV+with+Headers).
54
+ #
55
+ #
56
+ # #### Parsing a String
57
+ #
58
+ # The input to be parsed can be a string:
59
+ # string = "foo,0\nbar,1\nbaz,2\n"
60
+ #
61
+ # Method CSV.parse returns the entire CSV data:
62
+ # CSV.parse(string) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
63
+ #
64
+ # Method CSV.parse_line returns only the first row:
65
+ # CSV.parse_line(string) # => ["foo", "0"]
66
+ #
67
+ # CSV extends class String with instance method String#parse_csv, which also
68
+ # returns only the first row:
69
+ # string.parse_csv # => ["foo", "0"]
70
+ #
71
+ # #### Parsing Via a File Path
72
+ #
73
+ # The input to be parsed can be in a file:
74
+ # string = "foo,0\nbar,1\nbaz,2\n"
75
+ # path = 't.csv'
76
+ # File.write(path, string)
77
+ #
78
+ # Method CSV.read returns the entire CSV data:
79
+ # CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
80
+ #
81
+ # Method CSV.foreach iterates, passing each row to the given block:
82
+ # CSV.foreach(path) do |row|
83
+ # p row
14
84
  # end
15
- # # or
16
- # row = csv.shift
17
85
  #
18
- # # Writing: IO object should be open for write
19
- # csv << row
86
+ # Output:
87
+ # ["foo", "0"]
88
+ # ["bar", "1"]
89
+ # ["baz", "2"]
90
+ #
91
+ # Method CSV.table returns the entire CSV data as a CSV::Table object:
92
+ # CSV.table(path) # => #<CSV::Table mode:col_or_row row_count:3>
20
93
  #
21
- # There are several specialized class methods for one-statement reading or
22
- # writing, described in the Specialized Methods section.
94
+ # #### Parsing from an Open IO Stream
23
95
  #
24
- # If a String is passed into ::new, it is internally wrapped into a StringIO
25
- # object.
96
+ # The input to be parsed can be in an open IO stream:
26
97
  #
27
- # `options` can be used for specifying the particular CSV flavor (column
28
- # separators, row separators, value quoting and so on), and for data conversion,
29
- # see Data Conversion section for the description of the latter.
98
+ # Method CSV.read returns the entire CSV data:
99
+ # File.open(path) do |file|
100
+ # CSV.read(file)
101
+ # end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
30
102
  #
31
- # ## Specialized Methods
103
+ # As does method CSV.parse:
104
+ # File.open(path) do |file|
105
+ # CSV.parse(file)
106
+ # end # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
32
107
  #
33
- # ### Reading
108
+ # Method CSV.parse_line returns only the first row:
109
+ # File.open(path) do |file|
110
+ # CSV.parse_line(file)
111
+ # end # => ["foo", "0"]
34
112
  #
35
- # # From a file: all at once
36
- # arr_of_rows = CSV.read("path/to/file.csv", **options)
37
- # # iterator-style:
38
- # CSV.foreach("path/to/file.csv", **options) do |row|
39
- # # ...
113
+ # Method CSV.foreach iterates, passing each row to the given block:
114
+ # File.open(path) do |file|
115
+ # CSV.foreach(file) do |row|
116
+ # p row
117
+ # end
40
118
  # end
41
119
  #
42
- # # From a string
43
- # arr_of_rows = CSV.parse("CSV,data,String", **options)
44
- # # or
45
- # CSV.parse("CSV,data,String", **options) do |row|
46
- # # ...
120
+ # Output:
121
+ # ["foo", "0"]
122
+ # ["bar", "1"]
123
+ # ["baz", "2"]
124
+ #
125
+ # Method CSV.table returns the entire CSV data as a CSV::Table object:
126
+ # File.open(path) do |file|
127
+ # CSV.table(file)
128
+ # end # => #<CSV::Table mode:col_or_row row_count:3>
129
+ #
130
+ # ### Simple Generating
131
+ #
132
+ # Method CSV.generate returns a String; this example uses method CSV#<< to
133
+ # append the rows that are to be generated:
134
+ # output_string = CSV.generate do |csv|
135
+ # csv << ['foo', 0]
136
+ # csv << ['bar', 1]
137
+ # csv << ['baz', 2]
47
138
  # end
139
+ # output_string # => "foo,0\nbar,1\nbaz,2\n"
48
140
  #
49
- # ### Writing
141
+ # Method CSV.generate_line returns a String containing the single row
142
+ # constructed from an Array:
143
+ # CSV.generate_line(['foo', '0']) # => "foo,0\n"
50
144
  #
51
- # # To a file
52
- # CSV.open("path/to/file.csv", "wb") do |csv|
53
- # csv << ["row", "of", "CSV", "data"]
54
- # csv << ["another", "row"]
55
- # # ...
145
+ # CSV extends class Array with instance method `Array#to_csv`, which forms an
146
+ # Array into a String:
147
+ # ['foo', '0'].to_csv # => "foo,0\n"
148
+ #
149
+ # ### "Filtering" CSV
150
+ #
151
+ # Method CSV.filter provides a Unix-style filter for CSV data. The input data is
152
+ # processed to form the output data:
153
+ # in_string = "foo,0\nbar,1\nbaz,2\n"
154
+ # out_string = ''
155
+ # CSV.filter(in_string, out_string) do |row|
156
+ # row[0] = row[0].upcase
157
+ # row[1] *= 4
56
158
  # end
159
+ # out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
160
+ #
161
+ # ## CSV Objects
162
+ #
163
+ # There are three ways to create a CSV object:
164
+ # * Method CSV.new returns a new CSV object.
165
+ # * Method CSV.instance returns a new or cached CSV object.
166
+ # * Method CSV() also returns a new or cached CSV object.
167
+ #
168
+ #
169
+ # ### Instance Methods
170
+ #
171
+ # CSV has three groups of instance methods:
172
+ # * Its own internally defined instance methods.
173
+ # * Methods included by module Enumerable.
174
+ # * Methods delegated to class IO. See below.
175
+ #
176
+ #
177
+ # #### Delegated Methods
178
+ #
179
+ # For convenience, a CSV object will delegate to many methods in class IO. (A
180
+ # few have wrapper "guard code" in CSV.) You may call:
181
+ # * IO#binmode
182
+ # * #binmode?
183
+ # * IO#close
184
+ # * IO#close_read
185
+ # * IO#close_write
186
+ # * IO#closed?
187
+ # * #eof
188
+ # * #eof?
189
+ # * IO#external_encoding
190
+ # * IO#fcntl
191
+ # * IO#fileno
192
+ # * #flock
193
+ # * IO#flush
194
+ # * IO#fsync
195
+ # * IO#internal_encoding
196
+ # * #ioctl
197
+ # * IO#isatty
198
+ # * #path
199
+ # * IO#pid
200
+ # * IO#pos
201
+ # * IO#pos=
202
+ # * IO#reopen
203
+ # * #rewind
204
+ # * IO#seek
205
+ # * #stat
206
+ # * IO#string
207
+ # * IO#sync
208
+ # * IO#sync=
209
+ # * IO#tell
210
+ # * #to_i
211
+ # * #to_io
212
+ # * IO#truncate
213
+ # * IO#tty?
214
+ #
215
+ #
216
+ # ### Options
217
+ #
218
+ # The default values for options are:
219
+ # DEFAULT_OPTIONS = {
220
+ # # For both parsing and generating.
221
+ # col_sep: ",",
222
+ # row_sep: :auto,
223
+ # quote_char: '"',
224
+ # # For parsing.
225
+ # field_size_limit: nil,
226
+ # converters: nil,
227
+ # unconverted_fields: nil,
228
+ # headers: false,
229
+ # return_headers: false,
230
+ # header_converters: nil,
231
+ # skip_blanks: false,
232
+ # skip_lines: nil,
233
+ # liberal_parsing: false,
234
+ # nil_value: nil,
235
+ # empty_value: "",
236
+ # strip: false,
237
+ # # For generating.
238
+ # write_headers: nil,
239
+ # quote_empty: true,
240
+ # force_quotes: false,
241
+ # write_converters: nil,
242
+ # write_nil_value: nil,
243
+ # write_empty_value: "",
244
+ # }
245
+ #
246
+ # #### Options for Parsing
247
+ #
248
+ # Options for parsing, described in detail below, include:
249
+ # * `row_sep`: Specifies the row separator; used to delimit rows.
250
+ # * `col_sep`: Specifies the column separator; used to delimit fields.
251
+ # * `quote_char`: Specifies the quote character; used to quote fields.
252
+ # * `field_size_limit`: Specifies the maximum field size allowed.
253
+ # * `converters`: Specifies the field converters to be used.
254
+ # * `unconverted_fields`: Specifies whether unconverted fields are to be
255
+ # available.
256
+ # * `headers`: Specifies whether data contains headers, or specifies the
257
+ # headers themselves.
258
+ # * `return_headers`: Specifies whether headers are to be returned.
259
+ # * `header_converters`: Specifies the header converters to be used.
260
+ # * `skip_blanks`: Specifies whether blanks lines are to be ignored.
261
+ # * `skip_lines`: Specifies how comments lines are to be recognized.
262
+ # * `strip`: Specifies whether leading and trailing whitespace are to be
263
+ # stripped from fields. This must be compatible with `col_sep`; if it is
264
+ # not, then an `ArgumentError` exception will be raised.
265
+ # * `liberal_parsing`: Specifies whether CSV should attempt to parse
266
+ # non-compliant data.
267
+ # * `nil_value`: Specifies the object that is to be substituted for each null
268
+ # (no-text) field.
269
+ # * `empty_value`: Specifies the object that is to be substituted for each
270
+ # empty field.
271
+ #
272
+ #
273
+ # ###### Option `row_sep`
274
+ #
275
+ # Specifies the row separator, a String or the Symbol `:auto` (see below), to be
276
+ # used for both parsing and generating.
277
+ #
278
+ # Default value:
279
+ # CSV::DEFAULT_OPTIONS.fetch(:row_sep) # => :auto
57
280
  #
58
- # # To a String
59
- # csv_string = CSV.generate do |csv|
60
- # csv << ["row", "of", "CSV", "data"]
61
- # csv << ["another", "row"]
62
- # # ...
281
+ # ---
282
+ #
283
+ # When `row_sep` is a String, that String becomes the row separator. The String
284
+ # will be transcoded into the data's Encoding before use.
285
+ #
286
+ # Using `"\n"`:
287
+ # row_sep = "\n"
288
+ # str = CSV.generate(row_sep: row_sep) do |csv|
289
+ # csv << [:foo, 0]
290
+ # csv << [:bar, 1]
291
+ # csv << [:baz, 2]
292
+ # end
293
+ # str # => "foo,0\nbar,1\nbaz,2\n"
294
+ # ary = CSV.parse(str)
295
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
296
+ #
297
+ # Using `|` (pipe):
298
+ # row_sep = '|'
299
+ # str = CSV.generate(row_sep: row_sep) do |csv|
300
+ # csv << [:foo, 0]
301
+ # csv << [:bar, 1]
302
+ # csv << [:baz, 2]
303
+ # end
304
+ # str # => "foo,0|bar,1|baz,2|"
305
+ # ary = CSV.parse(str, row_sep: row_sep)
306
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
307
+ #
308
+ # Using `--` (two hyphens):
309
+ # row_sep = '--'
310
+ # str = CSV.generate(row_sep: row_sep) do |csv|
311
+ # csv << [:foo, 0]
312
+ # csv << [:bar, 1]
313
+ # csv << [:baz, 2]
314
+ # end
315
+ # str # => "foo,0--bar,1--baz,2--"
316
+ # ary = CSV.parse(str, row_sep: row_sep)
317
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
318
+ #
319
+ # Using `''` (empty string):
320
+ # row_sep = ''
321
+ # str = CSV.generate(row_sep: row_sep) do |csv|
322
+ # csv << [:foo, 0]
323
+ # csv << [:bar, 1]
324
+ # csv << [:baz, 2]
325
+ # end
326
+ # str # => "foo,0bar,1baz,2"
327
+ # ary = CSV.parse(str, row_sep: row_sep)
328
+ # ary # => [["foo", "0bar", "1baz", "2"]]
329
+ #
330
+ # ---
331
+ #
332
+ # When `row_sep` is the Symbol `:auto` (the default), generating uses `"\n"` as
333
+ # the row separator:
334
+ # str = CSV.generate do |csv|
335
+ # csv << [:foo, 0]
336
+ # csv << [:bar, 1]
337
+ # csv << [:baz, 2]
338
+ # end
339
+ # str # => "foo,0\nbar,1\nbaz,2\n"
340
+ #
341
+ # Parsing, on the other hand, invokes auto-discovery of the row separator.
342
+ #
343
+ # Auto-discovery reads ahead in the data looking for the next `\r\n`, `\n`, or
344
+ # `\r` sequence. The sequence will be selected even if it occurs in a quoted
345
+ # field, assuming that you would have the same line endings there.
346
+ #
347
+ # Example:
348
+ # str = CSV.generate do |csv|
349
+ # csv << [:foo, 0]
350
+ # csv << [:bar, 1]
351
+ # csv << [:baz, 2]
352
+ # end
353
+ # str # => "foo,0\nbar,1\nbaz,2\n"
354
+ # ary = CSV.parse(str)
355
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
356
+ #
357
+ # The default `$INPUT_RECORD_SEPARATOR` (`$/`) is used if any of the following
358
+ # is true:
359
+ # * None of those sequences is found.
360
+ # * Data is `ARGF`, `STDIN`, `STDOUT`, or `STDERR`.
361
+ # * The stream is only available for output.
362
+ #
363
+ #
364
+ # Obviously, discovery takes a little time. Set manually if speed is important.
365
+ # Also note that IO objects should be opened in binary mode on Windows if this
366
+ # feature will be used as the line-ending translation can cause problems with
367
+ # resetting the document position to where it was before the read ahead.
368
+ #
369
+ # ---
370
+ #
371
+ # Raises an exception if the given value is not String-convertible:
372
+ # row_sep = BasicObject.new
373
+ # # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
374
+ # CSV.generate(ary, row_sep: row_sep)
375
+ # # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
376
+ # CSV.parse(str, row_sep: row_sep)
377
+ #
378
+ # ###### Option `col_sep`
379
+ #
380
+ # Specifies the String field separator to be used for both parsing and
381
+ # generating. The String will be transcoded into the data's Encoding before use.
382
+ #
383
+ # Default value:
384
+ # CSV::DEFAULT_OPTIONS.fetch(:col_sep) # => "," (comma)
385
+ #
386
+ # Using the default (comma):
387
+ # str = CSV.generate do |csv|
388
+ # csv << [:foo, 0]
389
+ # csv << [:bar, 1]
390
+ # csv << [:baz, 2]
391
+ # end
392
+ # str # => "foo,0\nbar,1\nbaz,2\n"
393
+ # ary = CSV.parse(str)
394
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
395
+ #
396
+ # Using `:` (colon):
397
+ # col_sep = ':'
398
+ # str = CSV.generate(col_sep: col_sep) do |csv|
399
+ # csv << [:foo, 0]
400
+ # csv << [:bar, 1]
401
+ # csv << [:baz, 2]
402
+ # end
403
+ # str # => "foo:0\nbar:1\nbaz:2\n"
404
+ # ary = CSV.parse(str, col_sep: col_sep)
405
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
406
+ #
407
+ # Using `::` (two colons):
408
+ # col_sep = '::'
409
+ # str = CSV.generate(col_sep: col_sep) do |csv|
410
+ # csv << [:foo, 0]
411
+ # csv << [:bar, 1]
412
+ # csv << [:baz, 2]
413
+ # end
414
+ # str # => "foo::0\nbar::1\nbaz::2\n"
415
+ # ary = CSV.parse(str, col_sep: col_sep)
416
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
417
+ #
418
+ # Using `''` (empty string):
419
+ # col_sep = ''
420
+ # str = CSV.generate(col_sep: col_sep) do |csv|
421
+ # csv << [:foo, 0]
422
+ # csv << [:bar, 1]
423
+ # csv << [:baz, 2]
424
+ # end
425
+ # str # => "foo0\nbar1\nbaz2\n"
426
+ #
427
+ # ---
428
+ #
429
+ # Raises an exception if parsing with the empty String:
430
+ # col_sep = ''
431
+ # # Raises ArgumentError (:col_sep must be 1 or more characters: "")
432
+ # CSV.parse("foo0\nbar1\nbaz2\n", col_sep: col_sep)
433
+ #
434
+ # Raises an exception if the given value is not String-convertible:
435
+ # col_sep = BasicObject.new
436
+ # # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
437
+ # CSV.generate(line, col_sep: col_sep)
438
+ # # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
439
+ # CSV.parse(str, col_sep: col_sep)
440
+ #
441
+ # ###### Option `quote_char`
442
+ #
443
+ # Specifies the character (String of length 1) used used to quote fields in both
444
+ # parsing and generating. This String will be transcoded into the data's
445
+ # Encoding before use.
446
+ #
447
+ # Default value:
448
+ # CSV::DEFAULT_OPTIONS.fetch(:quote_char) # => "\"" (double quote)
449
+ #
450
+ # This is useful for an application that incorrectly uses `'` (single-quote) to
451
+ # quote fields, instead of the correct `"` (double-quote).
452
+ #
453
+ # Using the default (double quote):
454
+ # str = CSV.generate do |csv|
455
+ # csv << ['foo', 0]
456
+ # csv << ["'bar'", 1]
457
+ # csv << ['"baz"', 2]
458
+ # end
459
+ # str # => "foo,0\n'bar',1\n\"\"\"baz\"\"\",2\n"
460
+ # ary = CSV.parse(str)
461
+ # ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
462
+ #
463
+ # Using `'` (single-quote):
464
+ # quote_char = "'"
465
+ # str = CSV.generate(quote_char: quote_char) do |csv|
466
+ # csv << ['foo', 0]
467
+ # csv << ["'bar'", 1]
468
+ # csv << ['"baz"', 2]
63
469
  # end
470
+ # str # => "foo,0\n'''bar''',1\n\"baz\",2\n"
471
+ # ary = CSV.parse(str, quote_char: quote_char)
472
+ # ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
473
+ #
474
+ # ---
475
+ #
476
+ # Raises an exception if the String length is greater than 1:
477
+ # # Raises ArgumentError (:quote_char has to be nil or a single character String)
478
+ # CSV.new('', quote_char: 'xx')
479
+ #
480
+ # Raises an exception if the value is not a String:
481
+ # # Raises ArgumentError (:quote_char has to be nil or a single character String)
482
+ # CSV.new('', quote_char: :foo)
483
+ #
484
+ # ###### Option `field_size_limit`
485
+ #
486
+ # Specifies the Integer field size limit.
487
+ #
488
+ # Default value:
489
+ # CSV::DEFAULT_OPTIONS.fetch(:field_size_limit) # => nil
490
+ #
491
+ # This is a maximum size CSV will read ahead looking for the closing quote for a
492
+ # field. (In truth, it reads to the first line ending beyond this size.) If a
493
+ # quote cannot be found within the limit CSV will raise a MalformedCSVError,
494
+ # assuming the data is faulty. You can use this limit to prevent what are
495
+ # effectively DoS attacks on the parser. However, this limit can cause a
496
+ # legitimate parse to fail; therefore the default value is `nil` (no limit).
497
+ #
498
+ # For the examples in this section:
499
+ # str = <<~EOT
500
+ # "a","b"
501
+ # "
502
+ # 2345
503
+ # ",""
504
+ # EOT
505
+ # str # => "\"a\",\"b\"\n\"\n2345\n\",\"\"\n"
506
+ #
507
+ # Using the default `nil`:
508
+ # ary = CSV.parse(str)
509
+ # ary # => [["a", "b"], ["\n2345\n", ""]]
510
+ #
511
+ # Using `50`:
512
+ # field_size_limit = 50
513
+ # ary = CSV.parse(str, field_size_limit: field_size_limit)
514
+ # ary # => [["a", "b"], ["\n2345\n", ""]]
515
+ #
516
+ # ---
517
+ #
518
+ # Raises an exception if a field is too long:
519
+ # big_str = "123456789\n" * 1024
520
+ # # Raises CSV::MalformedCSVError (Field size exceeded in line 1.)
521
+ # CSV.parse('valid,fields,"' + big_str + '"', field_size_limit: 2048)
522
+ #
523
+ # ###### Option `converters`
524
+ #
525
+ # Specifies converters to be used in parsing fields. See [Field
526
+ # Converters](#class-CSV-label-Field+Converters)
527
+ #
528
+ # Default value:
529
+ # CSV::DEFAULT_OPTIONS.fetch(:converters) # => nil
530
+ #
531
+ # The value may be a field converter name (see [Stored
532
+ # Converters](#class-CSV-label-Stored+Converters)):
533
+ # str = '1,2,3'
534
+ # # Without a converter
535
+ # array = CSV.parse_line(str)
536
+ # array # => ["1", "2", "3"]
537
+ # # With built-in converter :integer
538
+ # array = CSV.parse_line(str, converters: :integer)
539
+ # array # => [1, 2, 3]
540
+ #
541
+ # The value may be a converter list (see [Converter
542
+ # Lists](#class-CSV-label-Converter+Lists)):
543
+ # str = '1,3.14159'
544
+ # # Without converters
545
+ # array = CSV.parse_line(str)
546
+ # array # => ["1", "3.14159"]
547
+ # # With built-in converters
548
+ # array = CSV.parse_line(str, converters: [:integer, :float])
549
+ # array # => [1, 3.14159]
550
+ #
551
+ # The value may be a Proc custom converter: (see [Custom Field
552
+ # Converters](#class-CSV-label-Custom+Field+Converters)):
553
+ # str = ' foo , bar , baz '
554
+ # # Without a converter
555
+ # array = CSV.parse_line(str)
556
+ # array # => [" foo ", " bar ", " baz "]
557
+ # # With a custom converter
558
+ # array = CSV.parse_line(str, converters: proc {|field| field.strip })
559
+ # array # => ["foo", "bar", "baz"]
560
+ #
561
+ # See also [Custom Field Converters](#class-CSV-label-Custom+Field+Converters)
562
+ #
563
+ # ---
564
+ #
565
+ # Raises an exception if the converter is not a converter name or a Proc:
566
+ # str = 'foo,0'
567
+ # # Raises NoMethodError (undefined method `arity' for nil:NilClass)
568
+ # CSV.parse(str, converters: :foo)
569
+ #
570
+ # ###### Option `unconverted_fields`
571
+ #
572
+ # Specifies the boolean that determines whether unconverted field values are to
573
+ # be available.
574
+ #
575
+ # Default value:
576
+ # CSV::DEFAULT_OPTIONS.fetch(:unconverted_fields) # => nil
577
+ #
578
+ # The unconverted field values are those found in the source data, prior to any
579
+ # conversions performed via option `converters`.
580
+ #
581
+ # When option `unconverted_fields` is `true`, each returned row (Array or
582
+ # CSV::Row) has an added method, `unconverted_fields`, that returns the
583
+ # unconverted field values:
584
+ # str = <<-EOT
585
+ # foo,0
586
+ # bar,1
587
+ # baz,2
588
+ # EOT
589
+ # # Without unconverted_fields
590
+ # csv = CSV.parse(str, converters: :integer)
591
+ # csv # => [["foo", 0], ["bar", 1], ["baz", 2]]
592
+ # csv.first.respond_to?(:unconverted_fields) # => false
593
+ # # With unconverted_fields
594
+ # csv = CSV.parse(str, converters: :integer, unconverted_fields: true)
595
+ # csv # => [["foo", 0], ["bar", 1], ["baz", 2]]
596
+ # csv.first.respond_to?(:unconverted_fields) # => true
597
+ # csv.first.unconverted_fields # => ["foo", "0"]
598
+ #
599
+ # ###### Option `headers`
600
+ #
601
+ # Specifies a boolean, Symbol, Array, or String to be used to define column
602
+ # headers.
603
+ #
604
+ # Default value:
605
+ # CSV::DEFAULT_OPTIONS.fetch(:headers) # => false
606
+ #
607
+ # ---
608
+ #
609
+ # Without `headers`:
610
+ # str = <<-EOT
611
+ # Name,Count
612
+ # foo,0
613
+ # bar,1
614
+ # bax,2
615
+ # EOT
616
+ # csv = CSV.new(str)
617
+ # csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
618
+ # csv.headers # => nil
619
+ # csv.shift # => ["Name", "Count"]
620
+ #
621
+ # ---
622
+ #
623
+ # If set to `true` or the Symbol `:first_row`, the first row of the data is
624
+ # treated as a row of headers:
625
+ # str = <<-EOT
626
+ # Name,Count
627
+ # foo,0
628
+ # bar,1
629
+ # bax,2
630
+ # EOT
631
+ # csv = CSV.new(str, headers: true)
632
+ # csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:2 col_sep:"," row_sep:"\n" quote_char:"\"" headers:["Name", "Count"]>
633
+ # csv.headers # => ["Name", "Count"]
634
+ # csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
635
+ #
636
+ # ---
637
+ #
638
+ # If set to an Array, the Array elements are treated as headers:
639
+ # str = <<-EOT
640
+ # foo,0
641
+ # bar,1
642
+ # bax,2
643
+ # EOT
644
+ # csv = CSV.new(str, headers: ['Name', 'Count'])
645
+ # csv
646
+ # csv.headers # => ["Name", "Count"]
647
+ # csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
648
+ #
649
+ # ---
650
+ #
651
+ # If set to a String `str`, method `CSV::parse_line(str, options)` is called
652
+ # with the current `options`, and the returned Array is treated as headers:
653
+ # str = <<-EOT
654
+ # foo,0
655
+ # bar,1
656
+ # bax,2
657
+ # EOT
658
+ # csv = CSV.new(str, headers: 'Name,Count')
659
+ # csv
660
+ # csv.headers # => ["Name", "Count"]
661
+ # csv.shift # => #<CSV::Row "Name":"bar" "Count":"1">
662
+ #
663
+ # ###### Option `return_headers`
664
+ #
665
+ # Specifies the boolean that determines whether method #shift returns or ignores
666
+ # the header row.
667
+ #
668
+ # Default value:
669
+ # CSV::DEFAULT_OPTIONS.fetch(:return_headers) # => false
670
+ #
671
+ # Examples:
672
+ # str = <<-EOT
673
+ # Name,Count
674
+ # foo,0
675
+ # bar,1
676
+ # bax,2
677
+ # EOT
678
+ # # Without return_headers first row is str.
679
+ # csv = CSV.new(str, headers: true)
680
+ # csv.shift # => #<CSV::Row "Name":"foo" "Count":"0">
681
+ # # With return_headers first row is headers.
682
+ # csv = CSV.new(str, headers: true, return_headers: true)
683
+ # csv.shift # => #<CSV::Row "Name":"Name" "Count":"Count">
684
+ #
685
+ # ###### Option `header_converters`
686
+ #
687
+ # Specifies converters to be used in parsing headers. See [Header
688
+ # Converters](#class-CSV-label-Header+Converters)
689
+ #
690
+ # Default value:
691
+ # CSV::DEFAULT_OPTIONS.fetch(:header_converters) # => nil
692
+ #
693
+ # Identical in functionality to option
694
+ # [converters](#class-CSV-label-Option+converters) except that:
695
+ # * The converters apply only to the header row.
696
+ # * The built-in header converters are `:downcase` and `:symbol`.
697
+ #
698
+ #
699
+ # This section assumes prior execution of:
700
+ # str = <<-EOT
701
+ # Name,Value
702
+ # foo,0
703
+ # bar,1
704
+ # baz,2
705
+ # EOT
706
+ # # With no header converter
707
+ # table = CSV.parse(str, headers: true)
708
+ # table.headers # => ["Name", "Value"]
709
+ #
710
+ # The value may be a header converter name (see [Stored
711
+ # Converters](#class-CSV-label-Stored+Converters)):
712
+ # table = CSV.parse(str, headers: true, header_converters: :downcase)
713
+ # table.headers # => ["name", "value"]
714
+ #
715
+ # The value may be a converter list (see [Converter
716
+ # Lists](#class-CSV-label-Converter+Lists)):
717
+ # header_converters = [:downcase, :symbol]
718
+ # table = CSV.parse(str, headers: true, header_converters: header_converters)
719
+ # table.headers # => [:name, :value]
720
+ #
721
+ # The value may be a Proc custom converter (see [Custom Header
722
+ # Converters](#class-CSV-label-Custom+Header+Converters)):
723
+ # upcase_converter = proc {|field| field.upcase }
724
+ # table = CSV.parse(str, headers: true, header_converters: upcase_converter)
725
+ # table.headers # => ["NAME", "VALUE"]
726
+ #
727
+ # See also [Custom Header Converters](#class-CSV-label-Custom+Header+Converters)
728
+ #
729
+ # ###### Option `skip_blanks`
730
+ #
731
+ # Specifies a boolean that determines whether blank lines in the input will be
732
+ # ignored; a line that contains a column separator is not considered to be
733
+ # blank.
734
+ #
735
+ # Default value:
736
+ # CSV::DEFAULT_OPTIONS.fetch(:skip_blanks) # => false
737
+ #
738
+ # See also option [skiplines](#class-CSV-label-Option+skip_lines).
739
+ #
740
+ # For examples in this section:
741
+ # str = <<-EOT
742
+ # foo,0
743
+ #
744
+ # bar,1
745
+ # baz,2
746
+ #
747
+ # ,
748
+ # EOT
749
+ #
750
+ # Using the default, `false`:
751
+ # ary = CSV.parse(str)
752
+ # ary # => [["foo", "0"], [], ["bar", "1"], ["baz", "2"], [], [nil, nil]]
753
+ #
754
+ # Using `true`:
755
+ # ary = CSV.parse(str, skip_blanks: true)
756
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
757
+ #
758
+ # Using a truthy value:
759
+ # ary = CSV.parse(str, skip_blanks: :foo)
760
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"], [nil, nil]]
761
+ #
762
+ # ###### Option `skip_lines`
763
+ #
764
+ # Specifies an object to use in identifying comment lines in the input that are
765
+ # to be ignored:
766
+ # * If a Regexp, ignores lines that match it.
767
+ # * If a String, converts it to a Regexp, ignores lines that match it.
768
+ # * If `nil`, no lines are considered to be comments.
769
+ #
770
+ #
771
+ # Default value:
772
+ # CSV::DEFAULT_OPTIONS.fetch(:skip_lines) # => nil
773
+ #
774
+ # For examples in this section:
775
+ # str = <<-EOT
776
+ # # Comment
777
+ # foo,0
778
+ # bar,1
779
+ # baz,2
780
+ # # Another comment
781
+ # EOT
782
+ # str # => "# Comment\nfoo,0\nbar,1\nbaz,2\n# Another comment\n"
783
+ #
784
+ # Using the default, `nil`:
785
+ # ary = CSV.parse(str)
786
+ # ary # => [["# Comment"], ["foo", "0"], ["bar", "1"], ["baz", "2"], ["# Another comment"]]
787
+ #
788
+ # Using a Regexp:
789
+ # ary = CSV.parse(str, skip_lines: /^#/)
790
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
791
+ #
792
+ # Using a String:
793
+ # ary = CSV.parse(str, skip_lines: '#')
794
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
795
+ #
796
+ # ---
797
+ #
798
+ # Raises an exception if given an object that is not a Regexp, a String, or
799
+ # `nil`:
800
+ # # Raises ArgumentError (:skip_lines has to respond to #match: 0)
801
+ # CSV.parse(str, skip_lines: 0)
802
+ #
803
+ # ###### Option `strip`
804
+ #
805
+ # Specifies the boolean value that determines whether whitespace is stripped
806
+ # from each input field.
807
+ #
808
+ # Default value:
809
+ # CSV::DEFAULT_OPTIONS.fetch(:strip) # => false
810
+ #
811
+ # With default value `false`:
812
+ # ary = CSV.parse_line(' a , b ')
813
+ # ary # => [" a ", " b "]
814
+ #
815
+ # With value `true`:
816
+ # ary = CSV.parse_line(' a , b ', strip: true)
817
+ # ary # => ["a", "b"]
818
+ #
819
+ # ###### Option `liberal_parsing`
820
+ #
821
+ # Specifies the boolean value that determines whether CSV will attempt to parse
822
+ # input not conformant with RFC 4180, such as double quotes in unquoted fields.
823
+ #
824
+ # Default value:
825
+ # CSV::DEFAULT_OPTIONS.fetch(:liberal_parsing) # => false
826
+ #
827
+ # For examples in this section:
828
+ # str = 'is,this "three, or four",fields'
829
+ #
830
+ # Without `liberal_parsing`:
831
+ # # Raises CSV::MalformedCSVError (Illegal quoting in str 1.)
832
+ # CSV.parse_line(str)
833
+ #
834
+ # With `liberal_parsing`:
835
+ # ary = CSV.parse_line(str, liberal_parsing: true)
836
+ # ary # => ["is", "this \"three", " or four\"", "fields"]
837
+ #
838
+ # ###### Option `nil_value`
839
+ #
840
+ # Specifies the object that is to be substituted for each null (no-text) field.
841
+ #
842
+ # Default value:
843
+ # CSV::DEFAULT_OPTIONS.fetch(:nil_value) # => nil
844
+ #
845
+ # With the default, `nil`:
846
+ # CSV.parse_line('a,,b,,c') # => ["a", nil, "b", nil, "c"]
847
+ #
848
+ # With a different object:
849
+ # CSV.parse_line('a,,b,,c', nil_value: 0) # => ["a", 0, "b", 0, "c"]
850
+ #
851
+ # ###### Option `empty_value`
852
+ #
853
+ # Specifies the object that is to be substituted for each field that has an
854
+ # empty String.
855
+ #
856
+ # Default value:
857
+ # CSV::DEFAULT_OPTIONS.fetch(:empty_value) # => "" (empty string)
858
+ #
859
+ # With the default, `""`:
860
+ # CSV.parse_line('a,"",b,"",c') # => ["a", "", "b", "", "c"]
64
861
  #
65
- # ### Shortcuts
862
+ # With a different object:
863
+ # CSV.parse_line('a,"",b,"",c', empty_value: 'x') # => ["a", "x", "b", "x", "c"]
66
864
  #
67
- # # Core extensions for converting one line
68
- # csv_string = ["CSV", "data"].to_csv # to CSV
69
- # csv_array = "CSV,String".parse_csv # from CSV
865
+ # #### Options for Generating
70
866
  #
71
- # # CSV() method
72
- # CSV { |csv_out| csv_out << %w{my data here} } # to $stdout
73
- # CSV(csv = "") { |csv_str| csv_str << %w{my data here} } # to a String
74
- # CSV($stderr) { |csv_err| csv_err << %w{my data here} } # to $stderr
75
- # CSV($stdin) { |csv_in| csv_in.each { |row| p row } } # from $stdin
867
+ # Options for generating, described in detail below, include:
868
+ # * `row_sep`: Specifies the row separator; used to delimit rows.
869
+ # * `col_sep`: Specifies the column separator; used to delimit fields.
870
+ # * `quote_char`: Specifies the quote character; used to quote fields.
871
+ # * `write_headers`: Specifies whether headers are to be written.
872
+ # * `force_quotes`: Specifies whether each output field is to be quoted.
873
+ # * `quote_empty`: Specifies whether each empty output field is to be quoted.
874
+ # * `write_converters`: Specifies the field converters to be used in writing.
875
+ # * `write_nil_value`: Specifies the object that is to be substituted for each
876
+ # `nil`-valued field.
877
+ # * `write_empty_value`: Specifies the object that is to be substituted for
878
+ # each empty field.
76
879
  #
77
- # ## Data Conversion
78
880
  #
79
- # ### CSV with headers
881
+ # ###### Option `row_sep`
882
+ #
883
+ # Specifies the row separator, a String or the Symbol `:auto` (see below), to be
884
+ # used for both parsing and generating.
885
+ #
886
+ # Default value:
887
+ # CSV::DEFAULT_OPTIONS.fetch(:row_sep) # => :auto
888
+ #
889
+ # ---
890
+ #
891
+ # When `row_sep` is a String, that String becomes the row separator. The String
892
+ # will be transcoded into the data's Encoding before use.
893
+ #
894
+ # Using `"\n"`:
895
+ # row_sep = "\n"
896
+ # str = CSV.generate(row_sep: row_sep) do |csv|
897
+ # csv << [:foo, 0]
898
+ # csv << [:bar, 1]
899
+ # csv << [:baz, 2]
900
+ # end
901
+ # str # => "foo,0\nbar,1\nbaz,2\n"
902
+ # ary = CSV.parse(str)
903
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
904
+ #
905
+ # Using `|` (pipe):
906
+ # row_sep = '|'
907
+ # str = CSV.generate(row_sep: row_sep) do |csv|
908
+ # csv << [:foo, 0]
909
+ # csv << [:bar, 1]
910
+ # csv << [:baz, 2]
911
+ # end
912
+ # str # => "foo,0|bar,1|baz,2|"
913
+ # ary = CSV.parse(str, row_sep: row_sep)
914
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
915
+ #
916
+ # Using `--` (two hyphens):
917
+ # row_sep = '--'
918
+ # str = CSV.generate(row_sep: row_sep) do |csv|
919
+ # csv << [:foo, 0]
920
+ # csv << [:bar, 1]
921
+ # csv << [:baz, 2]
922
+ # end
923
+ # str # => "foo,0--bar,1--baz,2--"
924
+ # ary = CSV.parse(str, row_sep: row_sep)
925
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
926
+ #
927
+ # Using `''` (empty string):
928
+ # row_sep = ''
929
+ # str = CSV.generate(row_sep: row_sep) do |csv|
930
+ # csv << [:foo, 0]
931
+ # csv << [:bar, 1]
932
+ # csv << [:baz, 2]
933
+ # end
934
+ # str # => "foo,0bar,1baz,2"
935
+ # ary = CSV.parse(str, row_sep: row_sep)
936
+ # ary # => [["foo", "0bar", "1baz", "2"]]
937
+ #
938
+ # ---
939
+ #
940
+ # When `row_sep` is the Symbol `:auto` (the default), generating uses `"\n"` as
941
+ # the row separator:
942
+ # str = CSV.generate do |csv|
943
+ # csv << [:foo, 0]
944
+ # csv << [:bar, 1]
945
+ # csv << [:baz, 2]
946
+ # end
947
+ # str # => "foo,0\nbar,1\nbaz,2\n"
948
+ #
949
+ # Parsing, on the other hand, invokes auto-discovery of the row separator.
950
+ #
951
+ # Auto-discovery reads ahead in the data looking for the next `\r\n`, `\n`, or
952
+ # `\r` sequence. The sequence will be selected even if it occurs in a quoted
953
+ # field, assuming that you would have the same line endings there.
954
+ #
955
+ # Example:
956
+ # str = CSV.generate do |csv|
957
+ # csv << [:foo, 0]
958
+ # csv << [:bar, 1]
959
+ # csv << [:baz, 2]
960
+ # end
961
+ # str # => "foo,0\nbar,1\nbaz,2\n"
962
+ # ary = CSV.parse(str)
963
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
964
+ #
965
+ # The default `$INPUT_RECORD_SEPARATOR` (`$/`) is used if any of the following
966
+ # is true:
967
+ # * None of those sequences is found.
968
+ # * Data is `ARGF`, `STDIN`, `STDOUT`, or `STDERR`.
969
+ # * The stream is only available for output.
970
+ #
971
+ #
972
+ # Obviously, discovery takes a little time. Set manually if speed is important.
973
+ # Also note that IO objects should be opened in binary mode on Windows if this
974
+ # feature will be used as the line-ending translation can cause problems with
975
+ # resetting the document position to where it was before the read ahead.
976
+ #
977
+ # ---
978
+ #
979
+ # Raises an exception if the given value is not String-convertible:
980
+ # row_sep = BasicObject.new
981
+ # # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
982
+ # CSV.generate(ary, row_sep: row_sep)
983
+ # # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
984
+ # CSV.parse(str, row_sep: row_sep)
985
+ #
986
+ # ###### Option `col_sep`
987
+ #
988
+ # Specifies the String field separator to be used for both parsing and
989
+ # generating. The String will be transcoded into the data's Encoding before use.
990
+ #
991
+ # Default value:
992
+ # CSV::DEFAULT_OPTIONS.fetch(:col_sep) # => "," (comma)
993
+ #
994
+ # Using the default (comma):
995
+ # str = CSV.generate do |csv|
996
+ # csv << [:foo, 0]
997
+ # csv << [:bar, 1]
998
+ # csv << [:baz, 2]
999
+ # end
1000
+ # str # => "foo,0\nbar,1\nbaz,2\n"
1001
+ # ary = CSV.parse(str)
1002
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
1003
+ #
1004
+ # Using `:` (colon):
1005
+ # col_sep = ':'
1006
+ # str = CSV.generate(col_sep: col_sep) do |csv|
1007
+ # csv << [:foo, 0]
1008
+ # csv << [:bar, 1]
1009
+ # csv << [:baz, 2]
1010
+ # end
1011
+ # str # => "foo:0\nbar:1\nbaz:2\n"
1012
+ # ary = CSV.parse(str, col_sep: col_sep)
1013
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
1014
+ #
1015
+ # Using `::` (two colons):
1016
+ # col_sep = '::'
1017
+ # str = CSV.generate(col_sep: col_sep) do |csv|
1018
+ # csv << [:foo, 0]
1019
+ # csv << [:bar, 1]
1020
+ # csv << [:baz, 2]
1021
+ # end
1022
+ # str # => "foo::0\nbar::1\nbaz::2\n"
1023
+ # ary = CSV.parse(str, col_sep: col_sep)
1024
+ # ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
1025
+ #
1026
+ # Using `''` (empty string):
1027
+ # col_sep = ''
1028
+ # str = CSV.generate(col_sep: col_sep) do |csv|
1029
+ # csv << [:foo, 0]
1030
+ # csv << [:bar, 1]
1031
+ # csv << [:baz, 2]
1032
+ # end
1033
+ # str # => "foo0\nbar1\nbaz2\n"
1034
+ #
1035
+ # ---
1036
+ #
1037
+ # Raises an exception if parsing with the empty String:
1038
+ # col_sep = ''
1039
+ # # Raises ArgumentError (:col_sep must be 1 or more characters: "")
1040
+ # CSV.parse("foo0\nbar1\nbaz2\n", col_sep: col_sep)
1041
+ #
1042
+ # Raises an exception if the given value is not String-convertible:
1043
+ # col_sep = BasicObject.new
1044
+ # # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
1045
+ # CSV.generate(line, col_sep: col_sep)
1046
+ # # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
1047
+ # CSV.parse(str, col_sep: col_sep)
1048
+ #
1049
+ # ###### Option `quote_char`
1050
+ #
1051
+ # Specifies the character (String of length 1) used used to quote fields in both
1052
+ # parsing and generating. This String will be transcoded into the data's
1053
+ # Encoding before use.
1054
+ #
1055
+ # Default value:
1056
+ # CSV::DEFAULT_OPTIONS.fetch(:quote_char) # => "\"" (double quote)
1057
+ #
1058
+ # This is useful for an application that incorrectly uses `'` (single-quote) to
1059
+ # quote fields, instead of the correct `"` (double-quote).
1060
+ #
1061
+ # Using the default (double quote):
1062
+ # str = CSV.generate do |csv|
1063
+ # csv << ['foo', 0]
1064
+ # csv << ["'bar'", 1]
1065
+ # csv << ['"baz"', 2]
1066
+ # end
1067
+ # str # => "foo,0\n'bar',1\n\"\"\"baz\"\"\",2\n"
1068
+ # ary = CSV.parse(str)
1069
+ # ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
1070
+ #
1071
+ # Using `'` (single-quote):
1072
+ # quote_char = "'"
1073
+ # str = CSV.generate(quote_char: quote_char) do |csv|
1074
+ # csv << ['foo', 0]
1075
+ # csv << ["'bar'", 1]
1076
+ # csv << ['"baz"', 2]
1077
+ # end
1078
+ # str # => "foo,0\n'''bar''',1\n\"baz\",2\n"
1079
+ # ary = CSV.parse(str, quote_char: quote_char)
1080
+ # ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
1081
+ #
1082
+ # ---
1083
+ #
1084
+ # Raises an exception if the String length is greater than 1:
1085
+ # # Raises ArgumentError (:quote_char has to be nil or a single character String)
1086
+ # CSV.new('', quote_char: 'xx')
1087
+ #
1088
+ # Raises an exception if the value is not a String:
1089
+ # # Raises ArgumentError (:quote_char has to be nil or a single character String)
1090
+ # CSV.new('', quote_char: :foo)
1091
+ #
1092
+ # ###### Option `write_headers`
1093
+ #
1094
+ # Specifies the boolean that determines whether a header row is included in the
1095
+ # output; ignored if there are no headers.
1096
+ #
1097
+ # Default value:
1098
+ # CSV::DEFAULT_OPTIONS.fetch(:write_headers) # => nil
1099
+ #
1100
+ # Without `write_headers`:
1101
+ # file_path = 't.csv'
1102
+ # CSV.open(file_path,'w',
1103
+ # :headers => ['Name','Value']
1104
+ # ) do |csv|
1105
+ # csv << ['foo', '0']
1106
+ # end
1107
+ # CSV.open(file_path) do |csv|
1108
+ # csv.shift
1109
+ # end # => ["foo", "0"]
1110
+ #
1111
+ # With `write_headers`":
1112
+ # CSV.open(file_path,'w',
1113
+ # :write_headers=> true,
1114
+ # :headers => ['Name','Value']
1115
+ # ) do |csv|
1116
+ # csv << ['foo', '0']
1117
+ # end
1118
+ # CSV.open(file_path) do |csv|
1119
+ # csv.shift
1120
+ # end # => ["Name", "Value"]
1121
+ #
1122
+ # ###### Option `force_quotes`
1123
+ #
1124
+ # Specifies the boolean that determines whether each output field is to be
1125
+ # double-quoted.
1126
+ #
1127
+ # Default value:
1128
+ # CSV::DEFAULT_OPTIONS.fetch(:force_quotes) # => false
1129
+ #
1130
+ # For examples in this section:
1131
+ # ary = ['foo', 0, nil]
1132
+ #
1133
+ # Using the default, `false`:
1134
+ # str = CSV.generate_line(ary)
1135
+ # str # => "foo,0,\n"
1136
+ #
1137
+ # Using `true`:
1138
+ # str = CSV.generate_line(ary, force_quotes: true)
1139
+ # str # => "\"foo\",\"0\",\"\"\n"
1140
+ #
1141
+ # ###### Option `quote_empty`
1142
+ #
1143
+ # Specifies the boolean that determines whether an empty value is to be
1144
+ # double-quoted.
1145
+ #
1146
+ # Default value:
1147
+ # CSV::DEFAULT_OPTIONS.fetch(:quote_empty) # => true
1148
+ #
1149
+ # With the default `true`:
1150
+ # CSV.generate_line(['"', ""]) # => "\"\"\"\",\"\"\n"
1151
+ #
1152
+ # With `false`:
1153
+ # CSV.generate_line(['"', ""], quote_empty: false) # => "\"\"\"\",\n"
1154
+ #
1155
+ # ###### Option `write_converters`
1156
+ #
1157
+ # Specifies converters to be used in generating fields. See [Write
1158
+ # Converters](#class-CSV-label-Write+Converters)
1159
+ #
1160
+ # Default value:
1161
+ # CSV::DEFAULT_OPTIONS.fetch(:write_converters) # => nil
1162
+ #
1163
+ # With no write converter:
1164
+ # str = CSV.generate_line(["\na\n", "\tb\t", " c "])
1165
+ # str # => "\"\na\n\",\tb\t, c \n"
1166
+ #
1167
+ # With a write converter:
1168
+ # strip_converter = proc {|field| field.strip }
1169
+ # str = CSV.generate_line(["\na\n", "\tb\t", " c "], write_converters: strip_converter)
1170
+ # str # => "a,b,c\n"
1171
+ #
1172
+ # With two write converters (called in order):
1173
+ # upcase_converter = proc {|field| field.upcase }
1174
+ # downcase_converter = proc {|field| field.downcase }
1175
+ # write_converters = [upcase_converter, downcase_converter]
1176
+ # str = CSV.generate_line(['a', 'b', 'c'], write_converters: write_converters)
1177
+ # str # => "a,b,c\n"
1178
+ #
1179
+ # See also [Write Converters](#class-CSV-label-Write+Converters)
1180
+ #
1181
+ # ---
1182
+ #
1183
+ # Raises an exception if the converter returns a value that is neither `nil` nor
1184
+ # String-convertible:
1185
+ # bad_converter = proc {|field| BasicObject.new }
1186
+ # # Raises NoMethodError (undefined method `is_a?' for #<BasicObject:>)
1187
+ # CSV.generate_line(['a', 'b', 'c'], write_converters: bad_converter)#
1188
+ #
1189
+ # ###### Option `write_nil_value`
1190
+ #
1191
+ # Specifies the object that is to be substituted for each `nil`-valued field.
1192
+ #
1193
+ # Default value:
1194
+ # CSV::DEFAULT_OPTIONS.fetch(:write_nil_value) # => nil
1195
+ #
1196
+ # Without the option:
1197
+ # str = CSV.generate_line(['a', nil, 'c', nil])
1198
+ # str # => "a,,c,\n"
1199
+ #
1200
+ # With the option:
1201
+ # str = CSV.generate_line(['a', nil, 'c', nil], write_nil_value: "x")
1202
+ # str # => "a,x,c,x\n"
1203
+ #
1204
+ # ###### Option `write_empty_value`
1205
+ #
1206
+ # Specifies the object that is to be substituted for each field that has an
1207
+ # empty String.
1208
+ #
1209
+ # Default value:
1210
+ # CSV::DEFAULT_OPTIONS.fetch(:write_empty_value) # => ""
1211
+ #
1212
+ # Without the option:
1213
+ # str = CSV.generate_line(['a', '', 'c', ''])
1214
+ # str # => "a,\"\",c,\"\"\n"
1215
+ #
1216
+ # With the option:
1217
+ # str = CSV.generate_line(['a', '', 'c', ''], write_empty_value: "x")
1218
+ # str # => "a,x,c,x\n"
1219
+ #
1220
+ # ### CSV with Headers
80
1221
  #
81
1222
  # CSV allows to specify column names of CSV file, whether they are in data, or
82
1223
  # provided separately. If headers are specified, reading methods return an
83
1224
  # instance of CSV::Table, consisting of CSV::Row.
84
1225
  #
85
- # # Headers are part of data
86
- # data = CSV.parse(<<~ROWS, headers: true)
87
- # Name,Department,Salary
88
- # Bob,Engineering,1000
89
- # Jane,Sales,2000
90
- # John,Management,5000
91
- # ROWS
1226
+ # # Headers are part of data
1227
+ # data = CSV.parse(<<~ROWS, headers: true)
1228
+ # Name,Department,Salary
1229
+ # Bob,Engineering,1000
1230
+ # Jane,Sales,2000
1231
+ # John,Management,5000
1232
+ # ROWS
1233
+ #
1234
+ # data.class #=> CSV::Table
1235
+ # data.first #=> #<CSV::Row "Name":"Bob" "Department":"Engineering" "Salary":"1000">
1236
+ # data.first.to_h #=> {"Name"=>"Bob", "Department"=>"Engineering", "Salary"=>"1000"}
1237
+ #
1238
+ # # Headers provided by developer
1239
+ # data = CSV.parse('Bob,Engineering,1000', headers: %i[name department salary])
1240
+ # data.first #=> #<CSV::Row name:"Bob" department:"Engineering" salary:"1000">
1241
+ #
1242
+ # ### Converters
1243
+ #
1244
+ # By default, each value (field or header) parsed by CSV is formed into a
1245
+ # String. You can use a *field* *converter* or *header* *converter* to
1246
+ # intercept and modify the parsed values:
1247
+ # * See [Field Converters](#class-CSV-label-Field+Converters).
1248
+ # * See [Header Converters](#class-CSV-label-Header+Converters).
1249
+ #
1250
+ #
1251
+ # Also by default, each value to be written during generation is written
1252
+ # 'as-is'. You can use a *write* *converter* to modify values before writing.
1253
+ # * See [Write Converters](#class-CSV-label-Write+Converters).
1254
+ #
1255
+ #
1256
+ # #### Specifying Converters
1257
+ #
1258
+ # You can specify converters for parsing or generating in the `options` argument
1259
+ # to various CSV methods:
1260
+ # * Option `converters` for converting parsed field values.
1261
+ # * Option `header_converters` for converting parsed header values.
1262
+ # * Option `write_converters` for converting values to be written (generated).
1263
+ #
1264
+ #
1265
+ # There are three forms for specifying converters:
1266
+ # * A converter proc: executable code to be used for conversion.
1267
+ # * A converter name: the name of a stored converter.
1268
+ # * A converter list: an array of converter procs, converter names, and
1269
+ # converter lists.
1270
+ #
1271
+ #
1272
+ # ##### Converter Procs
1273
+ #
1274
+ # This converter proc, `strip_converter`, accepts a value `field` and returns
1275
+ # `field.strip`:
1276
+ # strip_converter = proc {|field| field.strip }
1277
+ #
1278
+ # In this call to `CSV.parse`, the keyword argument `converters:
1279
+ # string_converter` specifies that:
1280
+ # * Proc `string_converter` is to be called for each parsed field.
1281
+ # * The converter's return value is to replace the `field` value.
1282
+ #
1283
+ # Example:
1284
+ # string = " foo , 0 \n bar , 1 \n baz , 2 \n"
1285
+ # array = CSV.parse(string, converters: strip_converter)
1286
+ # array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
1287
+ #
1288
+ # A converter proc can receive a second argument, `field_info`, that contains
1289
+ # details about the field. This modified `strip_converter` displays its
1290
+ # arguments:
1291
+ # strip_converter = proc do |field, field_info|
1292
+ # p [field, field_info]
1293
+ # field.strip
1294
+ # end
1295
+ # string = " foo , 0 \n bar , 1 \n baz , 2 \n"
1296
+ # array = CSV.parse(string, converters: strip_converter)
1297
+ # array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
1298
+ #
1299
+ # Output:
1300
+ # [" foo ", #<struct CSV::FieldInfo index=0, line=1, header=nil>]
1301
+ # [" 0 ", #<struct CSV::FieldInfo index=1, line=1, header=nil>]
1302
+ # [" bar ", #<struct CSV::FieldInfo index=0, line=2, header=nil>]
1303
+ # [" 1 ", #<struct CSV::FieldInfo index=1, line=2, header=nil>]
1304
+ # [" baz ", #<struct CSV::FieldInfo index=0, line=3, header=nil>]
1305
+ # [" 2 ", #<struct CSV::FieldInfo index=1, line=3, header=nil>]
1306
+ #
1307
+ # Each CSV::FieldInfo object shows:
1308
+ # * The 0-based field index.
1309
+ # * The 1-based line index.
1310
+ # * The field header, if any.
1311
+ #
1312
+ #
1313
+ # ##### Stored Converters
1314
+ #
1315
+ # A converter may be given a name and stored in a structure where the parsing
1316
+ # methods can find it by name.
1317
+ #
1318
+ # The storage structure for field converters is the Hash CSV::Converters. It has
1319
+ # several built-in converter procs:
1320
+ # * `:integer`: converts each String-embedded integer into a true Integer.
1321
+ # * `:float`: converts each String-embedded float into a true Float.
1322
+ # * `:date`: converts each String-embedded date into a true Date.
1323
+ # * `:date_time`: converts each String-embedded date-time into a true DateTime
1324
+ #
1325
+ # . This example creates a converter proc, then stores it:
1326
+ # strip_converter = proc {|field| field.strip }
1327
+ # CSV::Converters[:strip] = strip_converter
1328
+ #
1329
+ # Then the parsing method call can refer to the converter by its name, `:strip`:
1330
+ # string = " foo , 0 \n bar , 1 \n baz , 2 \n"
1331
+ # array = CSV.parse(string, converters: :strip)
1332
+ # array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
1333
+ #
1334
+ # The storage structure for header converters is the Hash CSV::HeaderConverters,
1335
+ # which works in the same way. It also has built-in converter procs:
1336
+ # * `:downcase`: Downcases each header.
1337
+ # * `:symbol`: Converts each header to a Symbol.
1338
+ #
1339
+ #
1340
+ # There is no such storage structure for write headers.
1341
+ #
1342
+ # In order for the parsing methods to access stored converters in
1343
+ # non-main-Ractors, the storage structure must be made shareable first.
1344
+ # Therefore, `Ractor.make_shareable(CSV::Converters)` and
1345
+ # `Ractor.make_shareable(CSV::HeaderConverters)` must be called before the
1346
+ # creation of Ractors that use the converters stored in these structures. (Since
1347
+ # making the storage structures shareable involves freezing them, any custom
1348
+ # converters that are to be used must be added first.)
1349
+ #
1350
+ # ##### Converter Lists
1351
+ #
1352
+ # A *converter* *list* is an Array that may include any assortment of:
1353
+ # * Converter procs.
1354
+ # * Names of stored converters.
1355
+ # * Nested converter lists.
1356
+ #
1357
+ #
1358
+ # Examples:
1359
+ # numeric_converters = [:integer, :float]
1360
+ # date_converters = [:date, :date_time]
1361
+ # [numeric_converters, strip_converter]
1362
+ # [strip_converter, date_converters, :float]
1363
+ #
1364
+ # Like a converter proc, a converter list may be named and stored in either
1365
+ # CSV::Converters or CSV::HeaderConverters:
1366
+ # CSV::Converters[:custom] = [strip_converter, date_converters, :float]
1367
+ # CSV::HeaderConverters[:custom] = [:downcase, :symbol]
1368
+ #
1369
+ # There are two built-in converter lists:
1370
+ # CSV::Converters[:numeric] # => [:integer, :float]
1371
+ # CSV::Converters[:all] # => [:date_time, :numeric]
1372
+ #
1373
+ # #### Field Converters
1374
+ #
1375
+ # With no conversion, all parsed fields in all rows become Strings:
1376
+ # string = "foo,0\nbar,1\nbaz,2\n"
1377
+ # ary = CSV.parse(string)
1378
+ # ary # => # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
1379
+ #
1380
+ # When you specify a field converter, each parsed field is passed to the
1381
+ # converter; its return value becomes the stored value for the field. A
1382
+ # converter might, for example, convert an integer embedded in a String into a
1383
+ # true Integer. (In fact, that's what built-in field converter `:integer` does.)
1384
+ #
1385
+ # There are three ways to use field converters.
1386
+ #
1387
+ # * Using option [converters](#class-CSV-label-Option+converters) with a
1388
+ # parsing method:
1389
+ # ary = CSV.parse(string, converters: :integer)
1390
+ # ary # => [0, 1, 2] # => [["foo", 0], ["bar", 1], ["baz", 2]]
1391
+ #
1392
+ # * Using option [converters](#class-CSV-label-Option+converters) with a new
1393
+ # CSV instance:
1394
+ # csv = CSV.new(string, converters: :integer)
1395
+ # # Field converters in effect:
1396
+ # csv.converters # => [:integer]
1397
+ # csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
1398
+ #
1399
+ # * Using method #convert to add a field converter to a CSV instance:
1400
+ # csv = CSV.new(string)
1401
+ # # Add a converter.
1402
+ # csv.convert(:integer)
1403
+ # csv.converters # => [:integer]
1404
+ # csv.read # => [["foo", 0], ["bar", 1], ["baz", 2]]
1405
+ #
1406
+ #
1407
+ # Installing a field converter does not affect already-read rows:
1408
+ # csv = CSV.new(string)
1409
+ # csv.shift # => ["foo", "0"]
1410
+ # # Add a converter.
1411
+ # csv.convert(:integer)
1412
+ # csv.converters # => [:integer]
1413
+ # csv.read # => [["bar", 1], ["baz", 2]]
1414
+ #
1415
+ # There are additional built-in converters, and custom converters are also
1416
+ # supported.
1417
+ #
1418
+ # ##### Built-In Field Converters
1419
+ #
1420
+ # The built-in field converters are in Hash CSV::Converters:
1421
+ # * Each key is a field converter name.
1422
+ # * Each value is one of:
1423
+ # * A Proc field converter.
1424
+ # * An Array of field converter names.
1425
+ #
1426
+ #
1427
+ #
1428
+ # Display:
1429
+ # CSV::Converters.each_pair do |name, value|
1430
+ # if value.kind_of?(Proc)
1431
+ # p [name, value.class]
1432
+ # else
1433
+ # p [name, value]
1434
+ # end
1435
+ # end
1436
+ #
1437
+ # Output:
1438
+ # [:integer, Proc]
1439
+ # [:float, Proc]
1440
+ # [:numeric, [:integer, :float]]
1441
+ # [:date, Proc]
1442
+ # [:date_time, Proc]
1443
+ # [:all, [:date_time, :numeric]]
1444
+ #
1445
+ # Each of these converters transcodes values to UTF-8 before attempting
1446
+ # conversion. If a value cannot be transcoded to UTF-8 the conversion will fail
1447
+ # and the value will remain unconverted.
1448
+ #
1449
+ # Converter `:integer` converts each field that Integer() accepts:
1450
+ # data = '0,1,2,x'
1451
+ # # Without the converter
1452
+ # csv = CSV.parse_line(data)
1453
+ # csv # => ["0", "1", "2", "x"]
1454
+ # # With the converter
1455
+ # csv = CSV.parse_line(data, converters: :integer)
1456
+ # csv # => [0, 1, 2, "x"]
1457
+ #
1458
+ # Converter `:float` converts each field that Float() accepts:
1459
+ # data = '1.0,3.14159,x'
1460
+ # # Without the converter
1461
+ # csv = CSV.parse_line(data)
1462
+ # csv # => ["1.0", "3.14159", "x"]
1463
+ # # With the converter
1464
+ # csv = CSV.parse_line(data, converters: :float)
1465
+ # csv # => [1.0, 3.14159, "x"]
1466
+ #
1467
+ # Converter `:numeric` converts with both `:integer` and `:float`..
1468
+ #
1469
+ # Converter `:date` converts each field that Date::parse accepts:
1470
+ # data = '2001-02-03,x'
1471
+ # # Without the converter
1472
+ # csv = CSV.parse_line(data)
1473
+ # csv # => ["2001-02-03", "x"]
1474
+ # # With the converter
1475
+ # csv = CSV.parse_line(data, converters: :date)
1476
+ # csv # => [#<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>, "x"]
1477
+ #
1478
+ # Converter `:date_time` converts each field that DateTime::parse accepts:
1479
+ # data = '2020-05-07T14:59:00-05:00,x'
1480
+ # # Without the converter
1481
+ # csv = CSV.parse_line(data)
1482
+ # csv # => ["2020-05-07T14:59:00-05:00", "x"]
1483
+ # # With the converter
1484
+ # csv = CSV.parse_line(data, converters: :date_time)
1485
+ # csv # => [#<DateTime: 2020-05-07T14:59:00-05:00 ((2458977j,71940s,0n),-18000s,2299161j)>, "x"]
1486
+ #
1487
+ # Converter `:numeric` converts with both `:date_time` and `:numeric`..
1488
+ #
1489
+ # As seen above, method #convert adds converters to a CSV instance, and method
1490
+ # #converters returns an Array of the converters in effect:
1491
+ # csv = CSV.new('0,1,2')
1492
+ # csv.converters # => []
1493
+ # csv.convert(:integer)
1494
+ # csv.converters # => [:integer]
1495
+ # csv.convert(:date)
1496
+ # csv.converters # => [:integer, :date]
1497
+ #
1498
+ # ##### Custom Field Converters
1499
+ #
1500
+ # You can define a custom field converter:
1501
+ # strip_converter = proc {|field| field.strip }
1502
+ # string = " foo , 0 \n bar , 1 \n baz , 2 \n"
1503
+ # array = CSV.parse(string, converters: strip_converter)
1504
+ # array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
1505
+ #
1506
+ # You can register the converter in Converters Hash, which allows you to refer
1507
+ # to it by name:
1508
+ # CSV::Converters[:strip] = strip_converter
1509
+ # string = " foo , 0 \n bar , 1 \n baz , 2 \n"
1510
+ # array = CSV.parse(string, converters: :strip)
1511
+ # array # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
1512
+ #
1513
+ # #### Header Converters
1514
+ #
1515
+ # Header converters operate only on headers (and not on other rows).
1516
+ #
1517
+ # There are three ways to use header converters; these examples use built-in
1518
+ # header converter `:dowhcase`, which downcases each parsed header.
1519
+ #
1520
+ # * Option `header_converters` with a singleton parsing method:
1521
+ # string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
1522
+ # tbl = CSV.parse(string, headers: true, header_converters: :downcase)
1523
+ # tbl.class # => CSV::Table
1524
+ # tbl.headers # => ["name", "count"]
1525
+ #
1526
+ # * Option `header_converters` with a new CSV instance:
1527
+ # csv = CSV.new(string, header_converters: :downcase)
1528
+ # # Header converters in effect:
1529
+ # csv.header_converters # => [:downcase]
1530
+ # tbl = CSV.parse(string, headers: true)
1531
+ # tbl.headers # => ["Name", "Count"]
1532
+ #
1533
+ # * Method #header_convert adds a header converter to a CSV instance:
1534
+ # csv = CSV.new(string)
1535
+ # # Add a header converter.
1536
+ # csv.header_convert(:downcase)
1537
+ # csv.header_converters # => [:downcase]
1538
+ # tbl = CSV.parse(string, headers: true)
1539
+ # tbl.headers # => ["Name", "Count"]
1540
+ #
1541
+ #
1542
+ # ##### Built-In Header Converters
1543
+ #
1544
+ # The built-in header converters are in Hash CSV::HeaderConverters. The keys
1545
+ # there are the names of the converters:
1546
+ # CSV::HeaderConverters.keys # => [:downcase, :symbol]
1547
+ #
1548
+ # Converter `:downcase` converts each header by downcasing it:
1549
+ # string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
1550
+ # tbl = CSV.parse(string, headers: true, header_converters: :downcase)
1551
+ # tbl.class # => CSV::Table
1552
+ # tbl.headers # => ["name", "count"]
1553
+ #
1554
+ # Converter `:symbol` converts each header by making it into a Symbol:
1555
+ # string = "Name,Count\nFoo,0\n,Bar,1\nBaz,2"
1556
+ # tbl = CSV.parse(string, headers: true, header_converters: :symbol)
1557
+ # tbl.headers # => [:name, :count]
1558
+ #
1559
+ # Details:
1560
+ # * Strips leading and trailing whitespace.
1561
+ # * Downcases the header.
1562
+ # * Replaces embedded spaces with underscores.
1563
+ # * Removes non-word characters.
1564
+ # * Makes the string into a Symbol.
1565
+ #
92
1566
  #
93
- # data.class #=> CSV::Table
94
- # data.first #=> #<CSV::Row "Name":"Bob" "Department":"Engineering" "Salary":"1000">
95
- # data.first.to_h #=> {"Name"=>"Bob", "Department"=>"Engineering", "Salary"=>"1000"}
1567
+ # ##### Custom Header Converters
96
1568
  #
97
- # # Headers provided by developer
98
- # data = CSV.parse('Bob,Engineering,1000', headers: %i[name department salary])
99
- # data.first #=> #<CSV::Row name:"Bob" department:"Engineering" salary:"1000">
1569
+ # You can define a custom header converter:
1570
+ # upcase_converter = proc {|header| header.upcase }
1571
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
1572
+ # table = CSV.parse(string, headers: true, header_converters: upcase_converter)
1573
+ # table # => #<CSV::Table mode:col_or_row row_count:4>
1574
+ # table.headers # => ["NAME", "VALUE"]
100
1575
  #
101
- # ### Typed data reading
1576
+ # You can register the converter in HeaderConverters Hash, which allows you to
1577
+ # refer to it by name:
1578
+ # CSV::HeaderConverters[:upcase] = upcase_converter
1579
+ # table = CSV.parse(string, headers: true, header_converters: :upcase)
1580
+ # table # => #<CSV::Table mode:col_or_row row_count:4>
1581
+ # table.headers # => ["NAME", "VALUE"]
102
1582
  #
103
- # CSV allows to provide a set of data *converters* e.g. transformations to try
104
- # on input data. Converter could be a symbol from CSV::Converters constant's
105
- # keys, or lambda.
1583
+ # ##### Write Converters
106
1584
  #
107
- # # Without any converters:
108
- # CSV.parse('Bob,2018-03-01,100')
109
- # #=> [["Bob", "2018-03-01", "100"]]
1585
+ # When you specify a write converter for generating CSV, each field to be
1586
+ # written is passed to the converter; its return value becomes the new value for
1587
+ # the field. A converter might, for example, strip whitespace from a field.
110
1588
  #
111
- # # With built-in converters:
112
- # CSV.parse('Bob,2018-03-01,100', converters: %i[numeric date])
113
- # #=> [["Bob", #<Date: 2018-03-01>, 100]]
1589
+ # Using no write converter (all fields unmodified):
1590
+ # output_string = CSV.generate do |csv|
1591
+ # csv << [' foo ', 0]
1592
+ # csv << [' bar ', 1]
1593
+ # csv << [' baz ', 2]
1594
+ # end
1595
+ # output_string # => " foo ,0\n bar ,1\n baz ,2\n"
114
1596
  #
115
- # # With custom converters:
116
- # CSV.parse('Bob,2018-03-01,100', converters: [->(v) { Time.parse(v) rescue v }])
117
- # #=> [["Bob", 2018-03-01 00:00:00 +0200, "100"]]
1597
+ # Using option `write_converters` with two custom write converters:
1598
+ # strip_converter = proc {|field| field.respond_to?(:strip) ? field.strip : field }
1599
+ # upcase_converter = proc {|field| field.respond_to?(:upcase) ? field.upcase : field }
1600
+ # write_converters = [strip_converter, upcase_converter]
1601
+ # output_string = CSV.generate(write_converters: write_converters) do |csv|
1602
+ # csv << [' foo ', 0]
1603
+ # csv << [' bar ', 1]
1604
+ # csv << [' baz ', 2]
1605
+ # end
1606
+ # output_string # => "FOO,0\nBAR,1\nBAZ,2\n"
118
1607
  #
119
- # ## CSV and Character Encodings (M17n or Multilingualization)
1608
+ # ### Character Encodings (M17n or Multilingualization)
120
1609
  #
121
1610
  # This new CSV parser is m17n savvy. The parser works in the Encoding of the IO
122
1611
  # or String object being read from or written to. Your data is never transcoded
@@ -162,287 +1651,605 @@ class CSV < Object
162
1651
  include Enumerable[untyped]
163
1652
  extend Forwardable
164
1653
 
165
- # This method is intended as the primary interface for reading CSV files. You
166
- # pass a `path` and any `options` you wish to set for the read. Each row of file
167
- # will be passed to the provided `block` in turn.
1654
+ # <!--
1655
+ # rdoc-file=lib/csv.rb
1656
+ # - foreach(path, mode='r', **options) {|row| ... )
1657
+ # - foreach(io, mode='r', **options {|row| ... )
1658
+ # - foreach(path, mode='r', headers: ..., **options) {|row| ... )
1659
+ # - foreach(io, mode='r', headers: ..., **options {|row| ... )
1660
+ # - foreach(path, mode='r', **options) -> new_enumerator
1661
+ # - foreach(io, mode='r', **options -> new_enumerator
1662
+ # -->
1663
+ # Calls the block with each row read from source `path` or `io`.
1664
+ #
1665
+ # * Argument `path`, if given, must be the path to a file.
1666
+ # * Argument `io` should be an IO object that is:
1667
+ # * Open for reading; on return, the IO object will be closed.
1668
+ # * Positioned at the beginning. To position at the end, for appending,
1669
+ # use method CSV.generate. For any other positioning, pass a preset
1670
+ # StringIO object instead.
1671
+ #
1672
+ # * Argument `mode`, if given, must be a File mode See [Open
1673
+ # Mode](IO.html#method-c-new-label-Open+Mode).
1674
+ # * Arguments `**options` must be keyword options. See [Options for
1675
+ # Parsing](#class-CSV-label-Options+for+Parsing).
1676
+ # * This method optionally accepts an additional `:encoding` option that you
1677
+ # can use to specify the Encoding of the data read from `path` or `io`. You
1678
+ # must provide this unless your data is in the encoding given by
1679
+ # `Encoding::default_external`. Parsing will use this to determine how to
1680
+ # parse the data. You may provide a second Encoding to have the data
1681
+ # transcoded as it is read. For example,
1682
+ # encoding: 'UTF-32BE:UTF-8'
1683
+ #
1684
+ # would read `UTF-32BE` data from the file but transcode it to `UTF-8`
1685
+ # before parsing.
1686
+ #
1687
+ #
1688
+ # ###### Without Option `headers`
1689
+ #
1690
+ # Without option `headers`, returns each row as an Array object.
1691
+ #
1692
+ # These examples assume prior execution of:
1693
+ # string = "foo,0\nbar,1\nbaz,2\n"
1694
+ # path = 't.csv'
1695
+ # File.write(path, string)
1696
+ #
1697
+ # Read rows from a file at `path`:
1698
+ # CSV.foreach(path) {|row| p row }
1699
+ #
1700
+ # Output:
1701
+ # ["foo", "0"]
1702
+ # ["bar", "1"]
1703
+ # ["baz", "2"]
1704
+ #
1705
+ # Read rows from an IO object:
1706
+ # File.open(path) do |file|
1707
+ # CSV.foreach(file) {|row| p row }
1708
+ # end
1709
+ #
1710
+ # Output:
1711
+ # ["foo", "0"]
1712
+ # ["bar", "1"]
1713
+ # ["baz", "2"]
1714
+ #
1715
+ # Returns a new Enumerator if no block given:
1716
+ # CSV.foreach(path) # => #<Enumerator: CSV:foreach("t.csv", "r")>
1717
+ # CSV.foreach(File.open(path)) # => #<Enumerator: CSV:foreach(#<File:t.csv>, "r")>
1718
+ #
1719
+ # Issues a warning if an encoding is unsupported:
1720
+ # CSV.foreach(File.open(path), encoding: 'foo:bar') {|row| }
1721
+ #
1722
+ # Output:
1723
+ # warning: Unsupported encoding foo ignored
1724
+ # warning: Unsupported encoding bar ignored
1725
+ #
1726
+ # ###### With Option `headers`
1727
+ #
1728
+ # With {option `headers`[}](#class-CSV-label-Option+headers), returns each row
1729
+ # as a CSV::Row object.
1730
+ #
1731
+ # These examples assume prior execution of:
1732
+ # string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n"
1733
+ # path = 't.csv'
1734
+ # File.write(path, string)
1735
+ #
1736
+ # Read rows from a file at `path`:
1737
+ # CSV.foreach(path, headers: true) {|row| p row }
1738
+ #
1739
+ # Output:
1740
+ # #<CSV::Row "Name":"foo" "Count":"0">
1741
+ # #<CSV::Row "Name":"bar" "Count":"1">
1742
+ # #<CSV::Row "Name":"baz" "Count":"2">
1743
+ #
1744
+ # Read rows from an IO object:
1745
+ # File.open(path) do |file|
1746
+ # CSV.foreach(file, headers: true) {|row| p row }
1747
+ # end
1748
+ #
1749
+ # Output:
1750
+ # #<CSV::Row "Name":"foo" "Count":"0">
1751
+ # #<CSV::Row "Name":"bar" "Count":"1">
1752
+ # #<CSV::Row "Name":"baz" "Count":"2">
1753
+ #
1754
+ # ---
1755
+ #
1756
+ # Raises an exception if `path` is a String, but not the path to a readable
1757
+ # file:
1758
+ # # Raises Errno::ENOENT (No such file or directory @ rb_sysopen - nosuch.csv):
1759
+ # CSV.foreach('nosuch.csv') {|row| }
168
1760
  #
169
- # The `options` parameter can be anything CSV::new() understands. This method
170
- # also understands an additional `:encoding` parameter that you can use to
171
- # specify the Encoding of the data in the file to be read. You must provide this
172
- # unless your data is in Encoding::default_external(). CSV will use this to
173
- # determine how to parse the data. You may provide a second Encoding to have the
174
- # data transcoded as it is read. For example, `encoding: "UTF-32BE:UTF-8"` would
175
- # read UTF-32BE data from the file but transcode it to UTF-8 before CSV parses
176
- # it.
1761
+ # Raises an exception if `io` is an IO object, but not open for reading:
1762
+ # io = File.open(path, 'w') {|row| }
1763
+ # # Raises TypeError (no implicit conversion of nil into String):
1764
+ # CSV.foreach(io) {|row| }
1765
+ #
1766
+ # Raises an exception if `mode` is invalid:
1767
+ # # Raises ArgumentError (invalid access mode nosuch):
1768
+ # CSV.foreach(path, 'nosuch') {|row| }
177
1769
  #
178
1770
  def self.foreach: [U] (String | IO | StringIO path, ?::Hash[Symbol, U] options) { (::Array[String?] arg0) -> void } -> void
179
1771
 
180
- # This constructor will wrap either a String or IO object passed in `data` for
181
- # reading and/or writing. In addition to the CSV instance methods, several IO
182
- # methods are delegated. (See CSV::open() for a complete list.) If you pass a
183
- # String for `data`, you can later retrieve it (after writing to it, for
184
- # example) with CSV.string().
185
- #
186
- # Note that a wrapped String will be positioned at the beginning (for reading).
187
- # If you want it at the end (for writing), use CSV::generate(). If you want any
188
- # other positioning, pass a preset StringIO object instead.
189
- #
190
- # You may set any reading and/or writing preferences in the `options` Hash.
191
- # Available options are:
192
- #
193
- # **`:col_sep`**
194
- # : The String placed between each field. This String will be transcoded into
195
- # the data's Encoding before parsing.
196
- # **`:row_sep`**
197
- # : The String appended to the end of each row. This can be set to the special
198
- # `:auto` setting, which requests that CSV automatically discover this from
199
- # the data. Auto-discovery reads ahead in the data looking for the next
200
- # `"\r\n"`, `"\n"`, or `"\r"` sequence. A sequence will be selected even if
201
- # it occurs in a quoted field, assuming that you would have the same line
202
- # endings there. If none of those sequences is found, `data` is `ARGF`,
203
- # `STDIN`, `STDOUT`, or `STDERR`, or the stream is only available for
204
- # output, the default `$INPUT_RECORD_SEPARATOR` (`$/`) is used. Obviously,
205
- # discovery takes a little time. Set manually if speed is important. Also
206
- # note that IO objects should be opened in binary mode on Windows if this
207
- # feature will be used as the line-ending translation can cause problems
208
- # with resetting the document position to where it was before the read
209
- # ahead. This String will be transcoded into the data's Encoding before
210
- # parsing.
211
- # **`:quote_char`**
212
- # : The character used to quote fields. This has to be a single character
213
- # String. This is useful for application that incorrectly use `'` as the
214
- # quote character instead of the correct `"`. CSV will always consider a
215
- # double sequence of this character to be an escaped quote. This String will
216
- # be transcoded into the data's Encoding before parsing.
217
- # **`:field_size_limit`**
218
- # : This is a maximum size CSV will read ahead looking for the closing quote
219
- # for a field. (In truth, it reads to the first line ending beyond this
220
- # size.) If a quote cannot be found within the limit CSV will raise a
221
- # MalformedCSVError, assuming the data is faulty. You can use this limit to
222
- # prevent what are effectively DoS attacks on the parser. However, this
223
- # limit can cause a legitimate parse to fail and thus is set to `nil`, or
224
- # off, by default.
225
- # **`:converters`**
226
- # : An Array of names from the Converters Hash and/or lambdas that handle
227
- # custom conversion. A single converter doesn't have to be in an Array. All
228
- # built-in converters try to transcode fields to UTF-8 before converting.
229
- # The conversion will fail if the data cannot be transcoded, leaving the
230
- # field unchanged.
231
- # **`:unconverted_fields`**
232
- # : If set to `true`, an unconverted_fields() method will be added to all
233
- # returned rows (Array or CSV::Row) that will return the fields as they were
234
- # before conversion. Note that `:headers` supplied by Array or String were
235
- # not fields of the document and thus will have an empty Array attached.
236
- # **`:headers`**
237
- # : If set to `:first_row` or `true`, the initial row of the CSV file will be
238
- # treated as a row of headers. If set to an Array, the contents will be used
239
- # as the headers. If set to a String, the String is run through a call of
240
- # CSV::parse_line() with the same `:col_sep`, `:row_sep`, and `:quote_char`
241
- # as this instance to produce an Array of headers. This setting causes
242
- # CSV#shift() to return rows as CSV::Row objects instead of Arrays and
243
- # CSV#read() to return CSV::Table objects instead of an Array of Arrays.
244
- # **`:return_headers`**
245
- # : When `false`, header rows are silently swallowed. If set to `true`, header
246
- # rows are returned in a CSV::Row object with identical headers and fields
247
- # (save that the fields do not go through the converters).
248
- # **`:write_headers`**
249
- # : When `true` and `:headers` is set, a header row will be added to the
250
- # output.
251
- # **`:header_converters`**
252
- # : Identical in functionality to `:converters` save that the conversions are
253
- # only made to header rows. All built-in converters try to transcode headers
254
- # to UTF-8 before converting. The conversion will fail if the data cannot be
255
- # transcoded, leaving the header unchanged.
256
- # **`:skip_blanks`**
257
- # : When setting a `true` value, CSV will skip over any empty rows. Note that
258
- # this setting will not skip rows that contain column separators, even if
259
- # the rows contain no actual data. If you want to skip rows that contain
260
- # separators but no content, consider using `:skip_lines`, or inspecting
261
- # fields.compact.empty? on each row.
262
- # **`:force_quotes`**
263
- # : When setting a `true` value, CSV will quote all CSV fields it creates.
264
- # **`:skip_lines`**
265
- # : When setting an object responding to `match`, every line matching it is
266
- # considered a comment and ignored during parsing. When set to a String, it
267
- # is first converted to a Regexp. When set to `nil` no line is considered a
268
- # comment. If the passed object does not respond to `match`, `ArgumentError`
269
- # is thrown.
270
- # **`:liberal_parsing`**
271
- # : When setting a `true` value, CSV will attempt to parse input not
272
- # conformant with RFC 4180, such as double quotes in unquoted fields.
273
- # **`:nil_value`**
274
- # : When set an object, any values of an empty field is replaced by the set
275
- # object, not nil.
276
- # **`:empty_value`**
277
- # : When setting an object, any values of a blank string field is replaced by
278
- # the set object.
279
- # **`:quote_empty`**
280
- # : When setting a `true` value, CSV will quote empty values with double
281
- # quotes. When `false`, CSV will emit an empty string for an empty field
282
- # value.
283
- # **`:write_converters`**
284
- # : Converts values on each line with the specified `Proc` object(s), which
285
- # receive a `String` value and return a `String` or `nil` value. When an
286
- # array is specified, each converter will be applied in order.
287
- # **`:write_nil_value`**
288
- # : When a `String` value, `nil` value(s) on each line will be replaced with
289
- # the specified value.
290
- # **`:write_empty_value`**
291
- # : When a `String` or `nil` value, empty value(s) on each line will be
292
- # replaced with the specified value.
293
- # **`:strip`**
294
- # : When setting a `true` value, CSV will strip "t\r\n\f\v" around the values.
295
- # If you specify a string instead of `true`, CSV will strip string. The
296
- # length of the string must be 1.
297
- #
298
- #
299
- # See CSV::DEFAULT_OPTIONS for the default settings.
300
- #
301
- # Options cannot be overridden in the instance methods for performance reasons,
302
- # so be sure to set what you want here.
1772
+ # <!--
1773
+ # rdoc-file=lib/csv.rb
1774
+ # - CSV.new(string)
1775
+ # - CSV.new(io)
1776
+ # - CSV.new(string, **options)
1777
+ # - CSV.new(io, **options)
1778
+ # -->
1779
+ # Returns the new CSV object created using `string` or `io` and the specified
1780
+ # `options`.
1781
+ #
1782
+ # * Argument `string` should be a String object; it will be put into a new
1783
+ # StringIO object positioned at the beginning.
1784
+ # * Argument `io` should be an IO object that is:
1785
+ # * Open for reading; on return, the IO object will be closed.
1786
+ # * Positioned at the beginning. To position at the end, for appending,
1787
+ # use method CSV.generate. For any other positioning, pass a preset
1788
+ # StringIO object instead.
1789
+ #
1790
+ # * Argument `options`: See:
1791
+ # * [Options for Parsing](#class-CSV-label-Options+for+Parsing)
1792
+ # * [Options for Generating](#class-CSV-label-Options+for+Generating)
1793
+ #
1794
+ # For performance reasons, the options cannot be overridden in a CSV object,
1795
+ # so those specified here will endure.
1796
+ #
1797
+ #
1798
+ # In addition to the CSV instance methods, several IO methods are delegated. See
1799
+ # [Delegated Methods](#class-CSV-label-Delegated+Methods).
1800
+ #
1801
+ # ---
1802
+ #
1803
+ # Create a CSV object from a String object:
1804
+ # csv = CSV.new('foo,0')
1805
+ # csv # => #<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
1806
+ #
1807
+ # Create a CSV object from a File object:
1808
+ # File.write('t.csv', 'foo,0')
1809
+ # csv = CSV.new(File.open('t.csv'))
1810
+ # csv # => #<CSV io_type:File io_path:"t.csv" encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
1811
+ #
1812
+ # ---
1813
+ #
1814
+ # Raises an exception if the argument is `nil`:
1815
+ # # Raises ArgumentError (Cannot parse nil as CSV):
1816
+ # CSV.new(nil)
1817
+ #
303
1818
  def initialize: (?String | IO | StringIO io, ?::Hash[Symbol, untyped] options) -> void
304
1819
 
305
- # This method can be used to easily parse CSV out of a String. You may either
306
- # provide a `block` which will be called with each row of the String in turn, or
307
- # just use the returned Array of Arrays (when no `block` is given).
1820
+ # <!--
1821
+ # rdoc-file=lib/csv.rb
1822
+ # - parse(string) -> array_of_arrays
1823
+ # - parse(io) -> array_of_arrays
1824
+ # - parse(string, headers: ..., **options) -> csv_table
1825
+ # - parse(io, headers: ..., **options) -> csv_table
1826
+ # - parse(string, **options) {|row| ... }
1827
+ # - parse(io, **options) {|row| ... }
1828
+ # -->
1829
+ # Parses `string` or `io` using the specified `options`.
1830
+ #
1831
+ # * Argument `string` should be a String object; it will be put into a new
1832
+ # StringIO object positioned at the beginning.
1833
+ # * Argument `io` should be an IO object that is:
1834
+ # * Open for reading; on return, the IO object will be closed.
1835
+ # * Positioned at the beginning. To position at the end, for appending,
1836
+ # use method CSV.generate. For any other positioning, pass a preset
1837
+ # StringIO object instead.
1838
+ #
1839
+ # * Argument `options`: see [Options for
1840
+ # Parsing](#class-CSV-label-Options+for+Parsing)
1841
+ #
1842
+ #
1843
+ # ###### Without Option `headers`
1844
+ #
1845
+ # Without {option `headers`[}](#class-CSV-label-Option+headers) case.
1846
+ #
1847
+ # These examples assume prior execution of:
1848
+ # string = "foo,0\nbar,1\nbaz,2\n"
1849
+ # path = 't.csv'
1850
+ # File.write(path, string)
1851
+ #
1852
+ # ---
1853
+ #
1854
+ # With no block given, returns an Array of Arrays formed from the source.
1855
+ #
1856
+ # Parse a String:
1857
+ # a_of_a = CSV.parse(string)
1858
+ # a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
1859
+ #
1860
+ # Parse an open File:
1861
+ # a_of_a = File.open(path) do |file|
1862
+ # CSV.parse(file)
1863
+ # end
1864
+ # a_of_a # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
1865
+ #
1866
+ # ---
1867
+ #
1868
+ # With a block given, calls the block with each parsed row:
308
1869
  #
309
- # You pass your `str` to read from, and an optional `options` containing
310
- # anything CSV::new() understands.
1870
+ # Parse a String:
1871
+ # CSV.parse(string) {|row| p row }
1872
+ #
1873
+ # Output:
1874
+ # ["foo", "0"]
1875
+ # ["bar", "1"]
1876
+ # ["baz", "2"]
1877
+ #
1878
+ # Parse an open File:
1879
+ # File.open(path) do |file|
1880
+ # CSV.parse(file) {|row| p row }
1881
+ # end
1882
+ #
1883
+ # Output:
1884
+ # ["foo", "0"]
1885
+ # ["bar", "1"]
1886
+ # ["baz", "2"]
1887
+ #
1888
+ # ###### With Option `headers`
1889
+ #
1890
+ # With {option `headers`[}](#class-CSV-label-Option+headers) case.
1891
+ #
1892
+ # These examples assume prior execution of:
1893
+ # string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n"
1894
+ # path = 't.csv'
1895
+ # File.write(path, string)
1896
+ #
1897
+ # ---
1898
+ #
1899
+ # With no block given, returns a CSV::Table object formed from the source.
1900
+ #
1901
+ # Parse a String:
1902
+ # csv_table = CSV.parse(string, headers: ['Name', 'Count'])
1903
+ # csv_table # => #<CSV::Table mode:col_or_row row_count:5>
1904
+ #
1905
+ # Parse an open File:
1906
+ # csv_table = File.open(path) do |file|
1907
+ # CSV.parse(file, headers: ['Name', 'Count'])
1908
+ # end
1909
+ # csv_table # => #<CSV::Table mode:col_or_row row_count:4>
1910
+ #
1911
+ # ---
1912
+ #
1913
+ # With a block given, calls the block with each parsed row, which has been
1914
+ # formed into a CSV::Row object:
1915
+ #
1916
+ # Parse a String:
1917
+ # CSV.parse(string, headers: ['Name', 'Count']) {|row| p row }
1918
+ #
1919
+ # Output:
1920
+ # # <CSV::Row "Name":"foo" "Count":"0">
1921
+ # # <CSV::Row "Name":"bar" "Count":"1">
1922
+ # # <CSV::Row "Name":"baz" "Count":"2">
1923
+ #
1924
+ # Parse an open File:
1925
+ # File.open(path) do |file|
1926
+ # CSV.parse(file, headers: ['Name', 'Count']) {|row| p row }
1927
+ # end
1928
+ #
1929
+ # Output:
1930
+ # # <CSV::Row "Name":"foo" "Count":"0">
1931
+ # # <CSV::Row "Name":"bar" "Count":"1">
1932
+ # # <CSV::Row "Name":"baz" "Count":"2">
1933
+ #
1934
+ # ---
1935
+ #
1936
+ # Raises an exception if the argument is not a String object or IO object:
1937
+ # # Raises NoMethodError (undefined method `close' for :foo:Symbol)
1938
+ # CSV.parse(:foo)
311
1939
  #
312
1940
  def self.parse: (String str, ?::Hash[Symbol, untyped] options) ?{ (::Array[String?] arg0) -> void } -> ::Array[::Array[String?]]?
313
1941
 
314
- # This method is a shortcut for converting a single line of a CSV String into an
315
- # Array. Note that if `line` contains multiple rows, anything beyond the first
316
- # row is ignored.
1942
+ # <!--
1943
+ # rdoc-file=lib/csv.rb
1944
+ # - CSV.parse_line(string) -> new_array or nil
1945
+ # - CSV.parse_line(io) -> new_array or nil
1946
+ # - CSV.parse_line(string, **options) -> new_array or nil
1947
+ # - CSV.parse_line(io, **options) -> new_array or nil
1948
+ # - CSV.parse_line(string, headers: true, **options) -> csv_row or nil
1949
+ # - CSV.parse_line(io, headers: true, **options) -> csv_row or nil
1950
+ # -->
1951
+ # Returns the data created by parsing the first line of `string` or `io` using
1952
+ # the specified `options`.
1953
+ #
1954
+ # * Argument `string` should be a String object; it will be put into a new
1955
+ # StringIO object positioned at the beginning.
1956
+ # * Argument `io` should be an IO object that is:
1957
+ # * Open for reading; on return, the IO object will be closed.
1958
+ # * Positioned at the beginning. To position at the end, for appending,
1959
+ # use method CSV.generate. For any other positioning, pass a preset
1960
+ # StringIO object instead.
1961
+ #
1962
+ # * Argument `options`: see [Options for
1963
+ # Parsing](#class-CSV-label-Options+for+Parsing)
1964
+ #
1965
+ #
1966
+ # ###### Without Option `headers`
1967
+ #
1968
+ # Without option `headers`, returns the first row as a new Array.
1969
+ #
1970
+ # These examples assume prior execution of:
1971
+ # string = "foo,0\nbar,1\nbaz,2\n"
1972
+ # path = 't.csv'
1973
+ # File.write(path, string)
1974
+ #
1975
+ # Parse the first line from a String object:
1976
+ # CSV.parse_line(string) # => ["foo", "0"]
317
1977
  #
318
- # The `options` parameter can be anything CSV::new() understands.
1978
+ # Parse the first line from a File object:
1979
+ # File.open(path) do |file|
1980
+ # CSV.parse_line(file) # => ["foo", "0"]
1981
+ # end # => ["foo", "0"]
1982
+ #
1983
+ # Returns `nil` if the argument is an empty String:
1984
+ # CSV.parse_line('') # => nil
1985
+ #
1986
+ # ###### With Option `headers`
1987
+ #
1988
+ # With {option `headers`[}](#class-CSV-label-Option+headers), returns the first
1989
+ # row as a CSV::Row object.
1990
+ #
1991
+ # These examples assume prior execution of:
1992
+ # string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n"
1993
+ # path = 't.csv'
1994
+ # File.write(path, string)
1995
+ #
1996
+ # Parse the first line from a String object:
1997
+ # CSV.parse_line(string, headers: true) # => #<CSV::Row "Name":"foo" "Count":"0">
1998
+ #
1999
+ # Parse the first line from a File object:
2000
+ # File.open(path) do |file|
2001
+ # CSV.parse_line(file, headers: true)
2002
+ # end # => #<CSV::Row "Name":"foo" "Count":"0">
2003
+ #
2004
+ # ---
2005
+ #
2006
+ # Raises an exception if the argument is `nil`:
2007
+ # # Raises ArgumentError (Cannot parse nil as CSV):
2008
+ # CSV.parse_line(nil)
319
2009
  #
320
2010
  def self.parse_line: (String str, ?::Hash[Symbol, untyped] options) -> ::Array[String?]?
321
2011
 
322
- # Slurps the remaining rows and returns an Array of Arrays.
2012
+ # <!--
2013
+ # rdoc-file=lib/csv.rb
2014
+ # - csv.read -> array or csv_table
2015
+ # -->
2016
+ # Forms the remaining rows from `self` into:
2017
+ # * A CSV::Table object, if headers are in use.
2018
+ # * An Array of Arrays, otherwise.
2019
+ #
2020
+ #
2021
+ # The data source must be opened for reading.
2022
+ #
2023
+ # Without headers:
2024
+ # string = "foo,0\nbar,1\nbaz,2\n"
2025
+ # path = 't.csv'
2026
+ # File.write(path, string)
2027
+ # csv = CSV.open(path)
2028
+ # csv.read # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
2029
+ #
2030
+ # With headers:
2031
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2032
+ # path = 't.csv'
2033
+ # File.write(path, string)
2034
+ # csv = CSV.open(path, headers: true)
2035
+ # csv.read # => #<CSV::Table mode:col_or_row row_count:4>
323
2036
  #
324
- # The data source must be open for reading.
2037
+ # ---
2038
+ #
2039
+ # Raises an exception if the source is not opened for reading:
2040
+ # string = "foo,0\nbar,1\nbaz,2\n"
2041
+ # csv = CSV.new(string)
2042
+ # csv.close
2043
+ # # Raises IOError (not opened for reading)
2044
+ # csv.read
325
2045
  #
326
2046
  def read: () -> ::Array[::Array[String?]]
327
2047
 
2048
+ # <!--
2049
+ # rdoc-file=lib/csv.rb
2050
+ # - readline()
2051
+ # -->
2052
+ #
328
2053
  def readline: () -> ::Array[String?]?
329
2054
 
330
- # Use to slurp a CSV file into an Array of Arrays. Pass the `path` to the file
331
- # and any `options` CSV::new() understands. This method also understands an
332
- # additional `:encoding` parameter that you can use to specify the Encoding of
333
- # the data in the file to be read. You must provide this unless your data is in
334
- # Encoding::default_external(). CSV will use this to determine how to parse the
335
- # data. You may provide a second Encoding to have the data transcoded as it is
336
- # read. For example, `encoding: "UTF-32BE:UTF-8"` would read UTF-32BE data from
337
- # the file but transcode it to UTF-8 before CSV parses it.
2055
+ # <!--
2056
+ # rdoc-file=lib/csv.rb
2057
+ # - read(source, **options) -> array_of_arrays
2058
+ # - read(source, headers: true, **options) -> csv_table
2059
+ # -->
2060
+ # Opens the given `source` with the given `options` (see CSV.open), reads the
2061
+ # source (see CSV#read), and returns the result, which will be either an Array
2062
+ # of Arrays or a CSV::Table.
2063
+ #
2064
+ # Without headers:
2065
+ # string = "foo,0\nbar,1\nbaz,2\n"
2066
+ # path = 't.csv'
2067
+ # File.write(path, string)
2068
+ # CSV.read(path) # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
2069
+ #
2070
+ # With headers:
2071
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2072
+ # path = 't.csv'
2073
+ # File.write(path, string)
2074
+ # CSV.read(path, headers: true) # => #<CSV::Table mode:col_or_row row_count:4>
338
2075
  #
339
2076
  def self.read: (String path, ?::Hash[Symbol, untyped] options) -> ::Array[::Array[String?]]
340
2077
 
341
- # The primary write method for wrapped Strings and IOs, `row` (an Array or
342
- # CSV::Row) is converted to CSV and appended to the data source. When a CSV::Row
343
- # is passed, only the row's fields() are appended to the output.
2078
+ # <!--
2079
+ # rdoc-file=lib/csv.rb
2080
+ # - csv << row -> self
2081
+ # -->
2082
+ # Appends a row to `self`.
344
2083
  #
345
- # The data source must be open for writing.
2084
+ # * Argument `row` must be an Array object or a CSV::Row object.
2085
+ # * The output stream must be open for writing.
2086
+ #
2087
+ #
2088
+ # ---
2089
+ #
2090
+ # Append Arrays:
2091
+ # CSV.generate do |csv|
2092
+ # csv << ['foo', 0]
2093
+ # csv << ['bar', 1]
2094
+ # csv << ['baz', 2]
2095
+ # end # => "foo,0\nbar,1\nbaz,2\n"
2096
+ #
2097
+ # Append CSV::Rows:
2098
+ # headers = []
2099
+ # CSV.generate do |csv|
2100
+ # csv << CSV::Row.new(headers, ['foo', 0])
2101
+ # csv << CSV::Row.new(headers, ['bar', 1])
2102
+ # csv << CSV::Row.new(headers, ['baz', 2])
2103
+ # end # => "foo,0\nbar,1\nbaz,2\n"
2104
+ #
2105
+ # Headers in CSV::Row objects are not appended:
2106
+ # headers = ['Name', 'Count']
2107
+ # CSV.generate do |csv|
2108
+ # csv << CSV::Row.new(headers, ['foo', 0])
2109
+ # csv << CSV::Row.new(headers, ['bar', 1])
2110
+ # csv << CSV::Row.new(headers, ['baz', 2])
2111
+ # end # => "foo,0\nbar,1\nbaz,2\n"
2112
+ #
2113
+ # ---
2114
+ #
2115
+ # Raises an exception if `row` is not an Array or CSV::Row:
2116
+ # CSV.generate do |csv|
2117
+ # # Raises NoMethodError (undefined method `collect' for :foo:Symbol)
2118
+ # csv << :foo
2119
+ # end
2120
+ #
2121
+ # Raises an exception if the output stream is not opened for writing:
2122
+ # path = 't.csv'
2123
+ # File.write(path, '')
2124
+ # File.open(path) do |file|
2125
+ # CSV.open(file) do |csv|
2126
+ # # Raises IOError (not opened for writing)
2127
+ # csv << ['foo', 0]
2128
+ # end
2129
+ # end
346
2130
  #
347
2131
  def <<: (::Array[untyped] | CSV::Row row) -> void
348
2132
 
349
- # This method wraps a String you provide, or an empty default String, in a CSV
350
- # object which is passed to the provided block. You can use the block to append
351
- # CSV rows to the String and when the block exits, the final String will be
352
- # returned.
2133
+ # <!--
2134
+ # rdoc-file=lib/csv.rb
2135
+ # - generate(csv_string, **options) {|csv| ... }
2136
+ # - generate(**options) {|csv| ... }
2137
+ # -->
2138
+ # * Argument `csv_string`, if given, must be a String object; defaults to a
2139
+ # new empty String.
2140
+ # * Arguments `options`, if given, should be generating options. See [Options
2141
+ # for Generating](#class-CSV-label-Options+for+Generating).
2142
+ #
353
2143
  #
354
- # Note that a passed String **is** modified by this method. Call dup() before
355
- # passing if you need a new String.
2144
+ # ---
2145
+ #
2146
+ # Creates a new CSV object via `CSV.new(csv_string, **options)`; calls the block
2147
+ # with the CSV object, which the block may modify; returns the String generated
2148
+ # from the CSV object.
2149
+ #
2150
+ # Note that a passed String **is** modified by this method. Pass
2151
+ # `csv_string`.dup if the String must be preserved.
2152
+ #
2153
+ # This method has one additional option: `:encoding`, which sets the base
2154
+ # Encoding for the output if no no `str` is specified. CSV needs this hint if
2155
+ # you plan to output non-ASCII compatible data.
2156
+ #
2157
+ # ---
2158
+ #
2159
+ # Add lines:
2160
+ # input_string = "foo,0\nbar,1\nbaz,2\n"
2161
+ # output_string = CSV.generate(input_string) do |csv|
2162
+ # csv << ['bat', 3]
2163
+ # csv << ['bam', 4]
2164
+ # end
2165
+ # output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
2166
+ # input_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
2167
+ # output_string.equal?(input_string) # => true # Same string, modified
2168
+ #
2169
+ # Add lines into new string, preserving old string:
2170
+ # input_string = "foo,0\nbar,1\nbaz,2\n"
2171
+ # output_string = CSV.generate(input_string.dup) do |csv|
2172
+ # csv << ['bat', 3]
2173
+ # csv << ['bam', 4]
2174
+ # end
2175
+ # output_string # => "foo,0\nbar,1\nbaz,2\nbat,3\nbam,4\n"
2176
+ # input_string # => "foo,0\nbar,1\nbaz,2\n"
2177
+ # output_string.equal?(input_string) # => false # Different strings
2178
+ #
2179
+ # Create lines from nothing:
2180
+ # output_string = CSV.generate do |csv|
2181
+ # csv << ['foo', 0]
2182
+ # csv << ['bar', 1]
2183
+ # csv << ['baz', 2]
2184
+ # end
2185
+ # output_string # => "foo,0\nbar,1\nbaz,2\n"
2186
+ #
2187
+ # ---
356
2188
  #
357
- # The `options` parameter can be anything CSV::new() understands. This method
358
- # understands an additional `:encoding` parameter when not passed a String to
359
- # set the base Encoding for the output. CSV needs this hint if you plan to
360
- # output non-ASCII compatible data.
2189
+ # Raises an exception if `csv_string` is not a String object:
2190
+ # # Raises TypeError (no implicit conversion of Integer into String)
2191
+ # CSV.generate(0)
361
2192
  #
362
2193
  def self.generate: (?String str, **untyped options) { (CSV csv) -> void } -> String
363
2194
 
364
- # :call-seq:
365
- # csv.each -> enumerator
366
- # csv.each {|row| ...}
367
- #
368
- # Calls the block with each successive row.
369
- # The data source must be opened for reading.
2195
+ # <!--
2196
+ # rdoc-file=lib/csv.rb
2197
+ # - csv.each -> enumerator
2198
+ # - csv.each {|row| ...}
2199
+ # -->
2200
+ # Calls the block with each successive row. The data source must be opened for
2201
+ # reading.
370
2202
  #
371
2203
  # Without headers:
372
- # string = "foo,0\nbar,1\nbaz,2\n"
373
- # csv = CSV.new(string)
374
- # csv.each do |row|
375
- # p row
376
- # end
2204
+ # string = "foo,0\nbar,1\nbaz,2\n"
2205
+ # csv = CSV.new(string)
2206
+ # csv.each do |row|
2207
+ # p row
2208
+ # end
2209
+ #
377
2210
  # Output:
378
- # ["foo", "0"]
379
- # ["bar", "1"]
380
- # ["baz", "2"]
2211
+ # ["foo", "0"]
2212
+ # ["bar", "1"]
2213
+ # ["baz", "2"]
381
2214
  #
382
2215
  # With headers:
383
- # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
384
- # csv = CSV.new(string, headers: true)
385
- # csv.each do |row|
386
- # p row
387
- # end
2216
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2217
+ # csv = CSV.new(string, headers: true)
2218
+ # csv.each do |row|
2219
+ # p row
2220
+ # end
2221
+ #
388
2222
  # Output:
389
- # <CSV::Row "Name":"foo" "Value":"0">
390
- # <CSV::Row "Name":"bar" "Value":"1">
391
- # <CSV::Row "Name":"baz" "Value":"2">
2223
+ # <CSV::Row "Name":"foo" "Value":"0">
2224
+ # <CSV::Row "Name":"bar" "Value":"1">
2225
+ # <CSV::Row "Name":"baz" "Value":"2">
392
2226
  #
393
2227
  # ---
394
2228
  #
395
2229
  # Raises an exception if the source is not opened for reading:
396
- # string = "foo,0\nbar,1\nbaz,2\n"
397
- # csv = CSV.new(string)
398
- # csv.close
399
- # # Raises IOError (not opened for reading)
400
- # csv.each do |row|
401
- # p row
402
- # end
2230
+ # string = "foo,0\nbar,1\nbaz,2\n"
2231
+ # csv = CSV.new(string)
2232
+ # csv.close
2233
+ # # Raises IOError (not opened for reading)
2234
+ # csv.each do |row|
2235
+ # p row
2236
+ # end
2237
+ #
403
2238
  def each: () -> Enumerator[untyped, Integer]
404
2239
  | () { (untyped) -> void } -> Integer
405
-
406
2240
  end
407
2241
 
408
- # The options used when no overrides are given by calling code. They are:
409
- #
410
- # **`:col_sep`**
411
- # : `","`
412
- # **`:row_sep`**
413
- # : `:auto`
414
- # **`:quote_char`**
415
- # : `'"'`
416
- # **`:field_size_limit`**
417
- # : `nil`
418
- # **`:converters`**
419
- # : `nil`
420
- # **`:unconverted_fields`**
421
- # : `nil`
422
- # **`:headers`**
423
- # : `false`
424
- # **`:return_headers`**
425
- # : `false`
426
- # **`:header_converters`**
427
- # : `nil`
428
- # **`:skip_blanks`**
429
- # : `false`
430
- # **`:force_quotes`**
431
- # : `false`
432
- # **`:skip_lines`**
433
- # : `nil`
434
- # **`:liberal_parsing`**
435
- # : `false`
436
- # **`:quote_empty`**
437
- # : `true`
438
- #
2242
+ # <!-- rdoc-file=lib/csv.rb -->
2243
+ # Default values for method options.
439
2244
  #
440
2245
  CSV::DEFAULT_OPTIONS: ::Hash[untyped, untyped]
441
2246
 
2247
+ # <!-- rdoc-file=lib/csv/version.rb -->
442
2248
  # The version of the installed library.
443
2249
  #
444
2250
  CSV::VERSION: String
445
2251
 
2252
+ # <!-- rdoc-file=lib/csv/row.rb -->
446
2253
  # A CSV::Row is part Array and part Hash. It retains an order for the fields and
447
2254
  # allows duplicates just as an Array would, but also allows you to access fields
448
2255
  # by name just as you could if they were in a Hash.
@@ -454,52 +2261,189 @@ class CSV::Row < Object
454
2261
  include Enumerable[Array[String]]
455
2262
  extend Forwardable
456
2263
 
457
- # If a two-element Array is provided, it is assumed to be a header and field and
458
- # the pair is appended. A Hash works the same way with the key being the header
459
- # and the value being the field. Anything else is assumed to be a lone field
460
- # which is appended with a `nil` header.
461
- #
462
- # This method returns the row for chaining.
2264
+ # <!--
2265
+ # rdoc-file=lib/csv/row.rb
2266
+ # - row << [header, value] -> self
2267
+ # - row << hash -> self
2268
+ # - row << value -> self
2269
+ # -->
2270
+ # Adds a field to `self`; returns `self`:
2271
+ #
2272
+ # If the argument is a 2-element Array `[header, value]`, a field is added with
2273
+ # the given `header` and `value`:
2274
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2275
+ # table = CSV.parse(source, headers: true)
2276
+ # row = table[0]
2277
+ # row << ['NAME', 'Bat']
2278
+ # row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":"Baz" "NAME":"Bat">
2279
+ #
2280
+ # If the argument is a Hash, each `key-value` pair is added as a field with
2281
+ # header `key` and value `value`.
2282
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2283
+ # table = CSV.parse(source, headers: true)
2284
+ # row = table[0]
2285
+ # row << {NAME: 'Bat', name: 'Bam'}
2286
+ # row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":"Baz" NAME:"Bat" name:"Bam">
2287
+ #
2288
+ # Otherwise, the given `value` is added as a field with no header.
2289
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2290
+ # table = CSV.parse(source, headers: true)
2291
+ # row = table[0]
2292
+ # row << 'Bag'
2293
+ # row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":"Baz" nil:"Bag">
463
2294
  #
464
2295
  def <<: (untyped arg) -> untyped
465
2296
 
2297
+ # <!--
2298
+ # rdoc-file=lib/csv/row.rb
2299
+ # - ==(other)
2300
+ # -->
466
2301
  # Returns `true` if this row contains the same headers and fields in the same
467
2302
  # order as `other`.
468
2303
  #
469
2304
  def ==: (untyped other) -> bool
470
2305
 
2306
+ # <!--
2307
+ # rdoc-file=lib/csv/row.rb
2308
+ # - [](header_or_index, minimum_index = 0)
2309
+ # -->
2310
+ #
471
2311
  alias [] field
472
2312
 
473
- # Looks up the field by the semantics described in CSV::Row.field() and assigns
474
- # the `value`.
2313
+ # <!--
2314
+ # rdoc-file=lib/csv/row.rb
2315
+ # - row[index] = value -> value
2316
+ # - row[header, offset] = value -> value
2317
+ # - row[header] = value -> value
2318
+ # -->
2319
+ # Assigns the field value for the given `index` or `header`; returns `value`.
2320
+ #
2321
+ # ---
2322
+ #
2323
+ # Assign field value by Integer index:
2324
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2325
+ # table = CSV.parse(source, headers: true)
2326
+ # row = table[0]
2327
+ # row[0] = 'Bat'
2328
+ # row[1] = 3
2329
+ # row # => #<CSV::Row "Name":"Bat" "Value":3>
2330
+ #
2331
+ # Counts backward from the last column if `index` is negative:
2332
+ # row[-1] = 4
2333
+ # row[-2] = 'Bam'
2334
+ # row # => #<CSV::Row "Name":"Bam" "Value":4>
2335
+ #
2336
+ # Extends the row with `nil:nil` if positive `index` is not in the row:
2337
+ # row[4] = 5
2338
+ # row # => #<CSV::Row "Name":"bad" "Value":4 nil:nil nil:nil nil:5>
2339
+ #
2340
+ # Raises IndexError if negative `index` is too small (too far from zero).
475
2341
  #
476
- # Assigning past the end of the row with an index will set all pairs between to
477
- # `[nil, nil]`. Assigning to an unused header appends the new pair.
2342
+ # ---
2343
+ #
2344
+ # Assign field value by header (first found):
2345
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2346
+ # table = CSV.parse(source, headers: true)
2347
+ # row = table[0]
2348
+ # row['Name'] = 'Bat'
2349
+ # row # => #<CSV::Row "Name":"Bat" "Name":"Bar" "Name":"Baz">
2350
+ #
2351
+ # Assign field value by header, ignoring `offset` leading fields:
2352
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2353
+ # table = CSV.parse(source, headers: true)
2354
+ # row = table[0]
2355
+ # row['Name', 2] = 4
2356
+ # row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":4>
2357
+ #
2358
+ # Append new field by (new) header:
2359
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2360
+ # table = CSV.parse(source, headers: true)
2361
+ # row = table[0]
2362
+ # row['New'] = 6
2363
+ # row# => #<CSV::Row "Name":"foo" "Value":"0" "New":6>
478
2364
  #
479
2365
  def []=: (*untyped args) -> untyped
480
2366
 
481
- # Removes a pair from the row by `header` or `index`. The pair is located as
482
- # described in CSV::Row.field(). The deleted pair is returned, or `nil` if a
483
- # pair could not be found.
2367
+ # <!--
2368
+ # rdoc-file=lib/csv/row.rb
2369
+ # - delete(index) -> [header, value] or nil
2370
+ # - delete(header) -> [header, value] or empty_array
2371
+ # - delete(header, offset) -> [header, value] or empty_array
2372
+ # -->
2373
+ # Removes a specified field from `self`; returns the 2-element Array `[header,
2374
+ # value]` if the field exists.
2375
+ #
2376
+ # If an Integer argument `index` is given, removes and returns the field at
2377
+ # offset `index`, or returns `nil` if the field does not exist:
2378
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2379
+ # table = CSV.parse(source, headers: true)
2380
+ # row = table[0]
2381
+ # row.delete(1) # => ["Name", "Bar"]
2382
+ # row.delete(50) # => nil
2383
+ #
2384
+ # Otherwise, if the single argument `header` is given, removes and returns the
2385
+ # first-found field with the given header, of returns a new empty Array if the
2386
+ # field does not exist:
2387
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2388
+ # table = CSV.parse(source, headers: true)
2389
+ # row = table[0]
2390
+ # row.delete('Name') # => ["Name", "Foo"]
2391
+ # row.delete('NAME') # => []
2392
+ #
2393
+ # If argument `header` and Integer argument `offset` are given, removes and
2394
+ # returns the first-found field with the given header whose `index` is at least
2395
+ # as large as `offset`:
2396
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2397
+ # table = CSV.parse(source, headers: true)
2398
+ # row = table[0]
2399
+ # row.delete('Name', 1) # => ["Name", "Bar"]
2400
+ # row.delete('NAME', 1) # => []
484
2401
  #
485
2402
  def delete: (untyped header_or_index, ?untyped minimum_index) -> untyped
486
2403
 
487
- # The provided `block` is passed a header and field for each pair in the row and
488
- # expected to return `true` or `false`, depending on whether the pair should be
489
- # deleted.
2404
+ # <!--
2405
+ # rdoc-file=lib/csv/row.rb
2406
+ # - row.delete_if {|header, value| ... } -> self
2407
+ # -->
2408
+ # Removes fields from `self` as selected by the block; returns `self`.
490
2409
  #
491
- # This method returns the row for chaining.
2410
+ # Removes each field for which the block returns a truthy value:
2411
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2412
+ # table = CSV.parse(source, headers: true)
2413
+ # row = table[0]
2414
+ # row.delete_if {|header, value| value.start_with?('B') } # => true
2415
+ # row # => #<CSV::Row "Name":"Foo">
2416
+ # row.delete_if {|header, value| header.start_with?('B') } # => false
492
2417
  #
493
- # If no block is given, an Enumerator is returned.
2418
+ # If no block is given, returns a new Enumerator:
2419
+ # row.delete_if # => #<Enumerator: #<CSV::Row "Name":"Foo">:delete_if>
494
2420
  #
495
2421
  def delete_if: () { (*untyped) -> untyped } -> untyped
496
2422
 
497
- # Extracts the nested value specified by the sequence of `index` or `header`
498
- # objects by calling dig at each step, returning nil if any intermediate step is
499
- # nil.
2423
+ # <!--
2424
+ # rdoc-file=lib/csv/row.rb
2425
+ # - row.dig(index_or_header, *identifiers) -> object
2426
+ # -->
2427
+ # Finds and returns the object in nested object that is specified by
2428
+ # `index_or_header` and `specifiers`.
2429
+ #
2430
+ # The nested objects may be instances of various classes. See [Dig
2431
+ # Methods](https://docs.ruby-lang.org/en/master/doc/dig_methods_rdoc.html).
2432
+ #
2433
+ # Examples:
2434
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2435
+ # table = CSV.parse(source, headers: true)
2436
+ # row = table[0]
2437
+ # row.dig(1) # => "0"
2438
+ # row.dig('Value') # => "0"
2439
+ # row.dig(5) # => nil
500
2440
  #
501
2441
  def dig: (untyped index_or_header, *untyped indexes) -> untyped
502
2442
 
2443
+ # <!--
2444
+ # rdoc-file=lib/csv/row.rb
2445
+ # - each(&block)
2446
+ # -->
503
2447
  # Yields each pair of the row as header and field tuples (much like iterating
504
2448
  # over a Hash). This method returns the row for chaining.
505
2449
  #
@@ -510,112 +2454,326 @@ class CSV::Row < Object
510
2454
  def each: () -> Enumerator[Array[String], self]
511
2455
  | () { (Array[String]) -> void } -> self
512
2456
 
2457
+ # <!--
2458
+ # rdoc-file=lib/csv/row.rb
2459
+ # - each_pair(&block)
2460
+ # -->
2461
+ #
513
2462
  alias each_pair each
514
2463
 
515
2464
  def empty?: (*untyped args) { (*untyped) -> untyped } -> bool
516
2465
 
517
- # This method will fetch the field value by `header`. It has the same behavior
518
- # as Hash#fetch: if there is a field with the given `header`, its value is
519
- # returned. Otherwise, if a block is given, it is yielded the `header` and its
520
- # result is returned; if a `default` is given as the second argument, it is
521
- # returned; otherwise a KeyError is raised.
2466
+ # <!--
2467
+ # rdoc-file=lib/csv/row.rb
2468
+ # - fetch(header)
2469
+ # - fetch(header, default)
2470
+ # - fetch(header) {|row| ... }
2471
+ # -->
2472
+ # Returns the field value as specified by `header`.
2473
+ #
2474
+ # ---
2475
+ #
2476
+ # With the single argument `header`, returns the field value for that header
2477
+ # (first found):
2478
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2479
+ # table = CSV.parse(source, headers: true)
2480
+ # row = table[0]
2481
+ # row.fetch('Name') # => "Foo"
2482
+ #
2483
+ # Raises exception `KeyError` if the header does not exist.
2484
+ #
2485
+ # ---
2486
+ #
2487
+ # With arguments `header` and `default` given, returns the field value for the
2488
+ # header (first found) if the header exists, otherwise returns `default`:
2489
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2490
+ # table = CSV.parse(source, headers: true)
2491
+ # row = table[0]
2492
+ # row.fetch('Name', '') # => "Foo"
2493
+ # row.fetch(:nosuch, '') # => ""
2494
+ #
2495
+ # ---
2496
+ #
2497
+ # With argument `header` and a block given, returns the field value for the
2498
+ # header (first found) if the header exists; otherwise calls the block and
2499
+ # returns its return value:
2500
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2501
+ # table = CSV.parse(source, headers: true)
2502
+ # row = table[0]
2503
+ # row.fetch('Name') {|header| fail 'Cannot happen' } # => "Foo"
2504
+ # row.fetch(:nosuch) {|header| "Header '#{header} not found'" } # => "Header 'nosuch not found'"
522
2505
  #
523
2506
  def fetch: (untyped header, *untyped varargs) ?{ (*untyped) -> untyped } -> untyped
524
2507
 
525
- # This method will return the field value by `header` or `index`. If a field is
526
- # not found, `nil` is returned.
2508
+ # <!--
2509
+ # rdoc-file=lib/csv/row.rb
2510
+ # - field(index)
2511
+ # - field(header)
2512
+ # - field(header, offset)
2513
+ # -->
2514
+ # Returns the field value for the given `index` or `header`.
2515
+ #
2516
+ # ---
2517
+ #
2518
+ # Fetch field value by Integer index:
2519
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2520
+ # table = CSV.parse(source, headers: true)
2521
+ # row = table[0]
2522
+ # row.field(0) # => "foo"
2523
+ # row.field(1) # => "bar"
2524
+ #
2525
+ # Counts backward from the last column if `index` is negative:
2526
+ # row.field(-1) # => "0"
2527
+ # row.field(-2) # => "foo"
2528
+ #
2529
+ # Returns `nil` if `index` is out of range:
2530
+ # row.field(2) # => nil
2531
+ # row.field(-3) # => nil
527
2532
  #
528
- # When provided, `offset` ensures that a header match occurs on or later than
529
- # the `offset` index. You can use this to find duplicate headers, without
530
- # resorting to hard-coding exact indices.
2533
+ # ---
2534
+ #
2535
+ # Fetch field value by header (first found):
2536
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2537
+ # table = CSV.parse(source, headers: true)
2538
+ # row = table[0]
2539
+ # row.field('Name') # => "Foo"
2540
+ #
2541
+ # Fetch field value by header, ignoring `offset` leading fields:
2542
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2543
+ # table = CSV.parse(source, headers: true)
2544
+ # row = table[0]
2545
+ # row.field('Name', 2) # => "Baz"
2546
+ #
2547
+ # Returns `nil` if the header does not exist.
531
2548
  #
532
2549
  def field: (untyped header_or_index, ?untyped minimum_index) -> untyped
533
2550
 
2551
+ # <!--
2552
+ # rdoc-file=lib/csv/row.rb
2553
+ # - field?(data)
2554
+ # -->
534
2555
  # Returns `true` if `data` matches a field in this row, and `false` otherwise.
535
2556
  #
536
2557
  def field?: (untyped data) -> bool
537
2558
 
538
- # Returns `true` if this is a field row.
2559
+ # <!--
2560
+ # rdoc-file=lib/csv/row.rb
2561
+ # - row.field_row? -> true or false
2562
+ # -->
2563
+ # Returns `true` if this is a field row, `false` otherwise.
539
2564
  #
540
2565
  def field_row?: () -> bool
541
2566
 
542
- # This method accepts any number of arguments which can be headers, indices,
543
- # Ranges of either, or two-element Arrays containing a header and offset. Each
544
- # argument will be replaced with a field lookup as described in
545
- # CSV::Row.field().
2567
+ # <!--
2568
+ # rdoc-file=lib/csv/row.rb
2569
+ # - self.fields(*specifiers)
2570
+ # -->
2571
+ # Returns field values per the given `specifiers`, which may be any mixture of:
2572
+ # * Integer index.
2573
+ # * Range of Integer indexes.
2574
+ # * 2-element Array containing a header and offset.
2575
+ # * Header.
2576
+ # * Range of headers.
2577
+ #
2578
+ #
2579
+ # For `specifier` in one of the first four cases above, returns the result of
2580
+ # `self.field(specifier)`; see #field.
2581
+ #
2582
+ # Although there may be any number of `specifiers`, the examples here will
2583
+ # illustrate one at a time.
546
2584
  #
547
- # If called with no arguments, all fields are returned.
2585
+ # When the specifier is an Integer `index`, returns `self.field(index)`L
2586
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2587
+ # table = CSV.parse(source, headers: true)
2588
+ # row = table[0]
2589
+ # row.fields(1) # => ["Bar"]
2590
+ #
2591
+ # When the specifier is a Range of Integers `range`, returns
2592
+ # `self.field(range)`:
2593
+ # row.fields(1..2) # => ["Bar", "Baz"]
2594
+ #
2595
+ # When the specifier is a 2-element Array `array`, returns `self.field(array)`L
2596
+ # row.fields('Name', 1) # => ["Foo", "Bar"]
2597
+ #
2598
+ # When the specifier is a header `header`, returns `self.field(header)`L
2599
+ # row.fields('Name') # => ["Foo"]
2600
+ #
2601
+ # When the specifier is a Range of headers `range`, forms a new Range
2602
+ # `new_range` from the indexes of `range.start` and `range.end`, and returns
2603
+ # `self.field(new_range)`:
2604
+ # source = "Name,NAME,name\nFoo,Bar,Baz\n"
2605
+ # table = CSV.parse(source, headers: true)
2606
+ # row = table[0]
2607
+ # row.fields('Name'..'NAME') # => ["Foo", "Bar"]
2608
+ #
2609
+ # Returns all fields if no argument given:
2610
+ # row.fields # => ["Foo", "Bar", "Baz"]
548
2611
  #
549
2612
  def fields: (*untyped headers_and_or_indices) -> untyped
550
2613
 
551
- # Returns `true` if there is a field with the given `header`.
2614
+ # <!--
2615
+ # rdoc-file=lib/csv/row.rb
2616
+ # - row.has_key?(header)
2617
+ # -->
2618
+ # Returns `true` if there is a field with the given `header`, `false` otherwise.
552
2619
  #
553
2620
  def has_key?: (untyped header) -> bool
554
2621
 
2622
+ # <!--
2623
+ # rdoc-file=lib/csv/row.rb
2624
+ # - header?(header)
2625
+ # -->
2626
+ #
555
2627
  alias header? has_key?
556
2628
 
557
- # Returns `true` if this is a header row.
2629
+ # <!--
2630
+ # rdoc-file=lib/csv/row.rb
2631
+ # - row.header_row? -> true or false
2632
+ # -->
2633
+ # Returns `true` if this is a header row, `false` otherwise.
558
2634
  #
559
2635
  def header_row?: () -> bool
560
2636
 
561
- # Returns the headers of this row.
2637
+ # <!--
2638
+ # rdoc-file=lib/csv/row.rb
2639
+ # - row.headers
2640
+ # -->
2641
+ # Returns the headers for this row:
2642
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2643
+ # table = CSV.parse(source, headers: true)
2644
+ # row = table.first
2645
+ # row.headers # => ["Name", "Value"]
562
2646
  #
563
2647
  def headers: () -> untyped
564
2648
 
2649
+ # <!--
2650
+ # rdoc-file=lib/csv/row.rb
2651
+ # - include?(header)
2652
+ # -->
2653
+ #
565
2654
  alias include? has_key?
566
2655
 
2656
+ # <!--
2657
+ # rdoc-file=lib/csv/row.rb
2658
+ # - index( header )
2659
+ # - index( header, offset )
2660
+ # -->
567
2661
  # This method will return the index of a field with the provided `header`. The
568
2662
  # `offset` can be used to locate duplicate header names, as described in
569
2663
  # CSV::Row.field().
570
2664
  #
571
2665
  def index: (untyped header, ?untyped minimum_index) -> untyped
572
2666
 
573
- # A summary of fields, by header, in an ASCII compatible String.
2667
+ # <!--
2668
+ # rdoc-file=lib/csv/row.rb
2669
+ # - row.inspect -> string
2670
+ # -->
2671
+ # Returns an ASCII-compatible String showing:
2672
+ # * Class CSV::Row.
2673
+ # * Header-value pairs.
2674
+ #
2675
+ # Example:
2676
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2677
+ # table = CSV.parse(source, headers: true)
2678
+ # row = table[0]
2679
+ # row.inspect # => "#<CSV::Row \"Name\":\"foo\" \"Value\":\"0\">"
574
2680
  #
575
2681
  def inspect: () -> String
576
2682
 
2683
+ # <!--
2684
+ # rdoc-file=lib/csv/row.rb
2685
+ # - key?(header)
2686
+ # -->
2687
+ #
577
2688
  alias key? has_key?
578
2689
 
579
2690
  def length: (*untyped args) { (*untyped) -> untyped } -> untyped
580
2691
 
2692
+ # <!--
2693
+ # rdoc-file=lib/csv/row.rb
2694
+ # - member?(header)
2695
+ # -->
2696
+ #
581
2697
  alias member? has_key?
582
2698
 
583
- # A shortcut for appending multiple fields. Equivalent to:
584
- #
585
- # args.each { |arg| csv_row << arg }
586
- #
587
- # This method returns the row for chaining.
2699
+ # <!--
2700
+ # rdoc-file=lib/csv/row.rb
2701
+ # - row.push(*values) ->self
2702
+ # -->
2703
+ # Appends each of the given `values` to `self` as a field; returns `self`:
2704
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2705
+ # table = CSV.parse(source, headers: true)
2706
+ # row = table[0]
2707
+ # row.push('Bat', 'Bam')
2708
+ # row # => #<CSV::Row "Name":"Foo" "Name":"Bar" "Name":"Baz" nil:"Bat" nil:"Bam">
588
2709
  #
589
2710
  def push: (*untyped args) -> untyped
590
2711
 
591
2712
  def size: (*untyped args) { (*untyped) -> untyped } -> untyped
592
2713
 
593
- # Returns the row as a CSV String. Headers are not used. Equivalent to:
594
- #
595
- # csv_row.fields.to_csv( options )
2714
+ # <!--
2715
+ # rdoc-file=lib/csv/row.rb
2716
+ # - row.to_csv -> csv_string
2717
+ # -->
2718
+ # Returns the row as a CSV String. Headers are not included:
2719
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2720
+ # table = CSV.parse(source, headers: true)
2721
+ # row = table[0]
2722
+ # row.to_csv # => "foo,0\n"
596
2723
  #
597
2724
  def to_csv: (**untyped) -> untyped
598
2725
 
599
- # Collapses the row into a simple Hash. Be warned that this discards field order
600
- # and clobbers duplicate fields.
2726
+ # <!--
2727
+ # rdoc-file=lib/csv/row.rb
2728
+ # - row.to_h -> hash
2729
+ # -->
2730
+ # Returns the new Hash formed by adding each header-value pair in `self` as a
2731
+ # key-value pair in the Hash.
2732
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2733
+ # table = CSV.parse(source, headers: true)
2734
+ # row = table[0]
2735
+ # row.to_h # => {"Name"=>"foo", "Value"=>"0"}
2736
+ #
2737
+ # Header order is preserved, but repeated headers are ignored:
2738
+ # source = "Name,Name,Name\nFoo,Bar,Baz\n"
2739
+ # table = CSV.parse(source, headers: true)
2740
+ # row = table[0]
2741
+ # row.to_h # => {"Name"=>"Foo"}
601
2742
  #
602
2743
  def to_h: () -> untyped
603
2744
 
2745
+ # <!--
2746
+ # rdoc-file=lib/csv/row.rb
2747
+ # - to_hash()
2748
+ # -->
2749
+ #
604
2750
  alias to_hash to_h
605
2751
 
2752
+ # <!--
2753
+ # rdoc-file=lib/csv/row.rb
2754
+ # - to_s(**options)
2755
+ # -->
2756
+ #
606
2757
  alias to_s to_csv
607
2758
 
2759
+ # <!--
2760
+ # rdoc-file=lib/csv/row.rb
2761
+ # - values_at(*headers_and_or_indices)
2762
+ # -->
2763
+ #
608
2764
  alias values_at fields
609
2765
  end
610
2766
 
611
2767
  class CSV::FieldInfo < Struct[untyped]
612
2768
  end
613
2769
 
2770
+ # <!-- rdoc-file=lib/csv.rb -->
614
2771
  # The error thrown when the parser encounters illegal CSV formatting.
615
2772
  #
616
2773
  class CSV::MalformedCSVError < RuntimeError
617
2774
  end
618
2775
 
2776
+ # <!-- rdoc-file=lib/csv/table.rb -->
619
2777
  # A CSV::Table is a two-dimensional data structure for representing CSV
620
2778
  # documents. Tables allow you to work with the data by row or column, manipulate
621
2779
  # the data, and even convert the results back to CSV, if needed.
@@ -627,6 +2785,10 @@ class CSV::Table[out Elem] < Object
627
2785
  include Enumerable[untyped]
628
2786
  extend Forwardable
629
2787
 
2788
+ # <!--
2789
+ # rdoc-file=lib/csv/table.rb
2790
+ # - new(array_of_rows, headers: nil)
2791
+ # -->
630
2792
  # Constructs a new CSV::Table from `array_of_rows`, which are expected to be
631
2793
  # CSV::Row objects. All rows are assumed to have the same headers.
632
2794
  #
@@ -642,27 +2804,142 @@ class CSV::Table[out Elem] < Object
642
2804
  #
643
2805
  def initialize: (untyped array_of_rows, ?headers: untyped) -> untyped
644
2806
 
645
- # Adds a new row to the bottom end of this table. You can provide an Array,
646
- # which will be converted to a CSV::Row (inheriting the table's headers()), or a
647
- # CSV::Row.
648
- #
649
- # This method returns the table for chaining.
2807
+ # <!--
2808
+ # rdoc-file=lib/csv/table.rb
2809
+ # - table << row_or_array -> self
2810
+ # -->
2811
+ # If `row_or_array` is a CSV::Row object, it is appended to the table:
2812
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2813
+ # table = CSV.parse(source, headers: true)
2814
+ # table << CSV::Row.new(table.headers, ['bat', 3])
2815
+ # table[3] # => #<CSV::Row "Name":"bat" "Value":3>
2816
+ #
2817
+ # If `row_or_array` is an Array, it is used to create a new CSV::Row object
2818
+ # which is then appended to the table:
2819
+ # table << ['bam', 4]
2820
+ # table[4] # => #<CSV::Row "Name":"bam" "Value":4>
650
2821
  #
651
2822
  def <<: (untyped row_or_array) -> untyped
652
2823
 
653
- # Returns `true` if all rows of this table ==() `other`'s rows.
2824
+ # <!--
2825
+ # rdoc-file=lib/csv/table.rb
2826
+ # - ==(other)
2827
+ # -->
2828
+ # Returns `true` if all each row of `self` `==` the corresponding row of
2829
+ # `other_table`, otherwise, `false`.
2830
+ #
2831
+ # The access mode does no affect the result.
2832
+ #
2833
+ # Equal tables:
2834
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2835
+ # table = CSV.parse(source, headers: true)
2836
+ # other_table = CSV.parse(source, headers: true)
2837
+ # table == other_table # => true
2838
+ #
2839
+ # Different row count:
2840
+ # other_table.delete(2)
2841
+ # table == other_table # => false
2842
+ #
2843
+ # Different last row:
2844
+ # other_table << ['bat', 3]
2845
+ # table == other_table # => false
654
2846
  #
655
2847
  def ==: (untyped other) -> bool
656
2848
 
657
- # In the default mixed mode, this method returns rows for index access and
658
- # columns for header access. You can force the index association by first
659
- # calling by_col!() or by_row!().
2849
+ # <!--
2850
+ # rdoc-file=lib/csv/table.rb
2851
+ # - table[n] -> row
2852
+ # - table[range] -> array_of_rows
2853
+ # - table[header] -> array_of_fields
2854
+ # -->
2855
+ # Returns data from the table; does not modify the table.
2856
+ #
2857
+ # ---
2858
+ #
2859
+ # The expression `table[n]`, where `n` is a non-negative Integer, returns the
2860
+ # +n+th row of the table, if that row exists, and if the access mode is `:row`
2861
+ # or `:col_or_row`:
2862
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2863
+ # table = CSV.parse(source, headers: true)
2864
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
2865
+ # table[1] # => #<CSV::Row "Name":"bar" "Value":"1">
2866
+ # table.by_col_or_row! # => #<CSV::Table mode:col_or_row row_count:4>
2867
+ # table[1] # => #<CSV::Row "Name":"bar" "Value":"1">
2868
+ #
2869
+ # Counts backward from the last row if `n` is negative:
2870
+ # table[-1] # => #<CSV::Row "Name":"baz" "Value":"2">
2871
+ #
2872
+ # Returns `nil` if `n` is too large or too small:
2873
+ # table[4] # => nil
2874
+ # table[-4] => nil
2875
+ #
2876
+ # Raises an exception if the access mode is `:row` and `n` is not an
2877
+ # [Integer-convertible
2878
+ # object](https://docs.ruby-lang.org/en/master/implicit_conversion_rdoc.html#lab
2879
+ # el-Integer-Convertible+Objects).
2880
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
2881
+ # # Raises TypeError (no implicit conversion of String into Integer):
2882
+ # table['Name']
2883
+ #
2884
+ # ---
2885
+ #
2886
+ # The expression `table[range]`, where `range` is a Range object, returns rows
2887
+ # from the table, beginning at row `range.first`, if those rows exist, and if
2888
+ # the access mode is `:row` or `:col_or_row`:
2889
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2890
+ # table = CSV.parse(source, headers: true)
2891
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
2892
+ # rows = table[1..2] # => #<CSV::Row "Name":"bar" "Value":"1">
2893
+ # rows # => [#<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]
2894
+ # table.by_col_or_row! # => #<CSV::Table mode:col_or_row row_count:4>
2895
+ # rows = table[1..2] # => #<CSV::Row "Name":"bar" "Value":"1">
2896
+ # rows # => [#<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]
2897
+ #
2898
+ # If there are too few rows, returns all from `range.first` to the end:
2899
+ # rows = table[1..50] # => #<CSV::Row "Name":"bar" "Value":"1">
2900
+ # rows # => [#<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]
2901
+ #
2902
+ # Special case: if `range.start == table.size`, returns an empty Array:
2903
+ # table[table.size..50] # => []
2904
+ #
2905
+ # If `range.end` is negative, calculates the ending index from the end:
2906
+ # rows = table[0..-1]
2907
+ # rows # => [#<CSV::Row "Name":"foo" "Value":"0">, #<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]
660
2908
  #
661
- # Columns are returned as an Array of values. Altering that Array has no effect
662
- # on the table.
2909
+ # If `range.start` is negative, calculates the starting index from the end:
2910
+ # rows = table[-1..2]
2911
+ # rows # => [#<CSV::Row "Name":"baz" "Value":"2">]
2912
+ #
2913
+ # If `range.start` is larger than `table.size`, returns `nil`:
2914
+ # table[4..4] # => nil
2915
+ #
2916
+ # ---
2917
+ #
2918
+ # The expression `table[header]`, where `header` is a String, returns column
2919
+ # values (Array of Strings) if the column exists and if the access mode is
2920
+ # `:col` or `:col_or_row`:
2921
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2922
+ # table = CSV.parse(source, headers: true)
2923
+ # table.by_col! # => #<CSV::Table mode:col row_count:4>
2924
+ # table['Name'] # => ["foo", "bar", "baz"]
2925
+ # table.by_col_or_row! # => #<CSV::Table mode:col_or_row row_count:4>
2926
+ # col = table['Name']
2927
+ # col # => ["foo", "bar", "baz"]
2928
+ #
2929
+ # Modifying the returned column values does not modify the table:
2930
+ # col[0] = 'bat'
2931
+ # col # => ["bat", "bar", "baz"]
2932
+ # table['Name'] # => ["foo", "bar", "baz"]
2933
+ #
2934
+ # Returns an Array of `nil` values if there is no such column:
2935
+ # table['Nosuch'] # => [nil, nil, nil]
663
2936
  #
664
2937
  def []: (untyped index_or_header) -> untyped
665
2938
 
2939
+ # <!--
2940
+ # rdoc-file=lib/csv/table.rb
2941
+ # - []=(index_or_header, value)
2942
+ # -->
666
2943
  # In the default mixed mode, this method assigns rows for index access and
667
2944
  # columns for header access. You can force the index association by first
668
2945
  # calling by_col!() or by_row!().
@@ -680,6 +2957,10 @@ class CSV::Table[out Elem] < Object
680
2957
  #
681
2958
  def []=: (untyped index_or_header, untyped value) -> untyped
682
2959
 
2960
+ # <!--
2961
+ # rdoc-file=lib/csv/table.rb
2962
+ # - by_col()
2963
+ # -->
683
2964
  # Returns a duplicate table object, in column mode. This is handy for chaining
684
2965
  # in a single call without changing the table mode, but be aware that this
685
2966
  # method can consume a fair amount of memory for bigger data sets.
@@ -689,6 +2970,10 @@ class CSV::Table[out Elem] < Object
689
2970
  #
690
2971
  def by_col: () -> untyped
691
2972
 
2973
+ # <!--
2974
+ # rdoc-file=lib/csv/table.rb
2975
+ # - by_col!()
2976
+ # -->
692
2977
  # Switches the mode of this table to column mode. All calls to indexing and
693
2978
  # iteration methods will work with columns until the mode is changed again.
694
2979
  #
@@ -696,6 +2981,10 @@ class CSV::Table[out Elem] < Object
696
2981
  #
697
2982
  def by_col!: () -> untyped
698
2983
 
2984
+ # <!--
2985
+ # rdoc-file=lib/csv/table.rb
2986
+ # - by_col_or_row()
2987
+ # -->
699
2988
  # Returns a duplicate table object, in mixed mode. This is handy for chaining in
700
2989
  # a single call without changing the table mode, but be aware that this method
701
2990
  # can consume a fair amount of memory for bigger data sets.
@@ -705,6 +2994,10 @@ class CSV::Table[out Elem] < Object
705
2994
  #
706
2995
  def by_col_or_row: () -> untyped
707
2996
 
2997
+ # <!--
2998
+ # rdoc-file=lib/csv/table.rb
2999
+ # - by_col_or_row!()
3000
+ # -->
708
3001
  # Switches the mode of this table to mixed mode. All calls to indexing and
709
3002
  # iteration methods will use the default intelligent indexing system until the
710
3003
  # mode is changed again. In mixed mode an index is assumed to be a row reference
@@ -714,6 +3007,10 @@ class CSV::Table[out Elem] < Object
714
3007
  #
715
3008
  def by_col_or_row!: () -> untyped
716
3009
 
3010
+ # <!--
3011
+ # rdoc-file=lib/csv/table.rb
3012
+ # - by_row()
3013
+ # -->
717
3014
  # Returns a duplicate table object, in row mode. This is handy for chaining in
718
3015
  # a single call without changing the table mode, but be aware that this method
719
3016
  # can consume a fair amount of memory for bigger data sets.
@@ -723,6 +3020,10 @@ class CSV::Table[out Elem] < Object
723
3020
  #
724
3021
  def by_row: () -> untyped
725
3022
 
3023
+ # <!--
3024
+ # rdoc-file=lib/csv/table.rb
3025
+ # - by_row!()
3026
+ # -->
726
3027
  # Switches the mode of this table to row mode. All calls to indexing and
727
3028
  # iteration methods will work with rows until the mode is changed again.
728
3029
  #
@@ -730,36 +3031,121 @@ class CSV::Table[out Elem] < Object
730
3031
  #
731
3032
  def by_row!: () -> untyped
732
3033
 
733
- # Removes and returns the indicated columns or rows. In the default mixed mode
734
- # indices refer to rows and everything else is assumed to be a column headers.
735
- # Use by_col!() or by_row!() to force the lookup.
3034
+ # <!--
3035
+ # rdoc-file=lib/csv/table.rb
3036
+ # - table.delete(*indexes) -> deleted_values
3037
+ # - table.delete(*headers) -> deleted_values
3038
+ # -->
3039
+ # If the access mode is `:row` or `:col_or_row`, and each argument is either an
3040
+ # Integer or a Range, returns deleted rows. Otherwise, returns deleted columns
3041
+ # data.
736
3042
  #
737
- def delete: (*untyped indexes_or_headers) -> untyped
738
-
739
- # Removes any column or row for which the block returns `true`. In the default
740
- # mixed mode or row mode, iteration is the standard row major walking of rows.
741
- # In column mode, iteration will `yield` two element tuples containing the
742
- # column name and an Array of values for that column.
3043
+ # In either case, the returned values are in the order specified by the
3044
+ # arguments. Arguments may be repeated.
743
3045
  #
744
- # This method returns the table for chaining.
3046
+ # ---
745
3047
  #
746
- # If no block is given, an Enumerator is returned.
3048
+ # Returns rows as an Array of CSV::Row objects.
3049
+ #
3050
+ # One index:
3051
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
3052
+ # table = CSV.parse(source, headers: true)
3053
+ # deleted_values = table.delete(0)
3054
+ # deleted_values # => [#<CSV::Row "Name":"foo" "Value":"0">]
3055
+ #
3056
+ # Two indexes:
3057
+ # table = CSV.parse(source, headers: true)
3058
+ # deleted_values = table.delete(2, 0)
3059
+ # deleted_values # => [#<CSV::Row "Name":"baz" "Value":"2">, #<CSV::Row "Name":"foo" "Value":"0">]
3060
+ #
3061
+ # ---
3062
+ #
3063
+ # Returns columns data as column Arrays.
3064
+ #
3065
+ # One header:
3066
+ # table = CSV.parse(source, headers: true)
3067
+ # deleted_values = table.delete('Name')
3068
+ # deleted_values # => ["foo", "bar", "baz"]
3069
+ #
3070
+ # Two headers:
3071
+ # table = CSV.parse(source, headers: true)
3072
+ # deleted_values = table.delete('Value', 'Name')
3073
+ # deleted_values # => [["0", "1", "2"], ["foo", "bar", "baz"]]
3074
+ #
3075
+ def delete: (*untyped indexes_or_headers) -> untyped
3076
+
3077
+ # <!--
3078
+ # rdoc-file=lib/csv/table.rb
3079
+ # - delete_if() { |header, self| ... }
3080
+ # -->
3081
+ # Removes rows or columns for which the block returns a truthy value; returns
3082
+ # `self`.
3083
+ #
3084
+ # Removes rows when the access mode is `:row` or `:col_or_row`; calls the block
3085
+ # with each CSV::Row object:
3086
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
3087
+ # table = CSV.parse(source, headers: true)
3088
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
3089
+ # table.size # => 3
3090
+ # table.delete_if {|row| row['Name'].start_with?('b') }
3091
+ # table.size # => 1
3092
+ #
3093
+ # Removes columns when the access mode is `:col`; calls the block with each
3094
+ # column as a 2-element array containing the header and an Array of column
3095
+ # fields:
3096
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
3097
+ # table = CSV.parse(source, headers: true)
3098
+ # table.by_col! # => #<CSV::Table mode:col row_count:4>
3099
+ # table.headers.size # => 2
3100
+ # table.delete_if {|column_data| column_data[1].include?('2') }
3101
+ # table.headers.size # => 1
3102
+ #
3103
+ # Returns a new Enumerator if no block is given:
3104
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
3105
+ # table = CSV.parse(source, headers: true)
3106
+ # table.delete_if # => #<Enumerator: #<CSV::Table mode:col_or_row row_count:4>:delete_if>
747
3107
  #
748
3108
  def delete_if: () { (*untyped) -> untyped } -> untyped
749
3109
 
3110
+ # <!--
3111
+ # rdoc-file=lib/csv/table.rb
3112
+ # - dig(index_or_header, *index_or_headers)
3113
+ # -->
750
3114
  # Extracts the nested value specified by the sequence of `index` or `header`
751
3115
  # objects by calling dig at each step, returning nil if any intermediate step is
752
3116
  # nil.
753
3117
  #
754
3118
  def dig: (untyped index_or_header, *untyped index_or_headers) -> untyped
755
3119
 
756
- # In the default mixed mode or row mode, iteration is the standard row major
757
- # walking of rows. In column mode, iteration will `yield` two element tuples
758
- # containing the column name and an Array of values for that column.
3120
+ # <!--
3121
+ # rdoc-file=lib/csv/table.rb
3122
+ # - each() { |header, self| ... }
3123
+ # -->
3124
+ # Calls the block with each row or column; returns `self`.
759
3125
  #
760
- # This method returns the table for chaining.
3126
+ # When the access mode is `:row` or `:col_or_row`, calls the block with each
3127
+ # CSV::Row object:
3128
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
3129
+ # table = CSV.parse(source, headers: true)
3130
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
3131
+ # table.each {|row| p row }
761
3132
  #
762
- # If no block is given, an Enumerator is returned.
3133
+ # Output:
3134
+ # #<CSV::Row "Name":"foo" "Value":"0">
3135
+ # #<CSV::Row "Name":"bar" "Value":"1">
3136
+ # #<CSV::Row "Name":"baz" "Value":"2">
3137
+ #
3138
+ # When the access mode is `:col`, calls the block with each column as a
3139
+ # 2-element array containing the header and an Array of column fields:
3140
+ # table.by_col! # => #<CSV::Table mode:col row_count:4>
3141
+ # table.each {|column_data| p column_data }
3142
+ #
3143
+ # Output:
3144
+ # ["Name", ["foo", "bar", "baz"]]
3145
+ # ["Value", ["0", "1", "2"]]
3146
+ #
3147
+ # Returns a new Enumerator if no block is given:
3148
+ # table.each # => #<Enumerator: #<CSV::Table mode:col row_count:4>:each>
763
3149
  #
764
3150
  def each: () -> Enumerator[untyped, self]
765
3151
  | () { (untyped) -> void } -> self
@@ -767,37 +3153,65 @@ class CSV::Table[out Elem] < Object
767
3153
 
768
3154
  def empty?: (*untyped args) { (*untyped) -> untyped } -> untyped
769
3155
 
3156
+ # <!--
3157
+ # rdoc-file=lib/csv/table.rb
3158
+ # - headers()
3159
+ # -->
770
3160
  # Returns the headers for the first row of this table (assumed to match all
771
3161
  # other rows). The headers Array passed to CSV::Table.new is returned for empty
772
3162
  # tables.
773
3163
  #
774
3164
  def headers: () -> untyped
775
3165
 
3166
+ # <!--
3167
+ # rdoc-file=lib/csv/table.rb
3168
+ # - inspect()
3169
+ # -->
776
3170
  # Shows the mode and size of this table in a US-ASCII String.
777
3171
  #
778
3172
  def inspect: () -> String
779
3173
 
780
3174
  def length: (*untyped args) { (*untyped) -> untyped } -> untyped
781
3175
 
3176
+ # <!-- rdoc-file=lib/csv/table.rb -->
782
3177
  # The current access mode for indexing and iteration.
783
3178
  #
784
3179
  def mode: () -> untyped
785
3180
 
3181
+ # <!--
3182
+ # rdoc-file=lib/csv/table.rb
3183
+ # - table.push(*rows_or_arrays) -> self
3184
+ # -->
786
3185
  # A shortcut for appending multiple rows. Equivalent to:
787
- #
788
- # rows.each { |row| self << row }
789
- #
790
- # This method returns the table for chaining.
3186
+ # rows.each {|row| self << row }
3187
+ #
3188
+ # Each argument may be either a CSV::Row object or an Array:
3189
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
3190
+ # table = CSV.parse(source, headers: true)
3191
+ # rows = [
3192
+ # CSV::Row.new(table.headers, ['bat', 3]),
3193
+ # ['bam', 4]
3194
+ # ]
3195
+ # table.push(*rows)
3196
+ # table[3..4] # => [#<CSV::Row "Name":"bat" "Value":3>, #<CSV::Row "Name":"bam" "Value":4>]
791
3197
  #
792
3198
  def push: (*untyped rows) -> untyped
793
3199
 
794
3200
  def size: (*untyped args) { (*untyped) -> untyped } -> untyped
795
3201
 
3202
+ # <!--
3203
+ # rdoc-file=lib/csv/table.rb
3204
+ # - to_a()
3205
+ # -->
796
3206
  # Returns the table as an Array of Arrays. Headers will be the first row, then
797
3207
  # all of the field rows will follow.
798
3208
  #
799
3209
  def to_a: () -> untyped
800
3210
 
3211
+ # <!--
3212
+ # rdoc-file=lib/csv/table.rb
3213
+ # - to_csv(write_headers: true, **options)
3214
+ # -->
801
3215
  # Returns the table as a complete CSV String. Headers will be listed first, then
802
3216
  # all of the field rows.
803
3217
  #
@@ -806,15 +3220,65 @@ class CSV::Table[out Elem] < Object
806
3220
  #
807
3221
  def to_csv: (?write_headers: boolish, **untyped) -> untyped
808
3222
 
3223
+ # <!--
3224
+ # rdoc-file=lib/csv/table.rb
3225
+ # - to_s(write_headers: true, **options)
3226
+ # -->
3227
+ #
809
3228
  alias to_s to_csv
810
3229
 
811
- # The mixed mode default is to treat a list of indices as row access, returning
812
- # the rows indicated. Anything else is considered columnar access. For columnar
813
- # access, the return set has an Array for each row with the values indicated by
814
- # the headers in each Array. You can force column or row mode using by_col!() or
815
- # by_row!().
3230
+ # <!--
3231
+ # rdoc-file=lib/csv/table.rb
3232
+ # - table.values_at(*indexes) -> array_of_rows
3233
+ # - table.values_at(*headers) -> array_of_columns_data
3234
+ # -->
3235
+ # If the access mode is `:row` or `:col_or_row`, and each argument is either an
3236
+ # Integer or a Range, returns rows. Otherwise, returns columns data.
3237
+ #
3238
+ # In either case, the returned values are in the order specified by the
3239
+ # arguments. Arguments may be repeated.
3240
+ #
3241
+ # ---
3242
+ #
3243
+ # Returns rows as an Array of CSV::Row objects.
3244
+ #
3245
+ # No argument:
3246
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
3247
+ # table = CSV.parse(source, headers: true)
3248
+ # table.values_at # => []
3249
+ #
3250
+ # One index:
3251
+ # values = table.values_at(0)
3252
+ # values # => [#<CSV::Row "Name":"foo" "Value":"0">]
3253
+ #
3254
+ # Two indexes:
3255
+ # values = table.values_at(2, 0)
3256
+ # values # => [#<CSV::Row "Name":"baz" "Value":"2">, #<CSV::Row "Name":"foo" "Value":"0">]
3257
+ #
3258
+ # One Range:
3259
+ # values = table.values_at(1..2)
3260
+ # values # => [#<CSV::Row "Name":"bar" "Value":"1">, #<CSV::Row "Name":"baz" "Value":"2">]
3261
+ #
3262
+ # Ranges and indexes:
3263
+ # values = table.values_at(0..1, 1..2, 0, 2)
3264
+ # pp values
3265
+ #
3266
+ # Output:
3267
+ # [#<CSV::Row "Name":"foo" "Value":"0">,
3268
+ # #<CSV::Row "Name":"bar" "Value":"1">,
3269
+ # #<CSV::Row "Name":"bar" "Value":"1">,
3270
+ # #<CSV::Row "Name":"baz" "Value":"2">,
3271
+ # #<CSV::Row "Name":"foo" "Value":"0">,
3272
+ # #<CSV::Row "Name":"baz" "Value":"2">]
3273
+ #
3274
+ # ---
816
3275
  #
817
- # You cannot mix column and row access.
3276
+ # Returns columns data as row Arrays, each consisting of the specified columns
3277
+ # data for that row:
3278
+ # values = table.values_at('Name')
3279
+ # values # => [["foo"], ["bar"], ["baz"]]
3280
+ # values = table.values_at('Value', 'Name')
3281
+ # values # => [["0", "foo"], ["1", "bar"], ["2", "baz"]]
818
3282
  #
819
3283
  def values_at: (*untyped indices_or_headers) -> untyped
820
3284
  end