csv 3.1.5 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/NEWS.md +110 -0
  3. data/README.md +5 -3
  4. data/doc/csv/arguments/io.rdoc +5 -0
  5. data/doc/csv/options/common/col_sep.rdoc +57 -0
  6. data/doc/csv/options/common/quote_char.rdoc +42 -0
  7. data/doc/{row_sep.rdoc → csv/options/common/row_sep.rdoc} +14 -14
  8. data/doc/{force_quotes.rdoc → csv/options/generating/force_quotes.rdoc} +0 -0
  9. data/doc/{quote_empty.rdoc → csv/options/generating/quote_empty.rdoc} +0 -0
  10. data/doc/{write_converters.rdoc → csv/options/generating/write_converters.rdoc} +6 -12
  11. data/doc/{write_empty_value.rdoc → csv/options/generating/write_empty_value.rdoc} +0 -0
  12. data/doc/{write_headers.rdoc → csv/options/generating/write_headers.rdoc} +0 -0
  13. data/doc/{write_nil_value.rdoc → csv/options/generating/write_nil_value.rdoc} +1 -1
  14. data/doc/csv/options/parsing/converters.rdoc +46 -0
  15. data/doc/{empty_value.rdoc → csv/options/parsing/empty_value.rdoc} +0 -0
  16. data/doc/{field_size_limit.rdoc → csv/options/parsing/field_size_limit.rdoc} +0 -0
  17. data/doc/csv/options/parsing/header_converters.rdoc +43 -0
  18. data/doc/{headers.rdoc → csv/options/parsing/headers.rdoc} +0 -0
  19. data/doc/{liberal_parsing.rdoc → csv/options/parsing/liberal_parsing.rdoc} +0 -0
  20. data/doc/{nil_value.rdoc → csv/options/parsing/nil_value.rdoc} +0 -0
  21. data/doc/{return_headers.rdoc → csv/options/parsing/return_headers.rdoc} +0 -0
  22. data/doc/{skip_blanks.rdoc → csv/options/parsing/skip_blanks.rdoc} +0 -0
  23. data/doc/{skip_lines.rdoc → csv/options/parsing/skip_lines.rdoc} +0 -0
  24. data/doc/{strip.rdoc → csv/options/parsing/strip.rdoc} +0 -0
  25. data/doc/{unconverted_fields.rdoc → csv/options/parsing/unconverted_fields.rdoc} +0 -0
  26. data/doc/csv/recipes/filtering.rdoc +158 -0
  27. data/doc/csv/recipes/generating.rdoc +298 -0
  28. data/doc/csv/recipes/parsing.rdoc +545 -0
  29. data/doc/csv/recipes/recipes.rdoc +6 -0
  30. data/lib/csv.rb +1604 -515
  31. data/lib/csv/parser.rb +1 -0
  32. data/lib/csv/row.rb +499 -132
  33. data/lib/csv/table.rb +753 -109
  34. data/lib/csv/version.rb +1 -1
  35. data/lib/csv/writer.rb +45 -4
  36. metadata +38 -28
  37. data/doc/col_sep.rdoc +0 -45
  38. data/doc/converters.rdoc +0 -45
  39. data/doc/header_converters.rdoc +0 -31
  40. data/doc/quote_char.rdoc +0 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eec352a246dc1189213c78e35541e9903f172889792b92a23d6b8d7215d9ae37
4
- data.tar.gz: 63754025784b9d6d26686b48efe8627b18c1aaa26e14f1261d14a09a4921612e
3
+ metadata.gz: c48c0d15454e002ff10270a9c56cf4311ce635a8a9dfb527f7a7541f29f801b2
4
+ data.tar.gz: 505d1d0dbb4cff0a544b2e00925cb1101ed71642a584d534f443405fba8bd820
5
5
  SHA512:
