iostreams 2.1.0 → 2.2.0
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/docs/config.md +13 -9
- data/docs/copy_files.md +20 -2
- data/docs/extensions.md +18 -4
- data/docs/formats.md +644 -16
- data/docs/path.md +18 -2
- data/docs/streams.md +54 -9
- data/docs/tutorial.md +14 -2
- data/docs/upgrading.md +470 -23
- data/lib/io_streams/builder/deprecations.rb +250 -0
- data/lib/io_streams/builder.rb +256 -39
- data/lib/io_streams/bzip2/reader.rb +18 -2
- data/lib/io_streams/bzip2/writer.rb +11 -2
- data/lib/io_streams/deprecation/methods.rb +51 -0
- data/lib/io_streams/deprecation/once.rb +27 -0
- data/lib/io_streams/deprecation/option_names.rb +26 -0
- data/lib/io_streams/deprecation/words.rb +42 -0
- data/lib/io_streams/deprecation.rb +259 -0
- data/lib/io_streams/encode/reader.rb +54 -3
- data/lib/io_streams/encode/writer.rb +19 -2
- data/lib/io_streams/encode.rb +99 -0
- data/lib/io_streams/errors.rb +51 -0
- data/lib/io_streams/gzip/reader.rb +11 -0
- data/lib/io_streams/io_streams.rb +365 -35
- data/lib/io_streams/line/reader.rb +2 -1
- data/lib/io_streams/line/utf8_reader.rb +23 -0
- data/lib/io_streams/path.rb +125 -35
- data/lib/io_streams/paths/file.rb +72 -9
- data/lib/io_streams/paths/http.rb +48 -2
- data/lib/io_streams/paths/matcher.rb +6 -3
- data/lib/io_streams/paths/s3.rb +180 -9
- data/lib/io_streams/paths/sftp.rb +47 -3
- data/lib/io_streams/paths.rb +23 -0
- data/lib/io_streams/pgp/reader.rb +18 -0
- data/lib/io_streams/pgp/writer.rb +16 -0
- data/lib/io_streams/pgp.rb +16 -2
- data/lib/io_streams/reader.rb +44 -0
- data/lib/io_streams/record/reader.rb +59 -68
- data/lib/io_streams/record/writer.rb +17 -10
- data/lib/io_streams/row/header_row.rb +21 -0
- data/lib/io_streams/row/reader.rb +52 -15
- data/lib/io_streams/row/writer.rb +64 -13
- data/lib/io_streams/schema/columns.rb +456 -0
- data/lib/io_streams/schema/constraints.rb +99 -0
- data/lib/io_streams/schema/field.rb +967 -0
- data/lib/io_streams/schema/json_number.rb +56 -0
- data/lib/io_streams/schema/keys.rb +78 -0
- data/lib/io_streams/schema/pattern.rb +257 -0
- data/lib/io_streams/schema/source.rb +31 -0
- data/lib/io_streams/schema.rb +616 -0
- data/lib/io_streams/stream.rb +836 -67
- data/lib/io_streams/symmetric_encryption/reader.rb +8 -0
- data/lib/io_streams/tabular/header.rb +29 -0
- data/lib/io_streams/tabular/header_mapping.rb +332 -0
- data/lib/io_streams/tabular/mapping.rb +165 -0
- data/lib/io_streams/tabular/parser/array.rb +5 -0
- data/lib/io_streams/tabular/parser/base.rb +24 -0
- data/lib/io_streams/tabular/parser/fixed.rb +197 -0
- data/lib/io_streams/tabular/parser/fixed_fields.rb +160 -0
- data/lib/io_streams/tabular/parser/hash.rb +10 -0
- data/lib/io_streams/tabular/parser/json.rb +17 -0
- data/lib/io_streams/tabular/parser/json_fields.rb +132 -0
- data/lib/io_streams/tabular/schema_mapping.rb +361 -0
- data/lib/io_streams/tabular.rb +344 -30
- data/lib/io_streams/utils.rb +441 -6
- data/lib/io_streams/version.rb +1 -1
- data/lib/io_streams/writer.rb +27 -0
- data/lib/io_streams/xlsx/cells.rb +127 -0
- data/lib/io_streams/xlsx/reader.rb +56 -0
- data/lib/io_streams/xlsx/schema_reader.rb +90 -0
- data/lib/io_streams/xlsx/v3_writer.rb +16 -0
- data/lib/io_streams/zip/reader.rb +7 -0
- data/lib/io_streams/zip/writer.rb +24 -2
- data/lib/iostreams.rb +21 -17
- metadata +28 -2
|
@@ -57,94 +57,85 @@ module IOStreams
|
|
|
57
57
|
# false:
|
|
58
58
|
# Raises Tabular::InvalidHeader when a column is supplied that is not in the whitelist.
|
|
59
59
|
#
|
|
60
|
+
# cleanse_header: [true|false]
|
|
61
|
+
# Whether to cleanse the header row read, see `IOStreams::Tabular::Header#cleanse!`, which the tabular that it
|
|
62
|
+
# creates does, see `IOStreams::Tabular.new`.
|
|
63
|
+
# With a schema it raises ArgumentError, even when nil, since the fields of the schema name the keys of the
|
|
64
|
+
# records instead.
|
|
65
|
+
# Default: cleanses it.
|
|
66
|
+
#
|
|
67
|
+
# tabular: [IOStreams::Tabular]
|
|
68
|
+
# The tabular that parses each line, such as one with a schema, see `IOStreams::Stream#schema`, in place of the
|
|
69
|
+
# other options, which create it.
|
|
70
|
+
#
|
|
71
|
+
# report_repeated_key: [true|false]
|
|
72
|
+
# Whether to report a deprecation warning, before the first record, when two columns of the header row are the
|
|
73
|
+
# same key, see #warn_repeated_key, which `IOStreams::Stream#each` and `#reader` ask for, rather than another
|
|
74
|
+
# gem that creates a reader, which its users cannot change.
|
|
75
|
+
# Default: false
|
|
76
|
+
#
|
|
60
77
|
# Note:
|
|
61
78
|
# * `allowed_columns`, `required_columns` and `skip_unknown` only apply to every input, including JSON records,
|
|
62
79
|
# supplied `columns` and `cleanse_header: false`, when `IOStreams.enforce_column_restrictions?` is true.
|
|
63
|
-
def initialize(line_reader,
|
|
80
|
+
def initialize(line_reader, original_file_name: nil, tabular: nil, report_repeated_key: false, **args)
|
|
64
81
|
unless line_reader.respond_to?(:each)
|
|
65
82
|
raise(ArgumentError, "Stream must be a IOStreams::Line::Reader or implement #each")
|
|
66
83
|
end
|
|
67
84
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
@warned = false
|
|
85
|
+
if tabular && (original_file_name || !args.empty?)
|
|
86
|
+
raise(ArgumentError, "Supply either tabular: or the options that create it, not both")
|
|
87
|
+
end
|
|
72
88
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
89
|
+
@tabular = tabular || IOStreams::Tabular.new(file_name: original_file_name, **args)
|
|
90
|
+
@line_reader = line_reader
|
|
91
|
+
@report_repeated_key = report_repeated_key
|
|
76
92
|
|
|
77
|
-
|
|
78
|
-
@
|
|
79
|
-
if @tabular.header?
|
|
80
|
-
@tabular.parse_header(line)
|
|
81
|
-
if @cleanse_header
|
|
82
|
-
cleanse_columns
|
|
83
|
-
elsif restricted?
|
|
84
|
-
restrict_columns
|
|
85
|
-
end
|
|
86
|
-
else
|
|
87
|
-
yield restrict(@tabular.record_parse(line))
|
|
88
|
-
end
|
|
89
|
-
end
|
|
93
|
+
# Supplied columns take the place of a header row, so apply the allowed and required columns to them.
|
|
94
|
+
@tabular.restrict_columns
|
|
90
95
|
end
|
|
91
96
|
|
|
92
|
-
|
|
97
|
+
# Yields each record, after the header row, which names their keys, see `IOStreams::Tabular#read_record_line`.
|
|
98
|
+
def each(&block)
|
|
99
|
+
return each_reporting(&block) if @report_repeated_key
|
|
93
100
|
|
|
94
|
-
|
|
95
|
-
@tabular.header.restricted?
|
|
101
|
+
@line_reader.each { |line| @tabular.read_record_line(line, &block) }
|
|
96
102
|
end
|
|
97
103
|
|
|
98
|
-
|
|
99
|
-
|
|
104
|
+
# Writes each record to the writer, see `IOStreams::Record::Writer`, as a copy with a schema does, see
|
|
105
|
+
# `IOStreams::Stream#copy_from`. A blank line, or a JSON line of null, which #each yields as nil, is not a record,
|
|
106
|
+
# so it is not written.
|
|
107
|
+
#
|
|
108
|
+
# Returns the result of #each.
|
|
109
|
+
def copy_to(writer)
|
|
110
|
+
each { |record| writer << record unless record.nil? }
|
|
100
111
|
end
|
|
101
112
|
|
|
102
|
-
|
|
103
|
-
# `cleanse_header: false`. Unless `IOStreams.enforce_column_restrictions?`, only warn when they would
|
|
104
|
-
# change the columns.
|
|
105
|
-
def restrict_columns
|
|
106
|
-
return cleanse_columns if IOStreams.enforce_column_restrictions?
|
|
107
|
-
return if @warned
|
|
113
|
+
private
|
|
108
114
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
)
|
|
118
|
-
copy.cleanse!(rename: @cleanse_header)
|
|
119
|
-
copy.columns != columns
|
|
115
|
+
# Yields each record, as #each does, after reporting a deprecation warning before the first one when two columns
|
|
116
|
+
# of the header row are the same key, see #warn_repeated_key.
|
|
117
|
+
def each_reporting
|
|
118
|
+
@line_reader.each do |line|
|
|
119
|
+
@tabular.read_record_line(line) do |record|
|
|
120
|
+
warn_repeated_key if @report_repeated_key
|
|
121
|
+
yield record
|
|
122
|
+
end
|
|
120
123
|
end
|
|
121
|
-
warn_restriction if changed
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
# Formats such as JSON have no header row, so apply the allowed and required columns to each record's keys.
|
|
125
|
-
# Unless `IOStreams.enforce_column_restrictions?`, only warn when they would change the record.
|
|
126
|
-
def restrict(record)
|
|
127
|
-
return record unless record.is_a?(Hash) && restricted? && @tabular.header.columns.nil?
|
|
128
|
-
return @tabular.header.restrict_hash(record, rename: @cleanse_header) if IOStreams.enforce_column_restrictions?
|
|
129
|
-
return record if @warned
|
|
130
|
-
|
|
131
|
-
warn_restriction if changed_by_restriction? { @tabular.header.restrict_hash(record, rename: @cleanse_header) != record }
|
|
132
|
-
record
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def changed_by_restriction?
|
|
136
|
-
yield
|
|
137
|
-
rescue IOStreams::Errors::InvalidHeader
|
|
138
|
-
true
|
|
139
124
|
end
|
|
140
125
|
|
|
141
|
-
#
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
126
|
+
# Reports a deprecation warning, once, when two columns of the header row are the same key, see
|
|
127
|
+
# `IOStreams::Tabular#repeated_key`, such as a header row of `a,a,b`, or of `A` and `a`, which are cleansed to the
|
|
128
|
+
# same key, since each record holds the value of only the last of them, while IOStreams v3.0 raises
|
|
129
|
+
# `IOStreams::Errors::InvalidHeader` for them, rather than lose the others.
|
|
130
|
+
def warn_repeated_key
|
|
131
|
+
@report_repeated_key = false
|
|
132
|
+
key = @tabular.repeated_key
|
|
133
|
+
return if key.nil?
|
|
134
|
+
|
|
135
|
+
Deprecation.warn("records read from a header row whose columns are the same key, #{key.inspect}, are " \
|
|
136
|
+
"deprecated, since each record holds the value of only the last of them, and v3.0 raises " \
|
|
137
|
+
"IOStreams::Errors::InvalidHeader for them: rename the columns, or read the rows with " \
|
|
138
|
+
"each(:array), which holds every column")
|
|
148
139
|
end
|
|
149
140
|
end
|
|
150
141
|
end
|
|
@@ -58,25 +58,32 @@ module IOStreams
|
|
|
58
58
|
# #as_hash will skip these additional columns entirely as if they were not in the file at all.
|
|
59
59
|
# false:
|
|
60
60
|
# Raises Tabular::InvalidHeader when a column is supplied that is not in the whitelist.
|
|
61
|
-
|
|
61
|
+
#
|
|
62
|
+
# tabular: [IOStreams::Tabular]
|
|
63
|
+
# The tabular that renders each record, such as one with a schema, see `IOStreams::Stream#schema`, in place of
|
|
64
|
+
# the other options, which create it.
|
|
65
|
+
def initialize(line_writer, columns: nil, original_file_name: nil, tabular: nil, **args)
|
|
62
66
|
raise(ArgumentError, "Stream must be a IOStreams::Line::Writer or implement #<<") unless line_writer.respond_to?(:<<)
|
|
63
67
|
|
|
64
|
-
|
|
68
|
+
if tabular && (columns || original_file_name || !args.empty?)
|
|
69
|
+
raise(ArgumentError, "Supply either tabular: or the options that create it, not both")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
IOStreams::Tabular.check_write_options(args)
|
|
73
|
+
@tabular = tabular || IOStreams::Tabular.new(columns: columns, file_name: original_file_name, **args)
|
|
65
74
|
@line_writer = line_writer
|
|
66
75
|
|
|
67
|
-
# Render header line when `columns` is supplied
|
|
68
|
-
|
|
76
|
+
# Render header line when `columns` is supplied, or with a schema the names of its fields, see
|
|
77
|
+
# `IOStreams::Tabular#start_records`.
|
|
78
|
+
@tabular.start_records { |line| @line_writer << line }
|
|
69
79
|
end
|
|
70
80
|
|
|
81
|
+
# Writes the record, after the header line that the keys of the first record give, when neither the columns
|
|
82
|
+
# supplied nor a schema give it, see `IOStreams::Tabular#render_record`.
|
|
71
83
|
def <<(hash)
|
|
72
84
|
raise(ArgumentError, "#<< only accepts a Hash argument") unless hash.is_a?(Hash)
|
|
73
85
|
|
|
74
|
-
|
|
75
|
-
# Extract header from the keys from the first row when not supplied above.
|
|
76
|
-
@tabular.header.columns = hash.keys
|
|
77
|
-
@line_writer << @tabular.render_header
|
|
78
|
-
end
|
|
79
|
-
@line_writer << @tabular.render(hash)
|
|
86
|
+
@tabular.render_record(hash) { |line| @line_writer << line }
|
|
80
87
|
end
|
|
81
88
|
end
|
|
82
89
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module IOStreams
|
|
4
|
+
module Row
|
|
5
|
+
# The header row that `IOStreams::Stream#each(:array)` yields before the rows of a file, which names the column of
|
|
6
|
+
# each value of the rows after it. It is an Array, as every other row is, whose class says that it is the header
|
|
7
|
+
# row, so that a writer of rows takes it as the header row of the rows written after it, rather than as a row of
|
|
8
|
+
# values, see `IOStreams::Row::Writer#<<`, and so that code that reads the rows can tell it apart:
|
|
9
|
+
#
|
|
10
|
+
# path.each(:array) do |row|
|
|
11
|
+
# next if row.is_a?(IOStreams::Row::HeaderRow)
|
|
12
|
+
#
|
|
13
|
+
# process(row)
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# It is equal to an Array of the same columns, and the methods of an Array that return a new Array, such as `map`,
|
|
17
|
+
# return an Array rather than a header row, so that a row made from it is a row of values.
|
|
18
|
+
class HeaderRow < ::Array
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -28,27 +28,64 @@ module IOStreams
|
|
|
28
28
|
# format: [Symbol]
|
|
29
29
|
# :csv, :hash, :array, :json, :psv, :fixed
|
|
30
30
|
#
|
|
31
|
-
#
|
|
32
|
-
|
|
31
|
+
# cleanse_header: [true|false]
|
|
32
|
+
# Whether to cleanse the header row read, see `IOStreams::Tabular::Header#cleanse!`, which the tabular that it
|
|
33
|
+
# creates does, see `IOStreams::Tabular.new`.
|
|
34
|
+
# With a schema it raises ArgumentError, even when nil, since the fields of the schema name the keys of the
|
|
35
|
+
# records instead.
|
|
36
|
+
# Default: cleanses it.
|
|
37
|
+
#
|
|
38
|
+
# tabular: [IOStreams::Tabular]
|
|
39
|
+
# The tabular that parses each line, such as one with a schema, see `IOStreams::Stream#schema`, in place of the
|
|
40
|
+
# other options, which create it.
|
|
41
|
+
#
|
|
42
|
+
# For all other parameters, see IOStreams::Tabular.new
|
|
43
|
+
def initialize(line_reader, original_file_name: nil, tabular: nil, **args)
|
|
33
44
|
unless line_reader.respond_to?(:each)
|
|
34
45
|
raise(ArgumentError, "Stream must be a IOStreams::Line::Reader or implement #each")
|
|
35
46
|
end
|
|
36
47
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
if tabular && (original_file_name || !args.empty?)
|
|
49
|
+
raise(ArgumentError, "Supply either tabular: or the options that create it, not both")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
@tabular = tabular || IOStreams::Tabular.new(file_name: original_file_name, **args)
|
|
53
|
+
@line_reader = line_reader
|
|
40
54
|
end
|
|
41
55
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
# Returns [true|false] whether the first row that #each yields is a header row, which names the column of each
|
|
57
|
+
# value of the rows after it, see `IOStreams::Tabular#rows_header?`: the header row of the file, or with a schema,
|
|
58
|
+
# the names of its fields, of a file without one, such as fixed width or JSON. False when the columns were
|
|
59
|
+
# supplied, which name the values of the rows instead. Asked before #each.
|
|
60
|
+
def header?
|
|
61
|
+
@tabular.rows_header?
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Returns [true|false] whether the rows that #each yields are the records of the file, Hashes rather than Arrays,
|
|
65
|
+
# see `IOStreams::Tabular#record_rows?`, such as those of JSON without a schema.
|
|
66
|
+
def record_rows?
|
|
67
|
+
@tabular.record_rows?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Yields each row, an Array, after the header row of a file with one, which it yields first, see
|
|
71
|
+
# `IOStreams::Tabular#read_row`. With a schema, the header row is an `IOStreams::Row::HeaderRow` of the names of
|
|
72
|
+
# the fields, also for a file without a header row, such as fixed width or JSON.
|
|
73
|
+
def each(&block)
|
|
74
|
+
@line_reader.each { |line| @tabular.read_row(line, &block) }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Writes each row to the writer, see `IOStreams::Row::Writer`, as a copy with a schema does, see
|
|
78
|
+
# `IOStreams::Stream#copy_from`, telling it the column of each value of the rows: the header row of the file, or
|
|
79
|
+
# for a file without one, the names of the fields of its schema, is an `IOStreams::Row::HeaderRow`, which the writer
|
|
80
|
+
# takes as the header row of the rows after it, see `IOStreams::Row::Writer#<<`, so that a target with a schema
|
|
81
|
+
# matches its columns to the fields, rather than write it as a row of values. Tabular decides which row is the
|
|
82
|
+
# header row, see `IOStreams::Tabular#start_copy` and `IOStreams::Tabular#copy_row`. A blank line, which is not a
|
|
83
|
+
# row, is not written.
|
|
84
|
+
#
|
|
85
|
+
# Returns the result of the #each of the line reader.
|
|
86
|
+
def copy_to(writer)
|
|
87
|
+
@tabular.start_copy { |columns| writer << columns }
|
|
88
|
+
@line_reader.each { |line| @tabular.copy_row(line) { |row| writer << row unless row.nil? } }
|
|
52
89
|
end
|
|
53
90
|
end
|
|
54
91
|
end
|
|
@@ -35,28 +35,79 @@ module IOStreams
|
|
|
35
35
|
# format: [Symbol]
|
|
36
36
|
# :csv, :hash, :array, :json, :psv, :fixed
|
|
37
37
|
#
|
|
38
|
+
# tabular: [IOStreams::Tabular]
|
|
39
|
+
# The tabular that renders each row, such as one with a schema, see `IOStreams::Stream#schema`, in place of the
|
|
40
|
+
# other options, which create it.
|
|
41
|
+
#
|
|
42
|
+
# report_repeated_key: [true|false]
|
|
43
|
+
# Whether to report a deprecation warning when the header row of the rows written to a format whose rows are
|
|
44
|
+
# records, such as JSON, has two columns of the same key, see #warn_repeated_key, which
|
|
45
|
+
# `IOStreams::Stream#writer` asks for, rather than another gem that creates a writer, which its users cannot
|
|
46
|
+
# change.
|
|
47
|
+
# Default: false
|
|
48
|
+
#
|
|
38
49
|
# For all other parameters, see Tabular::Header.new
|
|
39
|
-
def initialize(line_writer, columns: nil, original_file_name: nil, **args)
|
|
50
|
+
def initialize(line_writer, columns: nil, original_file_name: nil, tabular: nil, report_repeated_key: false, **args)
|
|
40
51
|
raise(ArgumentError, "Stream must be a IOStreams::Line::Writer or implement #<<") unless line_writer.respond_to?(:<<)
|
|
41
52
|
|
|
42
|
-
|
|
43
|
-
|
|
53
|
+
if tabular && (columns || original_file_name || !args.empty?)
|
|
54
|
+
raise(ArgumentError, "Supply either tabular: or the options that create it, not both")
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
IOStreams::Tabular.check_write_options(args)
|
|
58
|
+
@tabular = tabular || IOStreams::Tabular.new(columns: columns, file_name: original_file_name, **args)
|
|
59
|
+
@line_writer = line_writer
|
|
60
|
+
@report_repeated_key = report_repeated_key
|
|
44
61
|
|
|
45
|
-
# Render header line when `columns` is supplied
|
|
46
|
-
|
|
62
|
+
# Render header line when `columns` is supplied, or with a schema the names of its fields, see
|
|
63
|
+
# `IOStreams::Tabular#start_rows`.
|
|
64
|
+
@tabular.start_rows { |line| @line_writer << line }
|
|
47
65
|
end
|
|
48
66
|
|
|
49
|
-
# Supply
|
|
67
|
+
# Supply an array to render, otherwise it raises ArgumentError.
|
|
68
|
+
#
|
|
69
|
+
# Without a schema, the first row is the header row, unless the columns were supplied. With a schema, the header
|
|
70
|
+
# row of a file with one is the names of its fields, which is written before the rows, so every row written is
|
|
71
|
+
# the values of the fields, in order. A header row that `IOStreams::Stream#each(:array)` yields with a schema, an
|
|
72
|
+
# `IOStreams::Row::HeaderRow`, is written as the header row of the rows after it, see #write_header.
|
|
50
73
|
def <<(array)
|
|
51
74
|
raise(ArgumentError, "Must supply an Array") unless array.is_a?(Array)
|
|
75
|
+
return write_header(array) if array.is_a?(HeaderRow)
|
|
52
76
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
77
|
+
@tabular.render_row(array) { |line| @line_writer << line }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Writes the header row of the rows after it, such as that of the file that is copied, see
|
|
81
|
+
# `IOStreams::Row::Reader#copy_to`, so that the value of each column of the rows after it is written to its
|
|
82
|
+
# column, or to its field with a schema, whose columns it matches to the fields, without a line. Without a schema,
|
|
83
|
+
# as the first row, see #<<, unless the format has no header row, such as JSON, and the columns are not known,
|
|
84
|
+
# when it gives the columns of the rows after it, or the columns were supplied, which name them instead, see
|
|
85
|
+
# `IOStreams::Tabular#render_header_row`.
|
|
86
|
+
#
|
|
87
|
+
# Returns self, so that calls can be chained.
|
|
88
|
+
def write_header(columns)
|
|
89
|
+
@tabular.render_header_row(columns) { |line| @line_writer << line }
|
|
90
|
+
warn_repeated_key if @report_repeated_key
|
|
91
|
+
self
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
# Reports a deprecation warning when two columns of the header row are the same key, see
|
|
97
|
+
# `IOStreams::Tabular#repeated_key`, such as a header row of `a,a,b`, and the format writes each row as a record,
|
|
98
|
+
# see `IOStreams::Tabular#record_rows?`, such as JSON, since each record holds the value of only the last of them,
|
|
99
|
+
# while IOStreams v3.0 raises `IOStreams::Errors::InvalidHeader` for them, rather than lose the others. A format
|
|
100
|
+
# whose rows are Arrays, such as CSV, writes every column.
|
|
101
|
+
def warn_repeated_key
|
|
102
|
+
return unless @tabular.record_rows?
|
|
103
|
+
|
|
104
|
+
key = @tabular.repeated_key
|
|
105
|
+
return if key.nil?
|
|
106
|
+
|
|
107
|
+
Deprecation.warn("rows written to a format whose rows are records, such as JSON, under a header row whose " \
|
|
108
|
+
"columns are the same key, #{key.inspect}, are deprecated, since each record holds the value " \
|
|
109
|
+
"of only the last of them, and v3.0 raises IOStreams::Errors::InvalidHeader for them: rename " \
|
|
110
|
+
"the columns")
|
|
60
111
|
end
|
|
61
112
|
end
|
|
62
113
|
end
|