csv 3.1.6 → 3.1.7

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.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS.md +20 -0
  3. data/doc/{arguments → csv/arguments}/io.rdoc +0 -0
  4. data/doc/{options → csv/options}/common/col_sep.rdoc +0 -0
  5. data/doc/{options → csv/options}/common/quote_char.rdoc +0 -0
  6. data/doc/{options → csv/options}/common/row_sep.rdoc +0 -0
  7. data/doc/{options → csv/options}/generating/force_quotes.rdoc +0 -0
  8. data/doc/{options → csv/options}/generating/quote_empty.rdoc +0 -0
  9. data/doc/{options → csv/options}/generating/write_converters.rdoc +0 -0
  10. data/doc/{options → csv/options}/generating/write_empty_value.rdoc +0 -0
  11. data/doc/{options → csv/options}/generating/write_headers.rdoc +0 -0
  12. data/doc/{options → csv/options}/generating/write_nil_value.rdoc +0 -0
  13. data/doc/{options → csv/options}/parsing/converters.rdoc +0 -0
  14. data/doc/{options → csv/options}/parsing/empty_value.rdoc +0 -0
  15. data/doc/{options → csv/options}/parsing/field_size_limit.rdoc +0 -0
  16. data/doc/{options → csv/options}/parsing/header_converters.rdoc +0 -0
  17. data/doc/{options → csv/options}/parsing/headers.rdoc +0 -0
  18. data/doc/{options → csv/options}/parsing/liberal_parsing.rdoc +0 -0
  19. data/doc/{options → csv/options}/parsing/nil_value.rdoc +0 -0
  20. data/doc/{options → csv/options}/parsing/return_headers.rdoc +0 -0
  21. data/doc/{options → csv/options}/parsing/skip_blanks.rdoc +0 -0
  22. data/doc/{options → csv/options}/parsing/skip_lines.rdoc +0 -0
  23. data/doc/{options → csv/options}/parsing/strip.rdoc +0 -0
  24. data/doc/{options → csv/options}/parsing/unconverted_fields.rdoc +0 -0
  25. data/lib/csv.rb +142 -46
  26. data/lib/csv/table.rb +285 -64
  27. data/lib/csv/version.rb +1 -1
  28. metadata +26 -40
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 684d334d79d666022640de8b3bfa8d2e6fa879cb0c9e59349e9adf8307147fa0
4
- data.tar.gz: 6298def337c705d19acb6d1da52560aa53f0dfeba5660202d8fc0259418d96a1
3
+ metadata.gz: c834580f6d364830ddcd85b07edcb44fc91520fd594492a835cb57f43f145c94
4
+ data.tar.gz: 989310760b22148eeb70be9181a39c2d08c8040f7e79fd6a06dc7586409c4e7f
5
5
  SHA512:
6
- metadata.gz: 42349aa586b53f75c75ea29a5388889c21645b24e1ad8ac8e1752697f94dc9e7564b62f36b2b6219516f34c1a27bbf581566f3f2dafef556f9783b907e932d04
7
- data.tar.gz: 69319007e9a35acb7659d73b5c9a38256a572a5a21ef59365b8f4fd0fee9d06c2c0c89ae346bf701e6c0af430fc99868c625323cc75f620340eb80006ce0d036
6
+ metadata.gz: 75859dd4eff126ab15bf372305da6eeb638ce1927186931f3ea87fe00c0a769c8adb38cb786b8ee3f7fd418de720d26fe01fba9ca28ac565bbd761431057cec8
7
+ data.tar.gz: 56b5de70961f3e9792296e6b68941fa1ea1e1eaa5ad2811ae47954a775c986d8f9455af50e5e6d25deb797794b697cef0e0c4a87695dc3a42d9fa477008d85dc
data/NEWS.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # News
2
2
 