6
- metadata.gz: c1b9895d4735d3f7a1376765d8e71a03388d4b8f52ace5a8eab3126e1f3167f77fcfd312212fdbdbda496d4a2f837a966bf33b871bee96f633c536b566ce0a9f
7
- data.tar.gz: 9347baa988315b544d41ec23ded72a812dec09b7c0832c72bc4ff3be950e25d0f2184f9ed43967113ddb63e56e29c847bffb469b7883ad4207b913368057b58c
6
+ metadata.gz: 1c9ecd18d5b9a4f663c0676694ffc133a4657e2f7a07cafe2f0a5d9ddd2d7846f505bc62c21698fcf1117126efc6978b7aa1b497d2fef8d532a8a4246c58bff2
7
+ data.tar.gz: e4fe05b49f92c68c011060d1dcd39ead1785d886eabbd3689a12884df9eb30124694417314e39bcf656cd05d6d0dea6a80a701dd5fe6cac42efc33c67be54926
data/NEWS.md CHANGED
@@ -1,5 +1,115 @@
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
+
34
+ ## 3.1.9 - 2020-11-23
35
+
36
+ ### Fixes
37
+
38
+ * Fixed a compatibility bug that the line to be processed by
39
+ `skip_lines:` has a row separator.
40
+ [GitHub#194][Reported by Josef Šimánek]
41
+
42
+ ### Thanks
43
+
44
+ * Josef Šimánek
45
+
46
+ ## 3.1.8 - 2020-11-18
47
+
48
+ ### Improvements
49
+
50
+ * Improved documentation.
51
+ [Patch by Burdette Lamar]
52
+
53
+ ### Thanks
54
+
55
+ * Burdette Lamar
56
+
57
+ ## 3.1.7 - 2020-08-04
58
+
59
+ ### Improvements
60
+
61
+ * Improved document.
62
+ [GitHub#158][GitHub#160][GitHub#161]
63
+ [Patch by Burdette Lamar]
64
+
65
+ * Updated required Ruby version to 2.5.0 or later.
66
+ [GitHub#159]
67
+ [Patch by Gabriel Nagy]
68
+
69
+ * Removed stringio 0.1.3 or later dependency.
70
+
71
+ ### Thanks
72
+
73
+ * Burdette Lamar
74
+
75
+ * Gabriel Nagy
76
+
77
+ ## 3.1.6 - 2020-07-20
78
+
79
+ ### Improvements
80
+
81
+ * Improved document.
82
+ [GitHub#127][GitHub#135][GitHub#136][GitHub#137][GitHub#139][GitHub#140]
83
+ [GitHub#141][GitHub#142][GitHub#143][GitHub#145][GitHub#146][GitHub#148]
84
+ [GitHub#148][GitHub#151][GitHub#152][GitHub#154][GitHub#155][GitHub#157]
85
+ [Patch by Burdette Lamar]
86
+
87
+ * `CSV.open`: Added support for `undef: :replace`.
88
+ [GitHub#129][Patch by Koichi ITO]
89
+
90
+ * `CSV.open`: Added support for `invalid: :replace`.
91
+ [GitHub#129][Patch by Koichi ITO]
92
+
93
+ * Don't run quotable check for invalid encoding field values.
94
+ [GitHub#131][Patch by Koichi ITO]
95
+
96
+ * Added support for specifying the target indexes and names to
97
+ `force_quotes:`.
98
+ [GitHub#153][Reported by Aleksandr]
99
+
100
+ * `CSV.generate`: Changed to use the encoding of the first non-ASCII
101
+ field rather than the encoding of ASCII only field.
102
+
103
+ * Changed to require the stringio gem 0.1.3 or later.
104
+
105
+ ### Thanks
106
+
107
+ * Burdette Lamar
108
+
109
+ * Koichi ITO
110
+
111
+ * Aleksandr
112
+
3
113
  ## 3.1.5 - 2020-05-18
4
114
 
5
115
  ### Improvements
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
@@ -31,6 +28,11 @@ CSV.foreach("path/to/file.csv") do |row|
31
28
  end
32
29
  ```
33
30
 
31
+ ## Documentation
32
+
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.
35
+
34
36
  ## Development
35
37
 
36
38
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,5 @@
1
+ * Argument +io+ should be an IO object that is:
2
+ * Open for reading; on return, the IO object will be closed.
3
+ * Positioned at the beginning.
4
+ To position at the end, for appending, use method CSV.generate.
5
+ For any other positioning, pass a preset \StringIO object instead.
@@ -0,0 +1,57 @@
1
+ ====== Option +col_sep+
2
+
3
+ Specifies the \String column separator to be used
4
+ for both parsing and generating.
5
+ The \String will be transcoded into the data's \Encoding before use.
6
+
7
+ Default value:
8
+ CSV::DEFAULT_OPTIONS.fetch(:col_sep) # => "," (comma)
9
+
10
+ Using the default (comma):
11
+ str = CSV.generate do |csv|
12
+ csv << [:foo, 0]
13
+ csv << [:bar, 1]
14
+ csv << [:baz, 2]
15
+ end
16
+ str # => "foo,0\nbar,1\nbaz,2\n"
17
+ ary = CSV.parse(str)
18
+ ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
19
+
20
+ Using +:+ (colon):
21
+ col_sep = ':'
22
+ str = CSV.generate(col_sep: col_sep) do |csv|
23
+ csv << [:foo, 0]
24
+ csv << [:bar, 1]
25
+ csv << [:baz, 2]
26
+ end
27
+ str # => "foo:0\nbar:1\nbaz:2\n"
28
+ ary = CSV.parse(str, col_sep: col_sep)
29
+ ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
30
+
31
+ Using +::+ (two colons):
32
+ col_sep = '::'
33
+ str = CSV.generate(col_sep: col_sep) do |csv|
34
+ csv << [:foo, 0]
35
+ csv << [:bar, 1]
36
+ csv << [:baz, 2]
37
+ end
38
+ str # => "foo::0\nbar::1\nbaz::2\n"
39
+ ary = CSV.parse(str, col_sep: col_sep)
40
+ ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
41
+
42
+ Using <tt>''</tt> (empty string):
43
+ col_sep = ''
44
+ str = CSV.generate(col_sep: col_sep) do |csv|
45
+ csv << [:foo, 0]
46
+ csv << [:bar, 1]
47
+ csv << [:baz, 2]
48
+ end
49
+ str # => "foo0\nbar1\nbaz2\n"
50
+
51
+ ---
52
+
53
+ Raises an exception if parsing with the empty \String:
54
+ col_sep = ''
55
+ # Raises ArgumentError (:col_sep must be 1 or more characters: "")
56
+ CSV.parse("foo0\nbar1\nbaz2\n", col_sep: col_sep)
57
+
@@ -0,0 +1,42 @@
1
+ ====== Option +quote_char+
2
+
3
+ Specifies the character (\String of length 1) used used to quote fields
4
+ in both parsing and generating.
5
+ This String will be transcoded into the data's \Encoding before use.
6
+
7
+ Default value:
8
+ CSV::DEFAULT_OPTIONS.fetch(:quote_char) # => "\"" (double quote)
9
+
10
+ This is useful for an application that incorrectly uses <tt>'</tt> (single-quote)
11
+ to quote fields, instead of the correct <tt>"</tt> (double-quote).
12
+
13
+ Using the default (double quote):
14
+ str = CSV.generate do |csv|
15
+ csv << ['foo', 0]
16
+ csv << ["'bar'", 1]
17
+ csv << ['"baz"', 2]
18
+ end
19
+ str # => "foo,0\n'bar',1\n\"\"\"baz\"\"\",2\n"
20
+ ary = CSV.parse(str)
21
+ ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
22
+
23
+ Using <tt>'</tt> (single-quote):
24
+ quote_char = "'"
25
+ str = CSV.generate(quote_char: quote_char) do |csv|
26
+ csv << ['foo', 0]
27
+ csv << ["'bar'", 1]
28
+ csv << ['"baz"', 2]
29
+ end
30
+ str # => "foo,0\n'''bar''',1\n\"baz\",2\n"
31
+ ary = CSV.parse(str, quote_char: quote_char)
32
+ ary # => [["foo", "0"], ["'bar'", "1"], ["\"baz\"", "2"]]
33
+
34
+ ---
35
+
36
+ Raises an exception if the \String length is greater than 1:
37
+ # Raises ArgumentError (:quote_char has to be nil or a single character String)
38
+ CSV.new('', quote_char: 'xx')
39
+
40
+ Raises an exception if the value is not a \String:
41
+ # Raises ArgumentError (:quote_char has to be nil or a single character String)
42
+ CSV.new('', quote_char: :foo)
@@ -12,7 +12,8 @@ When +row_sep+ is a \String, that \String becomes the row separator.
12
12
  The String will be transcoded into the data's Encoding before use.
13
13
 
14
14
  Using <tt>"\n"</tt>:
15
- str = CSV.generate do |csv|
15
+ row_sep = "\n"
16
+ str = CSV.generate(row_sep: row_sep) do |csv|
16
17
  csv << [:foo, 0]
17
18
  csv << [:bar, 1]
18
19
  csv << [:baz, 2]
@@ -57,20 +58,28 @@ Using <tt>''</tt> (empty string):
57
58
  ---
58
59
 
59
60
  When +row_sep+ is the \Symbol +:auto+ (the default),
60
- invokes auto-discovery of the row separator.
61
+ generating uses <tt>"\n"</tt> as the row separator:
62
+ str = CSV.generate do |csv|
63
+ csv << [:foo, 0]
64
+ csv << [:bar, 1]
65
+ csv << [:baz, 2]
66
+ end
67
+ str # => "foo,0\nbar,1\nbaz,2\n"
68
+
69
+ Parsing, on the other hand, invokes auto-discovery of the row separator.
61
70
 
62
71
  Auto-discovery reads ahead in the data looking for the next <tt>\r\n</tt>, +\n+, or +\r+ sequence.
63
72
  The sequence will be selected even if it occurs in a quoted field,
64
73
  assuming that you would have the same line endings there.
65
74
 
66
- row_sep = :auto
67
- str = CSV.generate(row_sep: row_sep) do |csv|
75
+ Example:
76
+ str = CSV.generate do |csv|
68
77
  csv << [:foo, 0]
69
78
  csv << [:bar, 1]
70
79
  csv << [:baz, 2]
71
80
  end
72
81
  str # => "foo,0\nbar,1\nbaz,2\n"
73
- ary = CSV.parse(str, row_sep: row_sep)
82
+ ary = CSV.parse(str)
74
83
  ary # => [["foo", "0"], ["bar", "1"], ["baz", "2"]]
75
84
 
76
85
  The default <tt>$INPUT_RECORD_SEPARATOR</tt> (<tt>$/</tt>) is used
@@ -80,12 +89,3 @@ if any of the following is true:
80
89
  * The stream is only available for output.
81
90
 
82
91
  Obviously, discovery takes a little time. Set manually if speed is important. Also note that IO objects should be opened in binary mode on Windows if this feature will be used as the line-ending translation can cause problems with resetting the document position to where it was before the read ahead.
83
-
84
- ---
85
-
86
- Raises an exception if the given value is not String-convertible:
87
- row_sep = BasicObject.new
88
- # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
89
- CSV.generate_line(ary, row_sep: row_sep)
90
- # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
91
- CSV.parse(str, row_sep: row_sep)
@@ -1,7 +1,7 @@
1
1
  ====== Option +write_converters+
2
2
 
3
- Specifies the \Proc or \Array of Procs that are to be called
4
- for converting each output field.
3
+ Specifies converters to be used in generating fields.
4
+ See {Write Converters}[#class-CSV-label-Write+Converters]
5
5
 
6
6
  Default value:
7
7
  CSV::DEFAULT_OPTIONS.fetch(:write_converters) # => nil
@@ -11,21 +11,15 @@ With no write converter:
11
11
  str # => "\"\na\n\",\tb\t, c \n"
12
12
 
13
13
  With a write converter:
14
- strip_converter = lambda {|field| field.strip }
14
+ strip_converter = proc {|field| field.strip }
15
15
  str = CSV.generate_line(["\na\n", "\tb\t", " c "], write_converters: strip_converter)
16
16
  str # => "a,b,c\n"
17
17
 
18
18
  With two write converters (called in order):
19
- upcase_converter = lambda {|field| field.upcase }
20
- downcase_converter = lambda {|field| field.downcase }
19
+ upcase_converter = proc {|field| field.upcase }
20
+ downcase_converter = proc {|field| field.downcase }
21
21
  write_converters = [upcase_converter, downcase_converter]
22
22
  str = CSV.generate_line(['a', 'b', 'c'], write_converters: write_converters)
23
23
  str # => "a,b,c\n"
24
24
 
25
- ---
26
-
27
- Raises an exception if the converter returns a value that is neither +nil+
28
- nor \String-convertible:
29
- bad_converter = lambda {|field| BasicObject.new }
30
- # Raises NoMethodError (undefined method `is_a?' for #<BasicObject:>)
31
- CSV.generate_line(['a', 'b', 'c'], write_converters: bad_converter)
25
+ See also {Write Converters}[#class-CSV-label-Write+Converters]
@@ -1,6 +1,6 @@
1
1
  ====== Option +write_nil_value+
2
2
 
3
- Specifies the object that is to be substituted for each +nil+ field.
3
+ Specifies the object that is to be substituted for each +nil+-valued field.
4
4
 
5
5
  Default value:
6
6
  CSV::DEFAULT_OPTIONS.fetch(:write_nil_value) # => nil
@@ -0,0 +1,46 @@
1
+ ====== Option +converters+
2
+
3
+ Specifies converters to be used in parsing fields.
4
+ See {Field Converters}[#class-CSV-label-Field+Converters]
5
+
6
+ Default value:
7
+ CSV::DEFAULT_OPTIONS.fetch(:converters) # => nil
8
+
9
+ The value may be a field converter name
10
+ (see {Stored Converters}[#class-CSV-label-Stored+Converters]):
11
+ str = '1,2,3'
12
+ # Without a converter
13
+ array = CSV.parse_line(str)
14
+ array # => ["1", "2", "3"]
15
+ # With built-in converter :integer
16
+ array = CSV.parse_line(str, converters: :integer)
17
+ array # => [1, 2, 3]
18
+
19
+ The value may be a converter list
20
+ (see {Converter Lists}[#class-CSV-label-Converter+Lists]):
21
+ str = '1,3.14159'
22
+ # Without converters
23
+ array = CSV.parse_line(str)
24
+ array # => ["1", "3.14159"]
25
+ # With built-in converters
26
+ array = CSV.parse_line(str, converters: [:integer, :float])
27
+ array # => [1, 3.14159]
28
+
29
+ The value may be a \Proc custom converter:
30
+ (see {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters]):
31
+ str = ' foo , bar , baz '
32
+ # Without a converter
33
+ array = CSV.parse_line(str)
34
+ array # => [" foo ", " bar ", " baz "]
35
+ # With a custom converter
36
+ array = CSV.parse_line(str, converters: proc {|field| field.strip })
37
+ array # => ["foo", "bar", "baz"]
38
+
39
+ See also {Custom Field Converters}[#class-CSV-label-Custom+Field+Converters]
40
+
41
+ ---
42
+
43
+ Raises an exception if the converter is not a converter name or a \Proc:
44
+ str = 'foo,0'
45
+ # Raises NoMethodError (undefined method `arity' for nil:NilClass)
46
+ CSV.parse(str, converters: :foo)
@@ -0,0 +1,43 @@
1
+ ====== Option +header_converters+
2
+
3
+ Specifies converters to be used in parsing headers.
4
+ See {Header Converters}[#class-CSV-label-Header+Converters]
5
+
6
+ Default value:
7
+ CSV::DEFAULT_OPTIONS.fetch(:header_converters) # => nil
8
+
9
+ Identical in functionality to option {converters}[#class-CSV-label-Option+converters]
10
+ except that:
11
+ - The converters apply only to the header row.
12
+ - The built-in header converters are +:downcase+ and +:symbol+.
13
+
14
+ This section assumes prior execution of:
15
+ str = <<-EOT
16
+ Name,Value
17
+ foo,0
18
+ bar,1
19
+ baz,2
20
+ EOT
21
+ # With no header converter
22
+ table = CSV.parse(str, headers: true)
23
+ table.headers # => ["Name", "Value"]
24
+
25
+ The value may be a header converter name
26
+ (see {Stored Converters}[#class-CSV-label-Stored+Converters]):
27
+ table = CSV.parse(str, headers: true, header_converters: :downcase)
28
+ table.headers # => ["name", "value"]
29
+
30
+ The value may be a converter list
31
+ (see {Converter Lists}[#class-CSV-label-Converter+Lists]):
32
+ header_converters = [:downcase, :symbol]
33
+ table = CSV.parse(str, headers: true, header_converters: header_converters)
34
+ table.headers # => [:name, :value]
35
+
36
+ The value may be a \Proc custom converter
37
+ (see {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters]):
38
+ upcase_converter = proc {|field| field.upcase }
39
+ table = CSV.parse(str, headers: true, header_converters: upcase_converter)
40
+ table.headers # => ["NAME", "VALUE"]
41
+
42
+ See also {Custom Header Converters}[#class-CSV-label-Custom+Header+Converters]
43
+