csv 3.1.9 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44985560f2528c6909f94ce869ec8ddb014ee66d89fe940fe6f4c872f8773e97
4
- data.tar.gz: 60297accbe6a82852d251f5e4990dfacc241d6ec1084a39eb7ce39ac04c059d6
3
+ metadata.gz: c48c0d15454e002ff10270a9c56cf4311ce635a8a9dfb527f7a7541f29f801b2
4
+ data.tar.gz: 505d1d0dbb4cff0a544b2e00925cb1101ed71642a584d534f443405fba8bd820
5
5
  SHA512:
6
- metadata.gz: 7d51eae6f0e4eaccf382ffc52306ff9b9235259353c8514aafc3fd0116449ae342d9b5972e6ab236ddad542a9a286580f060080503fb18a2f81dfc97299cb8e8
7
- data.tar.gz: ef7d5e134f0ed59e4e0e466c5a6c4a6e45d51ff90a8e3bc22be1014041d29cb3a70c6ae7b482865426d5957962007875b734364b43742b2b7074548d3263bc76
6
+ metadata.gz: 1c9ecd18d5b9a4f663c0676694ffc133a4657e2f7a07cafe2f0a5d9ddd2d7846f505bc62c21698fcf1117126efc6978b7aa1b497d2fef8d532a8a4246c58bff2
7
+ data.tar.gz: e4fe05b49f92c68c011060d1dcd39ead1785d886eabbd3689a12884df9eb30124694417314e39bcf656cd05d6d0dea6a80a701dd5fe6cac42efc33c67be54926
data/NEWS.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # News
2
2
 
