rbs 2.0.0 → 2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/comments.yml +34 -0
- data/.github/workflows/ruby.yml +5 -0
- data/CHANGELOG.md +82 -0
- data/README.md +6 -1
- data/Rakefile +56 -21
- data/core/array.rbs +2866 -1086
- data/core/basic_object.rbs +150 -30
- data/core/binding.rbs +33 -0
- data/core/builtin.rbs +4 -4
- data/core/class.rbs +43 -5
- data/core/comparable.rbs +57 -0
- data/core/complex.rbs +170 -4
- data/core/constants.rbs +51 -0
- data/core/deprecated.rbs +7 -0
- data/core/dir.rbs +305 -20
- data/core/encoding.rbs +1214 -77
- data/core/enumerable.rbs +2173 -234
- data/core/enumerator.rbs +448 -182
- data/core/env.rbs +448 -1
- data/core/errno.rbs +1 -10
- data/core/errors.rbs +152 -2
- data/core/exception.rbs +201 -127
- data/core/false_class.rbs +27 -0
- data/core/fiber.rbs +118 -37
- data/core/fiber_error.rbs +8 -9
- data/core/file.rbs +1060 -142
- data/core/file_test.rbs +287 -32
- data/core/float.rbs +776 -300
- data/core/gc.rbs +185 -34
- data/core/global_variables.rbs +5 -1
- data/core/hash.rbs +1582 -649
- data/core/integer.rbs +974 -204
- data/core/io/buffer.rbs +710 -0
- data/core/io/wait.rbs +29 -8
- data/core/io.rbs +2438 -417
- data/core/kernel.rbs +2319 -318
- data/core/marshal.rbs +37 -2
- data/core/match_data.rbs +123 -6
- data/core/math.rbs +126 -6
- data/core/method.rbs +226 -102
- data/core/module.rbs +421 -45
- data/core/nil_class.rbs +64 -0
- data/core/numeric.rbs +620 -142
- data/core/object.rbs +453 -81
- data/core/object_space.rbs +92 -2
- data/core/proc.rbs +482 -285
- data/core/process.rbs +443 -34
- data/core/ractor.rbs +232 -9
- data/core/random.rbs +151 -52
- data/core/range.rbs +885 -160
- data/core/rational.rbs +122 -6
- data/core/rb_config.rbs +14 -4
- data/core/refinement.rbs +44 -0
- data/core/regexp.rbs +156 -14
- data/core/ruby_vm.rbs +42 -3
- data/core/signal.rbs +78 -39
- data/core/string.rbs +2123 -567
- data/core/string_io.rbs +204 -0
- data/core/struct.rbs +283 -28
- data/core/symbol.rbs +304 -30
- data/core/thread.rbs +1288 -688
- data/core/thread_group.rbs +66 -10
- data/core/time.rbs +643 -217
- data/core/trace_point.rbs +100 -12
- data/core/true_class.rbs +24 -0
- data/core/unbound_method.rbs +73 -7
- data/core/warning.rbs +37 -12
- data/docs/CONTRIBUTING.md +40 -34
- data/docs/stdlib.md +3 -102
- data/docs/syntax.md +54 -11
- data/ext/rbs_extension/extconf.rb +1 -0
- data/ext/rbs_extension/lexer.h +5 -0
- data/ext/rbs_extension/lexstate.c +6 -0
- data/ext/rbs_extension/parser.c +85 -10
- data/ext/rbs_extension/ruby_objs.c +4 -2
- data/ext/rbs_extension/ruby_objs.h +2 -2
- data/goodcheck.yml +0 -11
- data/lib/rbs/annotate/annotations.rb +197 -0
- data/lib/rbs/annotate/formatter.rb +80 -0
- data/lib/rbs/annotate/rdoc_annotator.rb +398 -0
- data/lib/rbs/annotate/rdoc_source.rb +120 -0
- data/lib/rbs/annotate.rb +6 -0
- data/lib/rbs/ast/members.rb +21 -13
- data/lib/rbs/buffer.rb +17 -11
- data/lib/rbs/cli.rb +48 -1
- data/lib/rbs/definition_builder/method_builder.rb +28 -16
- data/lib/rbs/definition_builder.rb +6 -2
- data/lib/rbs/environment.rb +8 -4
- data/lib/rbs/location_aux.rb +12 -0
- data/lib/rbs/namespace.rb +1 -1
- data/lib/rbs/prototype/rb.rb +12 -0
- data/lib/rbs/type_alias_regularity.rb +6 -4
- data/lib/rbs/type_name.rb +1 -1
- data/lib/rbs/types.rb +1 -1
- data/lib/rbs/validator.rb +6 -0
- data/lib/rbs/version.rb +1 -1
- data/lib/rbs/writer.rb +54 -4
- data/lib/rbs.rb +0 -2
- data/schema/typeParam.json +3 -3
- data/sig/annotate/annotations.rbs +102 -0
- data/sig/annotate/formatter.rbs +24 -0
- data/sig/annotate/rdoc_annotater.rbs +82 -0
- data/sig/annotate/rdoc_source.rbs +30 -0
- data/sig/buffer.rbs +6 -2
- data/sig/cli.rbs +2 -0
- data/sig/collection/{collections.rbs → sources.rbs} +0 -0
- data/sig/location.rbs +6 -0
- data/sig/members.rbs +24 -18
- data/sig/method_builder.rbs +5 -4
- data/sig/method_types.rbs +5 -1
- data/sig/polyfill.rbs +78 -0
- data/sig/validator.rbs +3 -1
- data/sig/writer.rbs +79 -2
- data/stdlib/abbrev/0/abbrev.rbs +6 -0
- data/stdlib/abbrev/0/array.rbs +26 -0
- data/stdlib/base64/0/base64.rbs +31 -0
- data/stdlib/benchmark/0/benchmark.rbs +74 -3
- data/stdlib/bigdecimal/0/big_decimal.rbs +614 -165
- data/stdlib/bigdecimal-math/0/big_math.rbs +41 -64
- data/stdlib/cgi/0/core.rbs +649 -21
- data/stdlib/coverage/0/coverage.rbs +164 -2
- data/stdlib/csv/0/csv.rbs +2862 -398
- data/stdlib/date/0/date.rbs +483 -25
- data/stdlib/date/0/date_time.rbs +187 -12
- data/stdlib/dbm/0/dbm.rbs +152 -17
- data/stdlib/digest/0/digest.rbs +146 -0
- data/stdlib/erb/0/erb.rbs +65 -245
- data/stdlib/fiber/0/fiber.rbs +73 -91
- data/stdlib/fileutils/0/fileutils.rbs +301 -1
- data/stdlib/find/0/find.rbs +9 -0
- data/stdlib/forwardable/0/forwardable.rbs +65 -1
- data/stdlib/io-console/0/io-console.rbs +227 -15
- data/stdlib/ipaddr/0/ipaddr.rbs +161 -0
- data/stdlib/json/0/json.rbs +1147 -145
- data/stdlib/logger/0/formatter.rbs +24 -0
- data/stdlib/logger/0/log_device.rbs +64 -0
- data/stdlib/logger/0/logger.rbs +165 -13
- data/stdlib/logger/0/period.rbs +10 -0
- data/stdlib/logger/0/severity.rbs +26 -0
- data/stdlib/monitor/0/monitor.rbs +163 -0
- data/stdlib/mutex_m/0/mutex_m.rbs +35 -6
- data/stdlib/net-http/0/manifest.yaml +1 -0
- data/stdlib/net-http/0/net-http.rbs +1513 -683
- data/stdlib/nkf/0/nkf.rbs +372 -0
- data/stdlib/objspace/0/objspace.rbs +149 -90
- data/stdlib/openssl/0/openssl.rbs +8108 -71
- data/stdlib/optparse/0/optparse.rbs +487 -19
- data/stdlib/pathname/0/pathname.rbs +425 -124
- data/stdlib/prettyprint/0/prettyprint.rbs +120 -99
- data/stdlib/prime/0/integer-extension.rbs +20 -2
- data/stdlib/prime/0/prime.rbs +88 -21
- data/stdlib/pstore/0/pstore.rbs +102 -0
- data/stdlib/pty/0/pty.rbs +64 -14
- data/stdlib/resolv/0/resolv.rbs +420 -31
- data/stdlib/rubygems/0/basic_specification.rbs +4 -1
- data/stdlib/rubygems/0/config_file.rbs +33 -1
- data/stdlib/rubygems/0/dependency_installer.rbs +4 -3
- data/stdlib/rubygems/0/installer.rbs +13 -1
- data/stdlib/rubygems/0/path_support.rbs +4 -1
- data/stdlib/rubygems/0/platform.rbs +5 -1
- data/stdlib/rubygems/0/request_set.rbs +44 -2
- data/stdlib/rubygems/0/requirement.rbs +65 -2
- data/stdlib/rubygems/0/rubygems.rbs +407 -0
- data/stdlib/rubygems/0/source_list.rbs +13 -0
- data/stdlib/rubygems/0/specification.rbs +21 -1
- data/stdlib/rubygems/0/stream_ui.rbs +3 -1
- data/stdlib/rubygems/0/uninstaller.rbs +8 -1
- data/stdlib/rubygems/0/version.rbs +60 -157
- data/stdlib/securerandom/0/securerandom.rbs +44 -0
- data/stdlib/set/0/set.rbs +423 -109
- data/stdlib/shellwords/0/shellwords.rbs +55 -77
- data/stdlib/singleton/0/singleton.rbs +20 -0
- data/stdlib/socket/0/addrinfo.rbs +210 -9
- data/stdlib/socket/0/basic_socket.rbs +103 -11
- data/stdlib/socket/0/ip_socket.rbs +31 -9
- data/stdlib/socket/0/socket.rbs +586 -38
- data/stdlib/socket/0/tcp_server.rbs +22 -2
- data/stdlib/socket/0/tcp_socket.rbs +12 -1
- data/stdlib/socket/0/udp_socket.rbs +25 -2
- data/stdlib/socket/0/unix_server.rbs +22 -2
- data/stdlib/socket/0/unix_socket.rbs +45 -5
- data/stdlib/strscan/0/string_scanner.rbs +210 -9
- data/stdlib/tempfile/0/tempfile.rbs +58 -10
- data/stdlib/time/0/time.rbs +208 -116
- data/stdlib/timeout/0/timeout.rbs +10 -0
- data/stdlib/tmpdir/0/tmpdir.rbs +13 -4
- data/stdlib/tsort/0/cyclic.rbs +1 -0
- data/stdlib/tsort/0/interfaces.rbs +1 -0
- data/stdlib/tsort/0/tsort.rbs +42 -0
- data/stdlib/uri/0/common.rbs +57 -8
- data/stdlib/uri/0/file.rbs +55 -109
- data/stdlib/uri/0/ftp.rbs +6 -3
- data/stdlib/uri/0/generic.rbs +558 -329
- data/stdlib/uri/0/http.rbs +60 -114
- data/stdlib/uri/0/https.rbs +8 -102
- data/stdlib/uri/0/ldap.rbs +143 -137
- data/stdlib/uri/0/ldaps.rbs +8 -102
- data/stdlib/uri/0/mailto.rbs +3 -0
- data/stdlib/uri/0/rfc2396_parser.rbs +66 -26
- data/stdlib/uri/0/ws.rbs +6 -3
- data/stdlib/uri/0/wss.rbs +5 -3
- data/stdlib/yaml/0/dbm.rbs +151 -87
- data/stdlib/yaml/0/store.rbs +6 -0
- data/stdlib/zlib/0/zlib.rbs +90 -31
- metadata +18 -6
- data/lib/rbs/location.rb +0 -221
- data/sig/char_scanner.rbs +0 -9
data/stdlib/csv/0/csv.rbs
CHANGED
|
@@ -1,122 +1,1611 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
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
|
-
#
|
|
19
|
-
#
|
|
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
|
-
#
|
|
22
|
-
# writing, described in the Specialized Methods section.
|
|
94
|
+
# #### Parsing from an Open IO Stream
|
|
23
95
|
#
|
|
24
|
-
#
|
|
25
|
-
# object.
|
|
96
|
+
# The input to be parsed can be in an open IO stream:
|
|
26
97
|
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
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
|
-
#
|
|
43
|
-
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
52
|
-
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
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
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
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
|
-
#
|
|
862
|
+
# With a different object:
|
|
863
|
+
# CSV.parse_line('a,"",b,"",c', empty_value: 'x') # => ["a", "x", "b", "x", "c"]
|
|
66
864
|
#
|
|
67
|
-
#
|
|
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
|
-
#
|
|
72
|
-
#
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
98
|
-
#
|
|
99
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
104
|
-
# on input data. Converter could be a symbol from CSV::Converters constant's
|
|
105
|
-
# keys, or lambda.
|
|
1583
|
+
# ##### Write Converters
|
|
106
1584
|
#
|
|
107
|
-
#
|
|
108
|
-
#
|
|
109
|
-
#
|
|
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
|
-
#
|
|
112
|
-
# CSV.
|
|
113
|
-
#
|
|
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
|
-
#
|
|
116
|
-
#
|
|
117
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
166
|
-
#
|
|
167
|
-
#
|
|
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
|
-
#
|
|
170
|
-
#
|
|
171
|
-
#
|
|
172
|
-
#
|
|
173
|
-
#
|
|
174
|
-
#
|
|
175
|
-
#
|
|
176
|
-
#
|
|
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
|
-
#
|
|
181
|
-
#
|
|
182
|
-
#
|
|
183
|
-
#
|
|
184
|
-
#
|
|
185
|
-
#
|
|
186
|
-
#
|
|
187
|
-
#
|
|
188
|
-
#
|
|
189
|
-
#
|
|
190
|
-
#
|
|
191
|
-
#
|
|
192
|
-
#
|
|
193
|
-
#
|
|
194
|
-
#
|
|
195
|
-
#
|
|
196
|
-
#
|
|
197
|
-
#
|
|
198
|
-
#
|
|
199
|
-
#
|
|
200
|
-
#
|
|
201
|
-
#
|
|
202
|
-
#
|
|
203
|
-
#
|
|
204
|
-
#
|
|
205
|
-
#
|
|
206
|
-
#
|
|
207
|
-
#
|
|
208
|
-
#
|
|
209
|
-
#
|
|
210
|
-
#
|
|
211
|
-
#
|
|
212
|
-
#
|
|
213
|
-
#
|
|
214
|
-
#
|
|
215
|
-
#
|
|
216
|
-
#
|
|
217
|
-
#
|
|
218
|
-
#
|
|
219
|
-
#
|
|
220
|
-
#
|
|
221
|
-
#
|
|
222
|
-
#
|
|
223
|
-
#
|
|
224
|
-
#
|
|
225
|
-
#
|
|
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
|
-
#
|
|
306
|
-
#
|
|
307
|
-
#
|
|
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
|
-
#
|
|
310
|
-
#
|
|
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
|
-
#
|
|
315
|
-
#
|
|
316
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
331
|
-
#
|
|
332
|
-
#
|
|
333
|
-
#
|
|
334
|
-
#
|
|
335
|
-
#
|
|
336
|
-
# read
|
|
337
|
-
#
|
|
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
|
-
#
|
|
342
|
-
#
|
|
343
|
-
#
|
|
2078
|
+
# <!--
|
|
2079
|
+
# rdoc-file=lib/csv.rb
|
|
2080
|
+
# - csv << row -> self
|
|
2081
|
+
# -->
|
|
2082
|
+
# Appends a row to `self`.
|
|
344
2083
|
#
|
|
345
|
-
#
|
|
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
|
-
#
|
|
350
|
-
#
|
|
351
|
-
#
|
|
352
|
-
#
|
|
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
|
-
#
|
|
355
|
-
#
|
|
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
|
-
#
|
|
358
|
-
#
|
|
359
|
-
#
|
|
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
|
-
#
|
|
365
|
-
# csv.
|
|
366
|
-
# csv.each
|
|
367
|
-
#
|
|
368
|
-
#
|
|
369
|
-
# The data source must be opened for
|
|
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
|
-
#
|
|
373
|
-
#
|
|
374
|
-
#
|
|
375
|
-
#
|
|
376
|
-
#
|
|
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
|
-
#
|
|
379
|
-
#
|
|
380
|
-
#
|
|
2211
|
+
# ["foo", "0"]
|
|
2212
|
+
# ["bar", "1"]
|
|
2213
|
+
# ["baz", "2"]
|
|
381
2214
|
#
|
|
382
2215
|
# With headers:
|
|
383
|
-
#
|
|
384
|
-
#
|
|
385
|
-
#
|
|
386
|
-
#
|
|
387
|
-
#
|
|
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
|
-
#
|
|
390
|
-
#
|
|
391
|
-
#
|
|
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
|
-
#
|
|
397
|
-
#
|
|
398
|
-
#
|
|
399
|
-
#
|
|
400
|
-
#
|
|
401
|
-
#
|
|
402
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
458
|
-
#
|
|
459
|
-
#
|
|
460
|
-
#
|
|
461
|
-
#
|
|
462
|
-
#
|
|
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
|
-
#
|
|
474
|
-
#
|
|
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
|
-
#
|
|
477
|
-
#
|
|
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
|
-
#
|
|
482
|
-
#
|
|
483
|
-
#
|
|
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
|
-
#
|
|
488
|
-
#
|
|
489
|
-
#
|
|
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
|
-
#
|
|
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,
|
|
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
|
-
#
|
|
498
|
-
#
|
|
499
|
-
#
|
|
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
|
-
#
|
|
518
|
-
#
|
|
519
|
-
#
|
|
520
|
-
#
|
|
521
|
-
#
|
|
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
|
-
#
|
|
526
|
-
#
|
|
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
|
-
#
|
|
529
|
-
#
|
|
530
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
543
|
-
#
|
|
544
|
-
#
|
|
545
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
584
|
-
#
|
|
585
|
-
#
|
|
586
|
-
#
|
|
587
|
-
#
|
|
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
|
-
#
|
|
594
|
-
#
|
|
595
|
-
#
|
|
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
|
-
#
|
|
600
|
-
#
|
|
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
|
-
#
|
|
646
|
-
#
|
|
647
|
-
#
|
|
648
|
-
#
|
|
649
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
658
|
-
#
|
|
659
|
-
#
|
|
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
|
-
#
|
|
662
|
-
#
|
|
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
|
-
#
|
|
734
|
-
#
|
|
735
|
-
#
|
|
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
|
-
|
|
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
|
-
#
|
|
3046
|
+
# ---
|
|
745
3047
|
#
|
|
746
|
-
#
|
|
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
|
-
#
|
|
757
|
-
#
|
|
758
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
789
|
-
#
|
|
790
|
-
#
|
|
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
|
-
#
|
|
812
|
-
#
|
|
813
|
-
#
|
|
814
|
-
#
|
|
815
|
-
#
|
|
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
|
-
#
|
|
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
|