3
+ ## 3.1.7 - 2020-08-04
4
+
5
+ ### Improvements
6
+
7
+ * Improved document.
8
+ [GitHub#158][GitHub#160][GitHub#161]
9
+ [Patch by Burdette Lamar]
10
+
11
+ * Updated required Ruby version to 2.5.0 or later.
12
+ [GitHub#159]
13
+ [Patch by Gabriel Nagy]
14
+
15
+ * Removed stringio 0.1.3 or later dependency.
16
+
17
+ ### Thanks
18
+
19
+ * Burdette Lamar
20
+
21
+ * Gabriel Nagy
22
+
3
23
  ## 3.1.6 - 2020-07-20
4
24
 
5
25
  ### Improvements
File without changes
data/lib/csv.rb CHANGED
@@ -104,7 +104,7 @@ require_relative "csv/writer"
104
104
  using CSV::MatchP if CSV.const_defined?(:MatchP)
105
105
 
106
106
  # == \CSV
107
- # \CSV (comma-separated variables) data is a text representation of a table:
107
+ # \CSV (comma-separated values) data is a text representation of a table:
108
108
  # - A _row_ _separator_ delimits table rows.
109
109
  # A common row separator is the newline character <tt>"\n"</tt>.
110
110
  # - A _column_ _separator_ delimits fields in a row.
@@ -357,35 +357,35 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
357
357
  # - +nil_value+: Specifies the object that is to be substituted for each null (no-text) field.
358
358
  # - +empty_value+: Specifies the object that is to be substituted for each empty field.
359
359
  #
360
- # :include: ../doc/options/common/row_sep.rdoc
360
+ # :include: ../doc/csv/options/common/row_sep.rdoc
361
361
  #
362
- # :include: ../doc/options/common/col_sep.rdoc
362
+ # :include: ../doc/csv/options/common/col_sep.rdoc
363
363
  #
364
- # :include: ../doc/options/common/quote_char.rdoc
364
+ # :include: ../doc/csv/options/common/quote_char.rdoc
365
365
  #
366
- # :include: ../doc/options/parsing/field_size_limit.rdoc
366
+ # :include: ../doc/csv/options/parsing/field_size_limit.rdoc
367
367
  #
368
- # :include: ../doc/options/parsing/converters.rdoc
368
+ # :include: ../doc/csv/options/parsing/converters.rdoc
369
369
  #
370
- # :include: ../doc/options/parsing/unconverted_fields.rdoc
370
+ # :include: ../doc/csv/options/parsing/unconverted_fields.rdoc
371
371
  #
372
- # :include: ../doc/options/parsing/headers.rdoc
372
+ # :include: ../doc/csv/options/parsing/headers.rdoc
373
373
  #
374
- # :include: ../doc/options/parsing/return_headers.rdoc
374
+ # :include: ../doc/csv/options/parsing/return_headers.rdoc
375
375
  #
376
- # :include: ../doc/options/parsing/header_converters.rdoc
376
+ # :include: ../doc/csv/options/parsing/header_converters.rdoc
377
377
  #
378
- # :include: ../doc/options/parsing/skip_blanks.rdoc
378
+ # :include: ../doc/csv/options/parsing/skip_blanks.rdoc
379
379
  #
380
- # :include: ../doc/options/parsing/skip_lines.rdoc
380
+ # :include: ../doc/csv/options/parsing/skip_lines.rdoc
381
381
  #
382
- # :include: ../doc/options/parsing/strip.rdoc
382
+ # :include: ../doc/csv/options/parsing/strip.rdoc
383
383
  #
384
- # :include: ../doc/options/parsing/liberal_parsing.rdoc
384
+ # :include: ../doc/csv/options/parsing/liberal_parsing.rdoc
385
385
  #
386
- # :include: ../doc/options/parsing/nil_value.rdoc
386
+ # :include: ../doc/csv/options/parsing/nil_value.rdoc
387
387
  #
388
- # :include: ../doc/options/parsing/empty_value.rdoc
388
+ # :include: ../doc/csv/options/parsing/empty_value.rdoc
389
389
  #
390
390
  # ==== Options for Generating
391
391
  #
@@ -400,23 +400,23 @@ using CSV::MatchP if CSV.const_defined?(:MatchP)
400
400
  # - +write_nil_value+: Specifies the object that is to be substituted for each +nil+-valued field.
401
401
  # - +write_empty_value+: Specifies the object that is to be substituted for each empty field.
402
402
  #
403
- # :include: ../doc/options/common/row_sep.rdoc
403
+ # :include: ../doc/csv/options/common/row_sep.rdoc
404
404
  #
405
- # :include: ../doc/options/common/col_sep.rdoc
405
+ # :include: ../doc/csv/options/common/col_sep.rdoc
406
406
  #
407
- # :include: ../doc/options/common/quote_char.rdoc
407
+ # :include: ../doc/csv/options/common/quote_char.rdoc
408
408
  #
409
- # :include: ../doc/options/generating/write_headers.rdoc
409
+ # :include: ../doc/csv/options/generating/write_headers.rdoc
410
410
  #
411
- # :include: ../doc/options/generating/force_quotes.rdoc
411
+ # :include: ../doc/csv/options/generating/force_quotes.rdoc
412
412
  #
413
- # :include: ../doc/options/generating/quote_empty.rdoc
413
+ # :include: ../doc/csv/options/generating/quote_empty.rdoc
414
414
  #
415
- # :include: ../doc/options/generating/write_converters.rdoc
415
+ # :include: ../doc/csv/options/generating/write_converters.rdoc
416
416
  #
417
- # :include: ../doc/options/generating/write_nil_value.rdoc
417
+ # :include: ../doc/csv/options/generating/write_nil_value.rdoc
418
418
  #
419
- # :include: ../doc/options/generating/write_empty_value.rdoc
419
+ # :include: ../doc/csv/options/generating/write_empty_value.rdoc
420
420
  #
421
421
  # === \CSV with Headers
422
422
  #
@@ -1075,7 +1075,7 @@ class CSV
1075
1075
  # Calls the block with each row read from source +path+ or +io+.
1076
1076
  #
1077
1077
  # * Argument +path+, if given, must be the path to a file.
1078
- # :include: ../doc/arguments/io.rdoc
1078
+ # :include: ../doc/csv/arguments/io.rdoc
1079
1079
  # * Argument +mode+, if given, must be a \File mode
1080
1080
  # See {Open Mode}[IO.html#method-c-new-label-Open+Mode].
1081
1081
  # * Arguments <tt>**options</tt> must be keyword options.
@@ -1322,7 +1322,7 @@ class CSV
1322
1322
  # :replace => string # replacement string ("?" or "\uFFFD" if not specified)
1323
1323
  #
1324
1324
  # * Argument +path+, if given, must be the path to a file.
1325
- # :include: ../doc/arguments/io.rdoc
1325
+ # :include: ../doc/csv/arguments/io.rdoc
1326
1326
  # * Argument +mode+, if given, must be a \File mode
1327
1327
  # See {Open Mode}[IO.html#method-c-new-label-Open+Mode].
1328
1328
  # * Arguments <tt>**options</tt> must be keyword options.
@@ -1427,7 +1427,7 @@ class CSV
1427
1427
  #
1428
1428
  # - Argument +string+ should be a \String object;
1429
1429
  # it will be put into a new StringIO object positioned at the beginning.
1430
- # :include: ../doc/arguments/io.rdoc
1430
+ # :include: ../doc/csv/arguments/io.rdoc
1431
1431
  # - Argument +options+: see {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
1432
1432
  #
1433
1433
  # ====== Without Option +headers+
@@ -1552,7 +1552,7 @@ class CSV
1552
1552
  #
1553
1553
  # - Argument +string+ should be a \String object;
1554
1554
  # it will be put into a new StringIO object positioned at the beginning.
1555
- # :include: ../doc/arguments/io.rdoc
1555
+ # :include: ../doc/csv/arguments/io.rdoc
1556
1556
  # - Argument +options+: see {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
1557
1557
  #
1558
1558
  # ====== Without Option +headers+
@@ -1672,7 +1672,7 @@ class CSV
1672
1672
  #
1673
1673
  # - Argument +string+ should be a \String object;
1674
1674
  # it will be put into a new StringIO object positioned at the beginning.
1675
- # :include: ../doc/arguments/io.rdoc
1675
+ # :include: ../doc/csv/arguments/io.rdoc
1676
1676
  # - Argument +options+: See:
1677
1677
  # * {Options for Parsing}[#class-CSV-label-Options+for+Parsing]
1678
1678
  # * {Options for Generating}[#class-CSV-label-Options+for+Generating]
@@ -2080,7 +2080,7 @@ class CSV
2080
2080
  ### End Delegation ###
2081
2081
 
2082
2082
  # :call-seq:
2083
- # csv.<< row
2083
+ # csv << row -> self
2084
2084
  #
2085
2085
  # Appends a row to +self+.
2086
2086
  #
@@ -2120,7 +2120,7 @@ class CSV
2120
2120
  # csv << :foo
2121
2121
  # end
2122
2122
  #
2123
- # Raises an exception if the output stream is not open for writing:
2123
+ # Raises an exception if the output stream is not opened for writing:
2124
2124
  # path = 't.csv'
2125
2125
  # File.write(path, '')
2126
2126
  # File.open(path) do |file|
@@ -2272,25 +2272,57 @@ class CSV
2272
2272
 
2273
2273
  include Enumerable
2274
2274
 
2275
+ # :call-seq:
2276
+ # csv.each -> enumerator
2277
+ # csv.each {|row| ...}
2275
2278
  #
2276
- # Yields each row of the data source in turn.
2279
+ # Calls the block with each successive row.
2280
+ # The data source must be opened for reading.
2277
2281
  #
2278
- # Support for Enumerable.
2282
+ # Without headers:
2283
+ # string = "foo,0\nbar,1\nbaz,2\n"
2284
+ # csv = CSV.new(string)
2285
+ # csv.each do |row|
2286
+ # p row
2287
+ # end
2288
+ # Output:
2289
+ # ["foo", "0"]
2290
+ # ["bar", "1"]
2291
+ # ["baz", "2"]
2279
2292
  #
2280
- # The data source must be open for reading.
2293
+ # With headers:
2294
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2295
+ # csv = CSV.new(string, headers: true)
2296
+ # csv.each do |row|
2297
+ # p row
2298
+ # end
2299
+ # Output:
2300
+ # <CSV::Row "Name":"foo" "Value":"0">
2301
+ # <CSV::Row "Name":"bar" "Value":"1">
2302
+ # <CSV::Row "Name":"baz" "Value":"2">
2303
+ #
2304
+ # ---
2281
2305
  #
2306
+ # Raises an exception if the source is not opened for reading:
2307
+ # string = "foo,0\nbar,1\nbaz,2\n"
2308
+ # csv = CSV.new(string)
2309
+ # csv.close
2310
+ # # Raises IOError (not opened for reading)
2311
+ # csv.each do |row|
2312
+ # p row
2313
+ # end
2282
2314
  def each(&block)
2283
2315
  parser_enumerator.each(&block)
2284
2316
  end
2285
2317
 
2286
2318
  # :call-seq:
2287
- # read
2319
+ # csv.read -> array or csv_table
2288
2320
  #
2289
2321
  # Forms the remaining rows from +self+ into:
2290
2322
  # - A CSV::Table object, if headers are in use.
2291
- # - An Array of Arrays, otherwise.
2323
+ # - An \Array of Arrays, otherwise.
2292
2324
  #
2293
- # The data source must be open for reading.
2325
+ # The data source must be opened for reading.
2294
2326
  #
2295
2327
  # Without headers:
2296
2328
  # string = "foo,0\nbar,1\nbaz,2\n"
@@ -2305,6 +2337,15 @@ class CSV
2305
2337
  # File.write(path, string)
2306
2338
  # csv = CSV.open(path, headers: true)
2307
2339
  # csv.read # => #<CSV::Table mode:col_or_row row_count:4>
2340
+ #
2341
+ # ---
2342
+ #
2343
+ # Raises an exception if the source is not opened for reading:
2344
+ # string = "foo,0\nbar,1\nbaz,2\n"
2345
+ # csv = CSV.new(string)
2346
+ # csv.close
2347
+ # # Raises IOError (not opened for reading)
2348
+ # csv.read
2308
2349
  def read
2309
2350
  rows = to_a
2310
2351
  if parser.use_headers?
@@ -2315,18 +2356,69 @@ class CSV
2315
2356
  end
2316
2357
  alias_method :readlines, :read
2317
2358
 
2318
- # Returns +true+ if the next row read will be a header row.
2359
+ # :call-seq:
2360
+ # csv.header_row? -> true or false
2361
+ #
2362
+ # Returns +true+ if the next row to be read is a header row\;
2363
+ # +false+ otherwise.
2364
+ #
2365
+ # Without headers:
2366
+ # string = "foo,0\nbar,1\nbaz,2\n"
2367
+ # csv = CSV.new(string)
2368
+ # csv.header_row? # => false
2369
+ #
2370
+ # With headers:
2371
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2372
+ # csv = CSV.new(string, headers: true)
2373
+ # csv.header_row? # => true
2374
+ # csv.shift # => #<CSV::Row "Name":"foo" "Value":"0">
2375
+ # csv.header_row? # => false
2376
+ #
2377
+ # ---
2378
+ #
2379
+ # Raises an exception if the source is not opened for reading:
2380
+ # string = "foo,0\nbar,1\nbaz,2\n"
2381
+ # csv = CSV.new(string)
2382
+ # csv.close
2383
+ # # Raises IOError (not opened for reading)
2384
+ # csv.header_row?
2319
2385
  def header_row?
2320
2386
  parser.header_row?
2321
2387
  end
2322
2388
 
2389
+ # :call-seq:
2390
+ # csv.shift -> array, csv_row, or nil
2323
2391
  #
2324
- # The primary read method for wrapped Strings and IOs, a single row is pulled
2325
- # from the data source, parsed and returned as an Array of fields (if header
2326
- # rows are not used) or a CSV::Row (when header rows are used).
2392
+ # Returns the next row of data as:
2393
+ # - An \Array if no headers are used.
2394
+ # - A CSV::Row object if headers are used.
2327
2395
  #
2328
- # The data source must be open for reading.
2396
+ # The data source must be opened for reading.
2329
2397
  #
2398
+ # Without headers:
2399
+ # string = "foo,0\nbar,1\nbaz,2\n"
2400
+ # csv = CSV.new(string)
2401
+ # csv.shift # => ["foo", "0"]
2402
+ # csv.shift # => ["bar", "1"]
2403
+ # csv.shift # => ["baz", "2"]
2404
+ # csv.shift # => nil
2405
+ #
2406
+ # With headers:
2407
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2408
+ # csv = CSV.new(string, headers: true)
2409
+ # csv.shift # => #<CSV::Row "Name":"foo" "Value":"0">
2410
+ # csv.shift # => #<CSV::Row "Name":"bar" "Value":"1">
2411
+ # csv.shift # => #<CSV::Row "Name":"baz" "Value":"2">
2412
+ # csv.shift # => nil
2413
+ #
2414
+ # ---
2415
+ #
2416
+ # Raises an exception if the source is not opened for reading:
2417
+ # string = "foo,0\nbar,1\nbaz,2\n"
2418
+ # csv = CSV.new(string)
2419
+ # csv.close
2420
+ # # Raises IOError (not opened for reading)
2421
+ # csv.shift
2330
2422
  def shift
2331
2423
  if @eof_error
2332
2424
  eof_error, @eof_error = @eof_error, nil
@@ -2341,10 +2433,14 @@ class CSV
2341
2433
  alias_method :gets, :shift
2342
2434
  alias_method :readline, :shift
2343
2435
 
2436
+ # :call-seq:
2437
+ # csv.inspect -> string
2344
2438
  #
2345
- # Returns a simplified description of the key CSV attributes in an
2346
- # ASCII compatible String.
2347
- #
2439
+ # Returns a \String showing certain properties of +self+:
2440
+ # string = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
2441
+ # csv = CSV.new(string, headers: true)
2442
+ # s = csv.inspect
2443
+ # s # => "#<CSV io_type:StringIO encoding:UTF-8 lineno:0 col_sep:\",\" row_sep:\"\\n\" quote_char:\"\\\"\" headers:true>"
2348
2444
  def inspect
2349
2445
  str = ["#<", self.class.to_s, " io_type:"]
2350
2446
  # show type of wrapped IO
@@ -3,31 +3,199 @@
3
3
  require "forwardable"
4
4
 
5
5
  class CSV
6
+ # = \CSV::Table
7
+ # A \CSV::Table instance is an object representing \CSV data.
8
+ # (see {class CSV}[../CSV.html]).
6
9
  #
7
- # A CSV::Table is a two-dimensional data structure for representing CSV
8
- # documents. Tables allow you to work with the data by row or column,
9
- # manipulate the data, and even convert the results back to CSV, if needed.
10
+ # The instance may have:
11
+ # - Rows: each is a Table::Row object.
12
+ # - Headers: names for the columns.
10
13
  #
11
- # All tables returned by CSV will be constructed from this class, if header
12
- # row processing is activated.
14
+ # === Instance Methods
13
15
  #
16
+ # \CSV::Table has three groups of instance methods:
17
+ # - Its own internally defined instance methods.
18
+ # - Methods included by module Enumerable.
19
+ # - Methods delegated to class Array.:
20
+ # * Array#empty?
21
+ # * Array#length
22
+ # * Array#size
23
+ #
24
+ # == Creating a \CSV::Table Instance
25
+ #
26
+ # Commonly, a new \CSV::Table instance is created by parsing \CSV source
27
+ # using headers:
28
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
29
+ # table = CSV.parse(source, headers: true)
30
+ # table.class # => CSV::Table
31
+ #
32
+ # You can also create an instance directly. See ::new.
33
+ #
34
+ # == Headers
35
+ #
36
+ # If a table has headers, the headers serve as labels for the columns of data.
37
+ # Each header serves as the label for its column.
38
+ #
39
+ # The headers for a \CSV::Table object are stored as an \Array of Strings.
40
+ #
41
+ # Commonly, headers are defined in the first row of \CSV source:
42
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
43
+ # table = CSV.parse(source, headers: true)
44
+ # table.headers # => ["Name", "Value"]
45
+ #
46
+ # If no headers are defined, the \Array is empty:
47
+ # table = CSV::Table.new([])
48
+ # table.headers # => []
49
+ #
50
+ # == Access Modes
51
+ #
52
+ # \CSV::Table provides three modes for accessing table data:
53
+ # - \Row mode.
54
+ # - Column mode.
55
+ # - Mixed mode (the default for a new table).
56
+ #
57
+ # The access mode for a\CSV::Table instance affects the behavior
58
+ # of some of its instance methods:
59
+ # - #[]
60
+ # - #[]=
61
+ # - #delete
62
+ # - #delete_if
63
+ # - #each
64
+ # - #values_at
65
+ #
66
+ # === \Row Mode
67
+ #
68
+ # Set a table to row mode with method #by_row!:
69
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
70
+ # table = CSV.parse(source, headers: true)
71
+ # table.by_row! # => #<CSV::Table mode:row row_count:4>
72
+ #
73
+ # Specify a single row by an \Integer index:
74
+ # # Get a row.
75
+ # table[1] # => #<CSV::Row "Name":"bar" "Value":"1">
76
+ # # Set a row, then get it.
77
+ # table[1] = CSV::Row.new(['Name', 'Value'], ['bam', 3])
78
+ # table[1] # => #<CSV::Row "Name":"bam" "Value":3>
79
+ #
80
+ # Specify a sequence of rows by a \Range:
81
+ # # Get rows.
82
+ # table[1..2] # => [#<CSV::Row "Name":"bam" "Value":3>, #<CSV::Row "Name":"baz" "Value":"2">]
83
+ # # Set rows, then get them.
84
+ # table[1..2] = [
85
+ # CSV::Row.new(['Name', 'Value'], ['bat', 4]),
86
+ # CSV::Row.new(['Name', 'Value'], ['bad', 5]),
87
+ # ]
88
+ # table[1..2] # => [["Name", #<CSV::Row "Name":"bat" "Value":4>], ["Value", #<CSV::Row "Name":"bad" "Value":5>]]
89
+ #
90
+ # === Column Mode
91
+ #
92
+ # Set a table to column mode with method #by_col!:
93
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
94
+ # table = CSV.parse(source, headers: true)
95
+ # table.by_col! # => #<CSV::Table mode:col row_count:4>
96
+ #
97
+ # Specify a column by an \Integer index:
98
+ # # Get a column.
99
+ # table[0]
100
+ # # Set a column, then get it.
101
+ # table[0] = ['FOO', 'BAR', 'BAZ']
102
+ # table[0] # => ["FOO", "BAR", "BAZ"]
103
+ #
104
+ # Specify a column by its \String header:
105
+ # # Get a column.
106
+ # table['Name'] # => ["FOO", "BAR", "BAZ"]
107
+ # # Set a column, then get it.
108
+ # table['Name'] = ['Foo', 'Bar', 'Baz']
109
+ # table['Name'] # => ["Foo", "Bar", "Baz"]
110
+ #
111
+ # === Mixed Mode
112
+ #
113
+ # In mixed mode, you can refer to either rows or columns:
114
+ # - An \Integer index refers to a row.
115
+ # - A \Range index refers to multiple rows.
116
+ # - A \String index refers to a column.
117
+ #
118
+ # Set a table to mixed mode with method #by_col_or_row!:
119
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
120
+ # table = CSV.parse(source, headers: true)
121
+ # table.by_col_or_row! # => #<CSV::Table mode:col_or_row row_count:4>
122
+ #
123
+ # Specify a single row by an \Integer index:
124
+ # # Get a row.
125
+ # table[1] # => #<CSV::Row "Name":"bar" "Value":"1">
126
+ # # Set a row, then get it.
127
+ # table[1] = CSV::Row.new(['Name', 'Value'], ['bam', 3])
128
+ # table[1] # => #<CSV::Row "Name":"bam" "Value":3>
129
+ #
130
+ # Specify a sequence of rows by a \Range:
131
+ # # Get rows.
132
+ # table[1..2] # => [#<CSV::Row "Name":"bam" "Value":3>, #<CSV::Row "Name":"baz" "Value":"2">]
133
+ # # Set rows, then get them.
134
+ # table[1] = CSV::Row.new(['Name', 'Value'], ['bat', 4])
135
+ # table[2] = CSV::Row.new(['Name', 'Value'], ['bad', 5])
136
+ # table[1..2] # => [["Name", #<CSV::Row "Name":"bat" "Value":4>], ["Value", #<CSV::Row "Name":"bad" "Value":5>]]
137
+ #
138
+ # Specify a column by its \String header:
139
+ # # Get a column.
140
+ # table['Name'] # => ["foo", "bat", "bad"]
141
+ # # Set a column, then get it.
142
+ # table['Name'] = ['Foo', 'Bar', 'Baz']
143
+ # table['Name'] # => ["Foo", "Bar", "Baz"]
14
144
  class Table
15
- #
16
- # Constructs a new CSV::Table from +array_of_rows+, which are expected
17
- # to be CSV::Row objects. All rows are assumed to have the same headers.
18
- #
19
- # The optional +headers+ parameter can be set to Array of headers.
20
- # If headers aren't set, headers are fetched from CSV::Row objects.
21
- # Otherwise, headers() method will return headers being set in
22
- # headers argument.
23
- #
24
- # A CSV::Table object supports the following Array methods through
25
- # delegation:
26
- #
27
- # * empty?()
28
- # * length()
29
- # * size()
30
- #
145
+ # :call-seq:
146
+ # CSV::Table.new(array_of_rows, headers = nil)
147
+ #
148
+ # Returns a new \CSV::Table object.
149
+ #
150
+ # - Argument +array_of_rows+ must be an \Array of CSV::Row objects.
151
+ # - Argument +headers+, if given, may be an \Array of Strings.
152
+ #
153
+ # ---
154
+ #
155
+ # Create an empty \CSV::Table object:
156
+ # table = CSV::Table.new([])
157
+ # table # => #<CSV::Table mode:col_or_row row_count:1>
158
+ #
159
+ # Create a non-empty \CSV::Table object:
160
+ # rows = [
161
+ # CSV::Row.new([], []),
162
+ # CSV::Row.new([], []),
163
+ # CSV::Row.new([], []),
164
+ # ]
165
+ # table = CSV::Table.new(rows)
166
+ # table # => #<CSV::Table mode:col_or_row row_count:4>
167
+ #
168
+ # ---
169
+ #
170
+ # If argument +headers+ is an \Array of Strings,
171
+ # those Strings become the table's headers:
172
+ # table = CSV::Table.new([], headers: ['Name', 'Age'])
173
+ # table.headers # => ["Name", "Age"]
174
+ #
175
+ # If argument +headers+ is not given and the table has rows,
176
+ # the headers are taken from the first row:
177
+ # rows = [
178
+ # CSV::Row.new(['Foo', 'Bar'], []),
179
+ # CSV::Row.new(['foo', 'bar'], []),
180
+ # CSV::Row.new(['FOO', 'BAR'], []),
181
+ # ]
182
+ # table = CSV::Table.new(rows)
183
+ # table.headers # => ["Foo", "Bar"]
184
+ #
185
+ # If argument +headers+ is not given and the table is empty (has no rows),
186
+ # the headers are also empty:
187
+ # table = CSV::Table.new([])
188
+ # table.headers # => []
189
+ #
190
+ # ---
191
+ #
192
+ # Raises an exception if argument +array_of_rows+ is not an \Array object:
193
+ # # Raises NoMethodError (undefined method `first' for :foo:Symbol):
194
+ # CSV::Table.new(:foo)
195
+ #
196
+ # Raises an exception if an element of +array_of_rows+ is not a \CSV::Table object:
197
+ # # Raises NoMethodError (undefined method `headers' for :foo:Symbol):
198
+ # CSV::Table.new([:foo])
31
199
  def initialize(array_of_rows, headers: nil)
32
200
  @table = array_of_rows
33
201
  @headers = headers
@@ -54,88 +222,141 @@ class CSV
54
222
  extend Forwardable
55
223
  def_delegators :@table, :empty?, :length, :size
56
224
 
225
+ # :call-seq:
226
+ # table.by_col
57
227
  #
58
- # Returns a duplicate table object, in column mode. This is handy for
59
- # chaining in a single call without changing the table mode, but be aware
60
- # that this method can consume a fair amount of memory for bigger data sets.
228
+ # Returns a duplicate of +self+, in column mode
229
+ # (see {Column Mode}[#class-CSV::Table-label-Column+Mode]):
230
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
231
+ # table = CSV.parse(source, headers: true)
232
+ # table.mode # => :col_or_row
233
+ # dup_table = table.by_col
234
+ # dup_table.mode # => :col
235
+ # dup_table.equal?(table) # => false # It's a dup
61
236
  #
62
- # This method returns the duplicate table for chaining. Don't chain
63
- # destructive methods (like []=()) this way though, since you are working
64
- # with a duplicate.
237
+ # This may be used to chain method calls without changing the mode
238
+ # (but also will affect performance and memory usage):
239
+ # dup_table.by_col['Name']
65
240
  #
241
+ # Also note that changes to the duplicate table will not affect the original.
66
242
  def by_col
67
243
  self.class.new(@table.dup).by_col!
68
244
  end
69
245
 
70
- #
71
- # Switches the mode of this table to column mode. All calls to indexing and
72
- # iteration methods will work with columns until the mode is changed again.
73
- #
74
- # This method returns the table and is safe to chain.
75
- #
246
+ # :call-seq:
247
+ # table.by_col!
248
+ #
249
+ # Sets the mode for +self+ to column mode
250
+ # (see {Column Mode}[#class-CSV::Table-label-Column+Mode]); returns +self+:
251
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
252
+ # table = CSV.parse(source, headers: true)
253
+ # table.mode # => :col_or_row
254
+ # table1 = table.by_col!
255
+ # table.mode # => :col
256
+ # table1.equal?(table) # => true # Returned self
76
257
  def by_col!
77
258
  @mode = :col
78
259
 
79
260
  self
80
261
  end
81
262
 
263
+ # :call-seq:
264
+ # table.by_col_or_row
82
265
  #
83
- # Returns a duplicate table object, in mixed mode. This is handy for
84
- # chaining in a single call without changing the table mode, but be aware
85
- # that this method can consume a fair amount of memory for bigger data sets.
266
+ # Returns a duplicate of +self+, in mixed mode
267
+ # (see {Mixed Mode}[#class-CSV::Table-label-Mixed+Mode]):
268
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
269
+ # table = CSV.parse(source, headers: true).by_col!
270
+ # table.mode # => :col
271
+ # dup_table = table.by_col_or_row
272
+ # dup_table.mode # => :col_or_row
273
+ # dup_table.equal?(table) # => false # It's a dup
86
274
  #
87
- # This method returns the duplicate table for chaining. Don't chain
88
- # destructive methods (like []=()) this way though, since you are working
89
- # with a duplicate.
275
+ # This may be used to chain method calls without changing the mode
276
+ # (but also will affect performance and memory usage):
277
+ # dup_table.by_col_or_row['Name']
90
278
  #
279
+ # Also note that changes to the duplicate table will not affect the original.
91
280
  def by_col_or_row
92
281
  self.class.new(@table.dup).by_col_or_row!
93
282
  end
94
283
 
95
- #
96
- # Switches the mode of this table to mixed mode. All calls to indexing and
97
- # iteration methods will use the default intelligent indexing system until
98
- # the mode is changed again. In mixed mode an index is assumed to be a row
99
- # reference while anything else is assumed to be column access by headers.
100
- #
101
- # This method returns the table and is safe to chain.
102
- #
284
+ # :call-seq:
285
+ # table.by_col_or_row!
286
+ #
287
+ # Sets the mode for +self+ to mixed mode
288
+ # (see {Mixed Mode}[#class-CSV::Table-label-Mixed+Mode]); returns +self+:
289
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
290
+ # table = CSV.parse(source, headers: true).by_col!
291
+ # table.mode # => :col
292
+ # table1 = table.by_col_or_row!
293
+ # table.mode # => :col_or_row
294
+ # table1.equal?(table) # => true # Returned self
103
295
  def by_col_or_row!
104
296
  @mode = :col_or_row
105
297
 
106
298
  self
107
299
  end
108
300
 
301
+ # :call-seq:
302
+ # table.by_row
109
303
  #
110
- # Returns a duplicate table object, in row mode. This is handy for chaining
111
- # in a single call without changing the table mode, but be aware that this
112
- # method can consume a fair amount of memory for bigger data sets.
304
+ # Returns a duplicate of +self+, in row mode
305
+ # (see {Row Mode}[#class-CSV::Table-label-Row+Mode]):
306
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
307
+ # table = CSV.parse(source, headers: true)
308
+ # table.mode # => :col_or_row
309
+ # dup_table = table.by_row
310
+ # dup_table.mode # => :row
311
+ # dup_table.equal?(table) # => false # It's a dup
113
312
  #
114
- # This method returns the duplicate table for chaining. Don't chain
115
- # destructive methods (like []=()) this way though, since you are working
116
- # with a duplicate.
313
+ # This may be used to chain method calls without changing the mode
314
+ # (but also will affect performance and memory usage):
315
+ # dup_table.by_row[1]
117
316
  #
317
+ # Also note that changes to the duplicate table will not affect the original.
118
318
  def by_row
119
319
  self.class.new(@table.dup).by_row!
120
320
  end
121
321
 
122
- #
123
- # Switches the mode of this table to row mode. All calls to indexing and
124
- # iteration methods will work with rows until the mode is changed again.
125
- #
126
- # This method returns the table and is safe to chain.
127
- #
322
+ # :call-seq:
323
+ # table.by_row!
324
+ #
325
+ # Sets the mode for +self+ to row mode
326
+ # (see {Row Mode}[#class-CSV::Table-label-Row+Mode]); returns +self+:
327
+ # source = "Name,Value\nfoo,0\nbar,1\nbaz,2\n"
328
+ # table = CSV.parse(source, headers: true)
329
+ # table.mode # => :col_or_row
330
+ # table1 = table.by_row!
331
+ # table.mode # => :row
332
+ # table1.equal?(table) # => true # Returned self
128
333
  def by_row!
129
334
  @mode = :row
130
335
 
131
336
  self
132
337
  end
133
338
 
134
- #
135
- # Returns the headers for the first row of this table (assumed to match all
136
- # other rows). The headers Array passed to CSV::Table.new is returned for
137
- # empty tables.
138
- #
339
+ # :call-seq:
340
+ # table.headers
341
+ #
342
+ # Returns a new \Array containing the \String headers for the table.
343
+ #
344
+ # If the table is not empty, returns the headers from the first row:
345
+ # rows = [
346
+ # CSV::Row.new(['Foo', 'Bar'], []),
347
+ # CSV::Row.new(['FOO', 'BAR'], []),
348
+ # CSV::Row.new(['foo', 'bar'], []),
349
+ # ]
350
+ # table = CSV::Table.new(rows)
351
+ # table.headers # => ["Foo", "Bar"]
352
+ # table.delete(0)
353
+ # table.headers # => ["FOO", "BAR"]
354
+ # table.delete(0)
355
+ # table.headers # => ["foo", "bar"]
356
+ #
357
+ # If the table is empty, returns a copy of the headers in the table itself:
358
+ # table.delete(0)
359
+ # table.headers # => ["Foo", "Bar"]
139
360
  def headers
140
361
  if @table.empty?
141
362
  @headers.dup
@@ -2,5 +2,5 @@
2
2
 
3
3
  class CSV
4
4
  # The version of the installed library.
5
- VERSION = "3.1.6"
5
+ VERSION = "3.1.7"
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.6
4
+ version: 3.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Edward Gray II
@@ -9,22 +9,8 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-07-19 00:00:00.000000000 Z
12
+ date: 2020-08-04 00:00:00.000000000 Z
13
13
  dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: stringio
16
- requirement: !ruby/object:Gem::Requirement
17
- requirements:
18
- - - ">="
19
- - !ruby/object:Gem::Version
20
- version: 0.1.3
21
- type: :runtime
22
- prerelease: false
23
- version_requirements: !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- version: 0.1.3
28
14
  - !ruby/object:Gem::Dependency
29
15
  name: bundler
30
16
  requirement: !ruby/object:Gem::Requirement
@@ -97,28 +83,28 @@ files:
97
83
  - LICENSE.txt
98
84
  - NEWS.md
99
85
  - README.md
100
- - doc/arguments/io.rdoc
101
- - doc/options/common/col_sep.rdoc
102
- - doc/options/common/quote_char.rdoc
103
- - doc/options/common/row_sep.rdoc
104
- - doc/options/generating/force_quotes.rdoc
105
- - doc/options/generating/quote_empty.rdoc
106
- - doc/options/generating/write_converters.rdoc
107
- - doc/options/generating/write_empty_value.rdoc
108
- - doc/options/generating/write_headers.rdoc
109
- - doc/options/generating/write_nil_value.rdoc
110
- - doc/options/parsing/converters.rdoc
111
- - doc/options/parsing/empty_value.rdoc
112
- - doc/options/parsing/field_size_limit.rdoc
113
- - doc/options/parsing/header_converters.rdoc
114
- - doc/options/parsing/headers.rdoc
115
- - doc/options/parsing/liberal_parsing.rdoc
116
- - doc/options/parsing/nil_value.rdoc
117
- - doc/options/parsing/return_headers.rdoc
118
- - doc/options/parsing/skip_blanks.rdoc
119
- - doc/options/parsing/skip_lines.rdoc
120
- - doc/options/parsing/strip.rdoc
121
- - doc/options/parsing/unconverted_fields.rdoc
86
+ - doc/csv/arguments/io.rdoc
87
+ - doc/csv/options/common/col_sep.rdoc
88
+ - doc/csv/options/common/quote_char.rdoc
89
+ - doc/csv/options/common/row_sep.rdoc
90
+ - doc/csv/options/generating/force_quotes.rdoc
91
+ - doc/csv/options/generating/quote_empty.rdoc
92
+ - doc/csv/options/generating/write_converters.rdoc
93
+ - doc/csv/options/generating/write_empty_value.rdoc
94
+ - doc/csv/options/generating/write_headers.rdoc
95
+ - doc/csv/options/generating/write_nil_value.rdoc
96
+ - doc/csv/options/parsing/converters.rdoc
97
+ - doc/csv/options/parsing/empty_value.rdoc
98
+ - doc/csv/options/parsing/field_size_limit.rdoc
99
+ - doc/csv/options/parsing/header_converters.rdoc
100
+ - doc/csv/options/parsing/headers.rdoc
101
+ - doc/csv/options/parsing/liberal_parsing.rdoc
102
+ - doc/csv/options/parsing/nil_value.rdoc
103
+ - doc/csv/options/parsing/return_headers.rdoc
104
+ - doc/csv/options/parsing/skip_blanks.rdoc
105
+ - doc/csv/options/parsing/skip_lines.rdoc
106
+ - doc/csv/options/parsing/strip.rdoc
107
+ - doc/csv/options/parsing/unconverted_fields.rdoc
122
108
  - lib/csv.rb
123
109
  - lib/csv/core_ext/array.rb
124
110
  - lib/csv/core_ext/string.rb
@@ -144,14 +130,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
144
130
  requirements:
145
131
  - - ">="
146
132
  - !ruby/object:Gem::Version
147
- version: 2.3.0
133
+ version: 2.5.0
148
134
  required_rubygems_version: !ruby/object:Gem::Requirement
149
135
  requirements:
150
136
  - - ">="
151
137
  - !ruby/object:Gem::Version
152
138
  version: '0'
153
139
  requirements: []
154
- rubygems_version: 3.2.0.pre1
140
+ rubygems_version: 3.2.0.rc.1
155
141
  signing_key:
156
142
  specification_version: 4
157
143
  summary: CSV Reading and Writing