3
+ ## 3.2.0 - 2021-06-06
4
+
5
+ ### Improvements
6
+
7
+ * `CSV.open`: Added support for `:newline` option.
8
+ [GitHub#198][Patch by Nobuyoshi Nakada]
9
+
10
+ * `CSV::Table#each`: Added support for column mode with duplicated
11
+ headers.
12
+ [GitHub#206][Reported by Yaroslav Berezovskiy]
13
+
14
+ * `Object#CSV`: Added support for Ruby 3.0.
15
+
16
+ * `CSV::Row`: Added support for pattern matching.
17
+ [GitHub#207][Patch by Kevin Newton]
18
+
19
+ ### Fixes
20
+
21
+ * Fixed typos in documentation.
22
+ [GitHub#196][GitHub#205][Patch by Sampat Badhe]
23
+
24
+ ### Thanks
25
+
26
+ * Sampat Badhe
27
+
28
+ * Nobuyoshi Nakada
29
+
30
+ * Yaroslav Berezovskiy
31
+
32
+ * Kevin Newton
33
+
3
34
  ## 3.1.9 - 2020-11-23
4
35
 
5
36
  ### Fixes
data/README.md CHANGED
@@ -1,8 +1,5 @@
1
1
  # CSV
2
2
 
3
- [![Build Status](https://travis-ci.org/ruby/csv.svg?branch=master)](https://travis-ci.org/ruby/csv)
4
- [![Test Coverage](https://api.codeclimate.com/v1/badges/321fa39e510a0abd0369/test_coverage)](https://codeclimate.com/github/ruby/csv/test_coverage)
5
-
6
3
  This library provides a complete interface to CSV files and data. It offers tools to enable you to read and write to and from Strings or IO objects, as needed.
7
4
 
8
5
  ## Installation
@@ -33,8 +30,8 @@ end
33
30
 
34
31
  ## Documentation
35
32
 
36
- - {API}[CSV.html]: all classes, methods, and constants.
37
- - {Recipes}[doc/csv/recipes/recipes_rdoc.html]: specific code for specific tasks.
33
+ - [API](https://ruby-doc.org/stdlib/libdoc/csv/rdoc/CSV.html): all classes, methods, and constants.
34
+ - [Recipes](https://ruby-doc.org/core/doc/csv/recipes/recipes_rdoc.html): specific code for specific tasks.
38
35
 
39
36
  ## Development
40
37
 
@@ -431,7 +431,7 @@ You can use multiple field converters in either of these ways:
431
431
 
432
432
  ===== Recipe: Specify Multiple Field Converters in Option +:converters+
433
433
 
434
- Apply multiple field converters by specifying them in option +:conveters+:
434
+ Apply multiple field converters by specifying them in option +:converters+:
435
435
  source = "Name,Value\nfoo,0\nbar,1.0\nbaz,2.0\n"
436
436
  parsed = CSV.parse(source, headers: true, converters: [:integer, :float])
437
437
  parsed['Value'] # => [0, 1.0, 2.0]
@@ -500,7 +500,7 @@ You can use multiple header converters in either of these ways:
500
500
 
501
501
  ===== Recipe: Specify Multiple Header Converters in Option :header_converters
502
502
 
503
- Apply multiple header converters by specifying them in option +:header_conveters+:
503
+ Apply multiple header converters by specifying them in option +:header_converters+:
504
504
  source = "Name,Value\nfoo,0\nbar,1.0\nbaz,2.0\n"
505
505
  parsed = CSV.parse(source, headers: true, header_converters: [:downcase, :symbol])
506
506
  parsed.headers # => [:name, :value]
data/lib/csv.rb CHANGED
@@ -48,7 +48,7 @@
48
48
  #
49
49
  # === Interface
50
50
  #
51
- # * CSV now uses Hash-style parameters to set options.
51
+ # * CSV now uses keyword parameters to set options.
52
52
  # * CSV no longer has generate_row() or parse_row().
53
53
  # * The old CSV's Reader and Writer classes have been dropped.
54
54
  # * CSV::open() is now more like Ruby's open().
@@ -705,7 +705,7 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
705
705
  # Header converters operate only on headers (and not on other rows).
706
706
  #
707
707
  # There are three ways to use header \converters;
708
- # these examples use built-in header converter +:dowhcase+,
708
+ # these examples use built-in header converter +:downcase+,
709
709
  # which downcases each parsed header.
710
710
  #
711
711
  # - Option +header_converters+ with a singleton parsing method:
@@ -1006,60 +1006,185 @@ class CSV
1006
1006
  end
1007
1007
 
1008
1008
  # :call-seq:
1009
- # filter(**options) {|row| ... }
1010
- # filter(in_string, **options) {|row| ... }
1011
- # filter(in_io, **options) {|row| ... }
1012
- # filter(in_string, out_string, **options) {|row| ... }
1013
- # filter(in_string, out_io, **options) {|row| ... }
1014
- # filter(in_io, out_string, **options) {|row| ... }
1015
- # filter(in_io, out_io, **options) {|row| ... }
1016
- #
1017
- # Reads \CSV input and writes \CSV output.
1018
- #
1019
- # For each input row:
1020
- # - Forms the data into:
1021
- # - A CSV::Row object, if headers are in use.
1022
- # - An \Array of Arrays, otherwise.
1023
- # - Calls the block with that object.
1024
- # - Appends the block's return value to the output.
1009
+ # filter(in_string_or_io, **options) {|row| ... } -> array_of_arrays or csv_table
1010
+ # filter(in_string_or_io, out_string_or_io, **options) {|row| ... } -> array_of_arrays or csv_table
1011
+ # filter(**options) {|row| ... } -> array_of_arrays or csv_table
1025
1012
  #
1026
- # Arguments:
1027
- # * \CSV source:
1028
- # * Argument +in_string+, if given, should be a \String object;
1029
- # it will be put into a new StringIO object positioned at the beginning.
1030
- # * Argument +in_io+, if given, should be an IO object that is
1031
- # open for reading; on return, the IO object will be closed.
1032
- # * If neither +in_string+ nor +in_io+ is given,
1033
- # the input stream defaults to {ARGF}[https://ruby-doc.org/core/ARGF.html].
1034
- # * \CSV output:
1035
- # * Argument +out_string+, if given, should be a \String object;
1036
- # it will be put into a new StringIO object positioned at the beginning.
1037
- # * Argument +out_io+, if given, should be an IO object that is
1038
- # ppen for writing; on return, the IO object will be closed.
1039
- # * If neither +out_string+ nor +out_io+ is given,
1040
- # the output stream defaults to <tt>$stdout</tt>.
1041
- # * Argument +options+ should be keyword arguments.
1042
- # - Each argument name that is prefixed with +in_+ or +input_+
1043
- # is stripped of its prefix and is treated as an option
1044
- # for parsing the input.
1045
- # Option +input_row_sep+ defaults to <tt>$INPUT_RECORD_SEPARATOR</tt>.
1046
- # - Each argument name that is prefixed with +out_+ or +output_+
1047
- # is stripped of its prefix and is treated as an option
1048
- # for generating the output.
1049
- # Option +output_row_sep+ defaults to <tt>$INPUT_RECORD_SEPARATOR</tt>.
1050
- # - Each argument not prefixed as above is treated as an option
1051
- # both for parsing the input and for generating the output.
1052
- # - See {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
1053
- # and {Options for Generating}[#class-CSV-label-Options+for+Generating].
1013
+ # - Parses \CSV from a source (\String, \IO stream, or ARGF).
1014
+ # - Calls the given block with each parsed row:
1015
+ # - Without headers, each row is an \Array.
1016
+ # - With headers, each row is a CSV::Row.
1017
+ # - Generates \CSV to an output (\String, \IO stream, or STDOUT).
1018
+ # - Returns the parsed source:
1019
+ # - Without headers, an \Array of \Arrays.
1020
+ # - With headers, a CSV::Table.
1054
1021
  #
1055
- # Example:
1056
- # in_string = "foo,0\nbar,1\nbaz,2\n"
1022
+ # When +in_string_or_io+ is given, but not +out_string_or_io+,
1023
+ # parses from the given +in_string_or_io+
1024
+ # and generates to STDOUT.
1025
+ #
1026
+ # \String input without headers:
1027
+ #
1028
+ # in_string = "foo,0\nbar,1\nbaz,2"
1029
+ # CSV.filter(in_string) do |row|
1030
+ # row[0].upcase!
1031
+ # row[1] = - row[1].to_i
1032
+ # end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]
1033
+ #
1034
+ # Output (to STDOUT):
1035
+ #
1036
+ # FOO,0
1037
+ # BAR,-1
1038
+ # BAZ,-2
1039
+ #
1040
+ # \String input with headers:
1041
+ #
1042
+ # in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2"
1043
+ # CSV.filter(in_string, headers: true) do |row|
1044
+ # row[0].upcase!
1045
+ # row[1] = - row[1].to_i
1046
+ # end # => #<CSV::Table mode:col_or_row row_count:4>
1047
+ #
1048
+ # Output (to STDOUT):
1049
+ #
1050
+ # Name,Value
1051
+ # FOO,0
1052
+ # BAR,-1
1053
+ # BAZ,-2
1054
+ #
1055
+ # \IO stream input without headers:
1056
+ #
1057
+ # File.write('t.csv', "foo,0\nbar,1\nbaz,2")
1058
+ # File.open('t.csv') do |in_io|
1059
+ # CSV.filter(in_io) do |row|
1060
+ # row[0].upcase!
1061
+ # row[1] = - row[1].to_i
1062
+ # end
1063
+ # end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]
1064
+ #
1065
+ # Output (to STDOUT):
1066
+ #
1067
+ # FOO,0
1068
+ # BAR,-1
1069
+ # BAZ,-2
1070
+ #
1071
+ # \IO stream input with headers:
1072
+ #
1073
+ # File.write('t.csv', "Name,Value\nfoo,0\nbar,1\nbaz,2")
1074
+ # File.open('t.csv') do |in_io|
1075
+ # CSV.filter(in_io, headers: true) do |row|
1076
+ # row[0].upcase!
1077
+ # row[1] = - row[1].to_i
1078
+ # end
1079
+ # end # => #<CSV::Table mode:col_or_row row_count:4>
1080
+ #
1081
+ # Output (to STDOUT):
1082
+ #
1083
+ # Name,Value
1084
+ # FOO,0
1085
+ # BAR,-1
1086
+ # BAZ,-2
1087
+ #
1088
+ # When both +in_string_or_io+ and +out_string_or_io+ are given,
1089
+ # parses from +in_string_or_io+ and generates to +out_string_or_io+.
1090
+ #
1091
+ # \String output without headers:
1092
+ #
1093
+ # in_string = "foo,0\nbar,1\nbaz,2"
1057
1094
  # out_string = ''
1058
1095
  # CSV.filter(in_string, out_string) do |row|
1059
- # row[0] = row[0].upcase
1060
- # row[1] *= 4
1061
- # end
1062
- # out_string # => "FOO,0000\nBAR,1111\nBAZ,2222\n"
1096
+ # row[0].upcase!
1097
+ # row[1] = - row[1].to_i
1098
+ # end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]
1099
+ # out_string # => "FOO,0\nBAR,-1\nBAZ,-2\n"
1100
+ #
1101
+ # \String output with headers:
1102
+ #
1103
+ # in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2"
1104
+ # out_string = ''
1105
+ # CSV.filter(in_string, out_string, headers: true) do |row|
1106
+ # row[0].upcase!
1107
+ # row[1] = - row[1].to_i
1108
+ # end # => #<CSV::Table mode:col_or_row row_count:4>
1109
+ # out_string # => "Name,Value\nFOO,0\nBAR,-1\nBAZ,-2\n"
1110
+ #
1111
+ # \IO stream output without headers:
1112
+ #
1113
+ # in_string = "foo,0\nbar,1\nbaz,2"
1114
+ # File.open('t.csv', 'w') do |out_io|
1115
+ # CSV.filter(in_string, out_io) do |row|
1116
+ # row[0].upcase!
1117
+ # row[1] = - row[1].to_i
1118
+ # end
1119
+ # end # => [["FOO", 0], ["BAR", -1], ["BAZ", -2]]
1120
+ # File.read('t.csv') # => "FOO,0\nBAR,-1\nBAZ,-2\n"
1121
+ #
1122
+ # \IO stream output with headers:
1123
+ #
1124
+ # in_string = "Name,Value\nfoo,0\nbar,1\nbaz,2"
1125
+ # File.open('t.csv', 'w') do |out_io|
1126
+ # CSV.filter(in_string, out_io, headers: true) do |row|
1127
+ # row[0].upcase!
1128
+ # row[1] = - row[1].to_i
1129
+ # end
1130
+ # end # => #<CSV::Table mode:col_or_row row_count:4>
1131
+ # File.read('t.csv') # => "Name,Value\nFOO,0\nBAR,-1\nBAZ,-2\n"
1132
+ #
1133
+ # When neither +in_string_or_io+ nor +out_string_or_io+ given,
1134
+ # parses from {ARGF}[https://docs.ruby-lang.org/en/master/ARGF.html]
1135
+ # and generates to STDOUT.
1136
+ #
1137
+ # Without headers:
1138
+ #
1139
+ # # Put Ruby code into a file.
1140
+ # ruby = <<-EOT
1141
+ # require 'csv'
1142
+ # CSV.filter do |row|
1143
+ # row[0].upcase!
1144
+ # row[1] = - row[1].to_i
1145
+ # end
1146
+ # EOT
1147
+ # File.write('t.rb', ruby)
1148
+ # # Put some CSV into a file.
1149
+ # File.write('t.csv', "foo,0\nbar,1\nbaz,2")
1150
+ # # Run the Ruby code with CSV filename as argument.
1151
+ # system(Gem.ruby, "t.rb", "t.csv")
1152
+ #
1153
+ # Output (to STDOUT):
1154
+ #
1155
+ # FOO,0
1156
+ # BAR,-1
1157
+ # BAZ,-2
1158
+ #
1159
+ # With headers:
1160
+ #
1161
+ # # Put Ruby code into a file.
1162
+ # ruby = <<-EOT
1163
+ # require 'csv'
1164
+ # CSV.filter(headers: true) do |row|
1165
+ # row[0].upcase!
1166
+ # row[1] = - row[1].to_i
1167
+ # end
1168
+ # EOT
1169
+ # File.write('t.rb', ruby)
1170
+ # # Put some CSV into a file.
1171
+ # File.write('t.csv', "Name,Value\nfoo,0\nbar,1\nbaz,2")
1172
+ # # Run the Ruby code with CSV filename as argument.
1173
+ # system(Gem.ruby, "t.rb", "t.csv")
1174
+ #
1175
+ # Output (to STDOUT):
1176
+ #
1177
+ # Name,Value
1178
+ # FOO,0
1179
+ # BAR,-1
1180
+ # BAZ,-2
1181
+ #
1182
+ # Arguments:
1183
+ #
1184
+ # * Argument +in_string_or_io+ must be a \String or an \IO stream.
1185
+ # * Argument +out_string_or_io+ must be a \String or an \IO stream.
1186
+ # * Arguments <tt>**options</tt> must be keyword options.
1187
+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
1063
1188
  def filter(input=nil, output=nil, **options)
1064
1189
  # parse options for input, output, or both
1065
1190
  in_options, out_options = Hash.new, {row_sep: $INPUT_RECORD_SEPARATOR}
@@ -1106,111 +1231,90 @@ class CSV
1106
1231
 
1107
1232
  #
1108
1233
  # :call-seq:
1109
- # foreach(path, mode='r', **options) {|row| ... )
1110
- # foreach(io, mode='r', **options {|row| ... )
1111
- # foreach(path, mode='r', headers: ..., **options) {|row| ... )
1112
- # foreach(io, mode='r', headers: ..., **options {|row| ... )
1113
- # foreach(path, mode='r', **options) -> new_enumerator
1114
- # foreach(io, mode='r', **options -> new_enumerator
1234
+ # foreach(path_or_io, mode='r', **options) {|row| ... )
1235
+ # foreach(path_or_io, mode='r', **options) -> new_enumerator
1115
1236
  #
1116
- # Calls the block with each row read from source +path+ or +io+.
1237
+ # Calls the block with each row read from source +path_or_io+.
1117
1238
  #
1118
- # * Argument +path+, if given, must be the path to a file.
1119
- # :include: ../doc/csv/arguments/io.rdoc
1120
- # * Argument +mode+, if given, must be a \File mode
1121
- # See {Open Mode}[IO.html#method-c-new-label-Open+Mode].
1122
- # * Arguments <tt>**options</tt> must be keyword options.
1123
- # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
1124
- # * This method optionally accepts an additional <tt>:encoding</tt> option
1125
- # that you can use to specify the Encoding of the data read from +path+ or +io+.
1126
- # You must provide this unless your data is in the encoding
1127
- # given by <tt>Encoding::default_external</tt>.
1128
- # Parsing will use this to determine how to parse the data.
1129
- # You may provide a second Encoding to
1130
- # have the data transcoded as it is read. For example,
1131
- # encoding: 'UTF-32BE:UTF-8'
1132
- # would read +UTF-32BE+ data from the file
1133
- # but transcode it to +UTF-8+ before parsing.
1134
- #
1135
- # ====== Without Option +headers+
1239
+ # \Path input without headers:
1136
1240
  #
1137
- # Without option +headers+, returns each row as an \Array object.
1138
- #
1139
- # These examples assume prior execution of:
1140
1241
  # string = "foo,0\nbar,1\nbaz,2\n"
1141
- # path = 't.csv'
1142
- # File.write(path, string)
1242
+ # in_path = 't.csv'
1243
+ # File.write(in_path, string)
1244
+ # CSV.foreach(in_path) {|row| p row }
1143
1245
  #
1144
- # Read rows from a file at +path+:
1145
- # CSV.foreach(path) {|row| p row }
1146
1246
  # Output:
1147
- # ["foo", "0"]
1148
- # ["bar", "1"]
1149
- # ["baz", "2"]
1150
1247
  #
1151
- # Read rows from an \IO object:
1152
- # File.open(path) do |file|
1153
- # CSV.foreach(file) {|row| p row }
1154
- # end
1155
- #
1156
- # Output:
1157
1248
  # ["foo", "0"]
1158
1249
  # ["bar", "1"]
1159
1250
  # ["baz", "2"]
1160
1251
  #
1161
- # Returns a new \Enumerator if no block given:
1162
- # CSV.foreach(path) # => #<Enumerator: CSV:foreach("t.csv", "r")>
1163
- # CSV.foreach(File.open(path)) # => #<Enumerator: CSV:foreach(#<File:t.csv>, "r")>
1252
+ # \Path input with headers:
1253
+ #
1254
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
1255
+ # in_path = 't.csv'
1256
+ # File.write(in_path, string)
1257
+ # CSV.foreach(in_path, headers: true) {|row| p row }
1164
1258
  #
1165
- # Issues a warning if an encoding is unsupported:
1166
- # CSV.foreach(File.open(path), encoding: 'foo:bar') {|row| }
1167
1259
  # Output:
1168
- # warning: Unsupported encoding foo ignored
1169
- # warning: Unsupported encoding bar ignored
1170
1260
  #
1171
- # ====== With Option +headers+
1261
+ # <CSV::Row "Name":"foo" "Value":"0">
1262
+ # <CSV::Row "Name":"bar" "Value":"1">
1263
+ # <CSV::Row "Name":"baz" "Value":"2">
1172
1264
  #
1173
- # With {option +headers+}[#class-CSV-label-Option+headers],
1174
- # returns each row as a CSV::Row object.
1265
+ # \IO stream input without headers:
1175
1266
  #
1176
- # These examples assume prior execution of:
1177
- # string = "Name,Count\nfoo,0\nbar,1\nbaz,2\n"
1267
+ # string = "foo,0\nbar,1\nbaz,2\n"
1178
1268
  # path = 't.csv'
1179
1269
  # File.write(path, string)
1180
- #
1181
- # Read rows from a file at +path+:
1182
- # CSV.foreach(path, headers: true) {|row| p row }
1270
+ # File.open('t.csv') do |in_io|
1271
+ # CSV.foreach(in_io) {|row| p row }
1272
+ # end
1183
1273
  #
1184
1274
  # Output:
1185
- # #<CSV::Row "Name":"foo" "Count":"0">
1186
- # #<CSV::Row "Name":"bar" "Count":"1">
1187
- # #<CSV::Row "Name":"baz" "Count":"2">
1188
1275
  #
1189
- # Read rows from an \IO object:
1190
- # File.open(path) do |file|
1191
- # CSV.foreach(file, headers: true) {|row| p row }
1276
+ # ["foo", "0"]
1277
+ # ["bar", "1"]
1278
+ # ["baz", "2"]
1279
+ #
1280
+ # \IO stream input with headers:
1281
+ #
1282
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
1283
+ # path = 't.csv'
1284
+ # File.write(path, string)
1285
+ # File.open('t.csv') do |in_io|
1286
+ # CSV.foreach(in_io, headers: true) {|row| p row }
1192
1287
  # end
1193
1288
  #
1194
1289
  # Output:
1195
- # #<CSV::Row "Name":"foo" "Count":"0">
1196
- # #<CSV::Row "Name":"bar" "Count":"1">
1197
- # #<CSV::Row "Name":"baz" "Count":"2">
1198
1290
  #
1199
- # ---
1291
+ # <CSV::Row "Name":"foo" "Value":"0">
1292
+ # <CSV::Row "Name":"bar" "Value":"1">
1293
+ # <CSV::Row "Name":"baz" "Value":"2">
1200
1294
  #
1201
- # Raises an exception if +path+ is a \String, but not the path to a readable file:
1202
- # # Raises Errno::ENOENT (No such file or directory @ rb_sysopen - nosuch.csv):
1203
- # CSV.foreach('nosuch.csv') {|row| }
1295
+ # With no block given, returns an \Enumerator:
1204
1296
  #
1205
- # Raises an exception if +io+ is an \IO object, but not open for reading:
1206
- # io = File.open(path, 'w') {|row| }
1207
- # # Raises TypeError (no implicit conversion of nil into String):
1208
- # CSV.foreach(io) {|row| }
1209
- #
1210
- # Raises an exception if +mode+ is invalid:
1211
- # # Raises ArgumentError (invalid access mode nosuch):
1212
- # CSV.foreach(path, 'nosuch') {|row| }
1297
+ # string = "foo,0\nbar,1\nbaz,2\n"
1298
+ # path = 't.csv'
1299
+ # File.write(path, string)
1300
+ # CSV.foreach(path) # => #<Enumerator: CSV:foreach("t.csv", "r")>
1213
1301
  #
1302
+ # Arguments:
1303
+ # * Argument +path_or_io+ must be a file path or an \IO stream.
1304
+ # * Argument +mode+, if given, must be a \File mode
1305
+ # See {Open Mode}[https://ruby-doc.org/core/IO.html#method-c-new-label-Open+Mode].
1306
+ # * Arguments <tt>**options</tt> must be keyword options.
1307
+ # See {Options for Parsing}[#class-CSV-label-Options+for+Parsing].
1308
+ # * This method optionally accepts an additional <tt>:encoding</tt> option
1309
+ # that you can use to specify the Encoding of the data read from +path+ or +io+.
1310
+ # You must provide this unless your data is in the encoding
1311
+ # given by <tt>Encoding::default_external</tt>.
1312
+ # Parsing will use this to determine how to parse the data.
1313
+ # You may provide a second Encoding to
1314
+ # have the data transcoded as it is read. For example,
1315
+ # encoding: 'UTF-32BE:UTF-8'
1316
+ # would read +UTF-32BE+ data from the file
1317
+ # but transcode it to +UTF-8+ before parsing.
1214
1318
  def foreach(path, mode="r", **options, &block)
1215
1319
  return to_enum(__method__, path, mode, **options) unless block_given?
1216
1320
  open(path, mode, **options) do |csv|
@@ -1356,7 +1460,7 @@ class CSV
1356
1460
  # open(io, mode = "rb", **options ) { |csv| ... } -> object
1357
1461
  #
1358
1462
  # possible options elements:
1359
- # hash form:
1463
+ # keyword form:
1360
1464
  # :invalid => nil # raise error on invalid byte sequence (default)
1361
1465
  # :invalid => :replace # replace invalid byte sequence
1362
1466
  # :undef => :replace # replace undefined conversion
@@ -1423,10 +1527,14 @@ class CSV
1423
1527
  def open(filename, mode="r", **options)
1424
1528
  # wrap a File opened with the remaining +args+ with no newline
1425
1529
  # decorator
1426
- file_opts = {universal_newline: false}.merge(options)
1530
+ file_opts = options.dup
1531
+ unless file_opts.key?(:newline)
1532
+ file_opts[:universal_newline] ||= false
1533
+ end
1427
1534
  options.delete(:invalid)
1428
1535
  options.delete(:undef)
1429
1536
  options.delete(:replace)
1537
+ options.delete_if {|k, _| /newline\z/.match?(k)}
1430
1538
 
1431
1539
  begin
1432
1540
  f = File.open(filename, mode, **file_opts)
@@ -1681,7 +1789,7 @@ class CSV
1681
1789
  #
1682
1790
  # Calls CSV.read with +source+, +options+, and certain default options:
1683
1791
  # - +headers+: +true+
1684
- # - +converbers+: +:numeric+
1792
+ # - +converters+: +:numeric+
1685
1793
  # - +header_converters+: +:symbol+
1686
1794
  #
1687
1795
  # Returns a CSV::Table object.
@@ -1985,7 +2093,7 @@ class CSV
1985
2093
  end
1986
2094
 
1987
2095
  # :call-seq:
1988
- # csv.encoding -> endcoding
2096
+ # csv.encoding -> encoding
1989
2097
  #
1990
2098
  # Returns the encoding used for parsing and generating;
1991
2099
  # see {Character Encodings (M17n or Multilingualization)}[#class-CSV-label-Character+Encodings+-28M17n+or+Multilingualization-29]:
@@ -2661,8 +2769,13 @@ end
2661
2769
  # c.read.any? { |a| a.include?("zombies") }
2662
2770
  # } #=> false
2663
2771
  #
2664
- def CSV(*args, &block)
2665
- CSV.instance(*args, &block)
2772
+ # CSV options may also be given.
2773
+ #
2774
+ # io = StringIO.new
2775
+ # CSV(io, col_sep: ";") { |csv| csv << ["a", "b", "c"] }
2776
+ #
2777
+ def CSV(*args, **options, &block)
2778
+ CSV.instance(*args, **options, &block)
2666
2779
  end
2667
2780
 
2668
2781
  require_relative "csv/version"
data/lib/csv/row.rb CHANGED
@@ -659,8 +659,30 @@ class CSV
659
659
  end
660
660
  alias_method :to_hash, :to_h
661
661
 
662
+ # :call-seq:
663
+ # row.deconstruct_keys(keys) -> hash
664
+ #
665
+ # Returns the new \Hash suitable for pattern matching containing only the
666
+ # keys specified as an argument.
667
+ def deconstruct_keys(keys)
668
+ if keys.nil?
669
+ to_h
670
+ else
671
+ keys.to_h { |key| [key, self[key]] }
672
+ end
673
+ end
674
+
662
675
  alias_method :to_ary, :to_a
663
676
 
677
+ # :call-seq:
678
+ # row.deconstruct -> array
679
+ #
680
+ # Returns the new \Array suitable for pattern matching containing the values
681
+ # of the row.
682
+ def deconstruct
683
+ fields
684
+ end
685
+
664
686
  # :call-seq:
665
687
  # row.to_csv -> csv_string
666
688
  #
data/lib/csv/table.rb CHANGED
@@ -932,7 +932,9 @@ class CSV
932
932
  return enum_for(__method__) { @mode == :col ? headers.size : size } unless block_given?
933
933
 
934
934
  if @mode == :col
935
- headers.each { |header| yield([header, self[header]]) }
935
+ headers.each.with_index do |header, i|
936
+ yield([header, @table.map {|row| row[header, i]}])
937
+ end
936
938
  else
937
939
  @table.each(&block)
938
940
  end
data/lib/csv/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
 
3
3
  class CSV
4
4
  # The version of the installed library.
5
- VERSION = "3.1.9"
5
+ VERSION = "3.2.0"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: csv
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.9
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Edward Gray II
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-11-22 00:00:00.000000000 Z
12
+ date: 2021-06-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -54,19 +54,19 @@ dependencies:
54
54
  - !ruby/object:Gem::Version
55
55
  version: '0'
56
56
  - !ruby/object:Gem::Dependency
57
- name: simplecov
57
+ name: test-unit
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
60
  - - ">="
61
61
  - !ruby/object:Gem::Version
62
- version: '0'
62
+ version: 3.4.3
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: '0'
69
+ version: 3.4.3
70
70
  description: The CSV library provides a complete interface to CSV files and data.
71
71
  It offers tools to enable you to read and write to and from Strings or IO objects,
72
72
  as needed.
@@ -146,7 +146,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
146
  - !ruby/object:Gem::Version
147
147
  version: '0'
148
148
  requirements: []
149
- rubygems_version: 3.2.0.rc.2
149
+ rubygems_version: 3.3.0.dev
150
150
  signing_key:
151
151
  specification_version: 4
152
152
  summary: CSV Reading and Writing