smarter_csv 1.4.2 → 1.5.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: 3be724101d41326ff480bcb723c1b40a3cabd879eb55e0c2f044372f8e5a57d0
4
- data.tar.gz: 657db1421352f449bf042f8df4d5178167af048ad37836e4f2f2f8a6aea3ece0
3
+ metadata.gz: 23032eface2d1d918bcd6daabb4ca79e03096612bda1017d06f1b0542d0c4619
4
+ data.tar.gz: 12b68eeafc4f83c06b66da45b27da5e716675bff1e77be2362c2c10006821d9c
5
5
  SHA512:
6
- metadata.gz: 3430649df35ac8139d35b04b85e8691ca5fc3d98b7b15f0d3987855f571987bdb742e0ed6f807ddb7a2e61e61d696d529ac311bc58e30188325f1c4bb78098a4
7
- data.tar.gz: 1b386af7cc7c39bc7ea934875e16f6641a2cc0c2bb5dfaa3b1f298739b1b355b2f41570e42998a2d7790a17f96feb07118b69c23d913acc634aae5901f0c9229
6
+ metadata.gz: 5b84337de25ed7a8492088b82342e6d3b16d1fdc95120f9699986aee7d9416a51cfec981eb125e0d4b17600bc1c06c52eb3b2251857668210d9402e95bb75860
7
+ data.tar.gz: b26b40b49bf6d739df9cd5deb477c33fdc22c54ed88c96f87e401fef789aedf3f9c55d25df60e4900a1e2a3c8bc0fc6e78018b128ab6ac14062fd97f694f3568
data/CHANGELOG.md CHANGED
@@ -1,7 +1,19 @@
1
1
 
2
2
  # SmarterCSV 1.x Change Log
3
3
 
4
- ## 1.4.1 (2022-02-12)
4
+ ## 1.5.0 (2022-04-25)
5
+ * fixed bug with trailing col_sep characters, introduced in 1.4.0
6
+ * Fix deprecation warning in Ruby 3.0.3 / $INPUT_RECORD_SEPARATOR (thanks to Joel Fouse )
7
+
8
+ * changed default for `comment_regexp` to be `nil` for a safer default behavior (thanks to David Lazar)
9
+ **Note**
10
+ This no longer assumes that lines starting with `#` are comments.
11
+ If you want to treat lines starting with '#' as comments, use `comment_regexp: /\A#/`
12
+
13
+ ## 1.4.2 (2022-02-12)
14
+ * fixed issue with simplecov
15
+
16
+ ## 1.4.1 (2022-02-12) (PULLED)
5
17
  * minor fix: also support `col_sep: :auto`
6
18
  * added simplecov
7
19
 
data/CONTRIBUTORS.md CHANGED
@@ -43,3 +43,4 @@ A Big Thank you to everyone who filed issues, sent comments, and who contributed
43
43
  * [Olle Jonsson](https://github.com/olleolleolle)
44
44
  * [Nicolas Guillemain](https://github.com/Viiruus)
45
45
  * [Sp6](https://github.com/sp6)
46
+ * [Joel Fouse](https://github.com/jfouse)
data/README.md CHANGED
@@ -215,7 +215,7 @@ The options and the block are optional.
215
215
  | :invalid_byte_sequence | '' | what to replace invalid byte sequences with |
216
216
  | :force_utf8 | false | force UTF-8 encoding of all lines (including headers) in the CSV file |
217
217
  | :skip_lines | nil | how many lines to skip before the first line or header line is processed |
218
- | :comment_regexp | /^#/ | regular expression which matches comment lines (see NOTE about the CSV header) |
218
+ | :comment_regexp | nil | regular expression to ignore comment lines (see NOTE on CSV header), e.g./\A#/ |
219
219
  ---------------------------------------------------------------------------------------------------------------------------------
220
220
  | :col_sep | ',' | column separator, can be set to :auto |
221
221
  | :force_simple_split | false | force simple splitting on :col_sep character for non-standard CSV-files. |
@@ -284,7 +284,8 @@ And header and data validations will also be supported in 2.x
284
284
  ```
285
285
  #### NOTES about CSV Headers:
286
286
  * as this method parses CSV files, it is assumed that the first line of any file will contain a valid header
287
- * the first line with the CSV header may or may not be commented out according to the :comment_regexp
287
+ * the first line with the header might be commented out, in which case you will need to set `comment_regexp: /\A#/`
288
+ This is no longer handled automatically since 1.5.0.
288
289
  * any occurences of :comment_regexp or :row_sep will be stripped from the first line with the CSV header
289
290
  * any of the keys in the header line will be downcased, spaces replaced by underscore, and converted to Ruby symbols before being used as keys in the returned Hashes
290
291
  * you can not combine the :user_provided_headers and :key_mapping options
@@ -12,7 +12,6 @@ module SmarterCSV
12
12
 
13
13
  headerA = []
14
14
  result = []
15
- old_row_sep = $INPUT_RECORD_SEPARATOR
16
15
  file_line_count = 0
17
16
  csv_line_count = 0
18
17
  has_rails = !! defined?(Rails)
@@ -21,9 +20,8 @@ module SmarterCSV
21
20
 
22
21
  # auto-detect the row separator
23
22
  options[:row_sep] = SmarterCSV.guess_line_ending(f, options) if options[:row_sep].to_sym == :auto
24
- $INPUT_RECORD_SEPARATOR = options[:row_sep]
25
23
  # attempt to auto-detect column separator
26
- options[:col_sep] = guess_column_separator(f) if options[:col_sep].to_sym == :auto
24
+ options[:col_sep] = guess_column_separator(f, options) if options[:col_sep].to_sym == :auto
27
25
  # preserve options, in case we need to call the CSV class
28
26
  csv_options = options.select{|k,v| [:col_sep, :row_sep, :quote_char].include?(k)} # options.slice(:col_sep, :row_sep, :quote_char)
29
27
  csv_options.delete(:row_sep) if [nil, :auto].include?( options[:row_sep].to_sym )
@@ -33,14 +31,15 @@ module SmarterCSV
33
31
  puts 'WARNING: you are trying to process UTF-8 input, but did not open the input with "b:utf-8" option. See README file "NOTES about File Encodings".'
34
32
  end
35
33
 
36
- options[:skip_lines].to_i.times{f.readline} if options[:skip_lines].to_i > 0
34
+ options[:skip_lines].to_i.times{f.readline(options[:row_sep])} if options[:skip_lines].to_i > 0
37
35
 
38
36
  if options[:headers_in_file] # extract the header line
39
37
  # process the header line in the CSV file..
40
38
  # the first line of a CSV file contains the header .. it might be commented out, so we need to read it anyhow
41
- header = f.readline
39
+ header = f.readline(options[:row_sep])
42
40
  header = header.force_encoding('utf-8').encode('utf-8', invalid: :replace, undef: :replace, replace: options[:invalid_byte_sequence]) if options[:force_utf8] || options[:file_encoding] !~ /utf-8/i
43
- header = header.sub(options[:comment_regexp],'').chomp(options[:row_sep])
41
+ header = header.sub(options[:comment_regexp],'') if options[:comment_regexp]
42
+ header = header.chomp(options[:row_sep])
44
43
 
45
44
  file_line_count += 1
46
45
  csv_line_count += 1
@@ -120,7 +119,7 @@ module SmarterCSV
120
119
 
121
120
  # now on to processing all the rest of the lines in the CSV file:
122
121
  while ! f.eof? # we can't use f.readlines() here, because this would read the whole file into memory at once, and eof => true
123
- line = f.readline # read one line.. this uses the input_record_separator $INPUT_RECORD_SEPARATOR which we set previously!
122
+ line = f.readline(options[:row_sep]) # read one line
124
123
 
125
124
  # replace invalid byte sequence in UTF-8 with question mark to avoid errors
126
125
  line = line.force_encoding('utf-8').encode('utf-8', invalid: :replace, undef: :replace, replace: options[:invalid_byte_sequence]) if options[:force_utf8] || options[:file_encoding] !~ /utf-8/i
@@ -128,21 +127,22 @@ module SmarterCSV
128
127
  file_line_count += 1
129
128
  csv_line_count += 1
130
129
  print "processing file line %10d, csv line %10d\r" % [file_line_count, csv_line_count] if options[:verbose]
131
- next if line =~ options[:comment_regexp] # ignore all comment lines if there are any
130
+
131
+ next if options[:comment_regexp] && line =~ options[:comment_regexp] # ignore all comment lines if there are any
132
132
 
133
133
  # cater for the quoted csv data containing the row separator carriage return character
134
134
  # in which case the row data will be split across multiple lines (see the sample content in spec/fixtures/carriage_returns_rn.csv)
135
135
  # by detecting the existence of an uneven number of quote characters
136
136
  multiline = line.count(options[:quote_char])%2 == 1 # should handle quote_char nil
137
137
  while line.count(options[:quote_char])%2 == 1 # should handle quote_char nil
138
- next_line = f.readline
138
+ next_line = f.readline(options[:row_sep])
139
139
  next_line = next_line.force_encoding('utf-8').encode('utf-8', invalid: :replace, undef: :replace, replace: options[:invalid_byte_sequence]) if options[:force_utf8] || options[:file_encoding] !~ /utf-8/i
140
140
  line += next_line
141
141
  file_line_count += 1
142
142
  end
143
143
  print "\nline contains uneven number of quote chars so including content through file line %d\n" % file_line_count if options[:verbose] && multiline
144
144
 
145
- line.chomp! # will use $INPUT_RECORD_SEPARATOR which is set to options[:col_sep]
145
+ line.chomp!(options[:row_sep])
146
146
 
147
147
  if (line =~ %r{#{options[:quote_char]}}) and (! options[:force_simple_split])
148
148
  dataA = begin
@@ -151,10 +151,10 @@ module SmarterCSV
151
151
  raise $!, "#{$!} [SmarterCSV: csv line #{csv_line_count}]", $!.backtrace
152
152
  end
153
153
  else
154
- dataA = line.split(options[:col_sep], header_size)
154
+ dataA = line.split(options[:col_sep], header_size)
155
155
  end
156
- #### dataA.map!{|x| x.gsub(%r/#{options[:quote_char]}/,'') } # this is actually not a good idea as a default
157
- dataA.map!{|x| x.strip} if options[:strip_whitespace]
156
+ dataA.map!{|x| x.sub(/(#{options[:col_sep]})+\z/, '')} # remove any unwanted trailing col_sep characters at the end
157
+ dataA.map!{|x| x.strip} if options[:strip_whitespace]
158
158
 
159
159
  # if all values are blank, then ignore this line
160
160
  # SEE: https://github.com/rails/rails/blob/32015b6f369adc839c4f0955f2d9dce50c0b6123/activesupport/lib/active_support/core_ext/object/blank.rb#L121
@@ -249,7 +249,6 @@ module SmarterCSV
249
249
  chunk = [] # initialize for next chunk of data
250
250
  end
251
251
  ensure
252
- $INPUT_RECORD_SEPARATOR = old_row_sep # make sure this stupid global variable is always reset to it's previous value after we're done!
253
252
  f.close if f.respond_to?(:close)
254
253
  end
255
254
  if block_given?
@@ -266,7 +265,7 @@ module SmarterCSV
266
265
  auto_row_sep_chars: 500,
267
266
  chunk_size: nil ,
268
267
  col_sep: ',',
269
- comment_regexp: /\A#/,
268
+ comment_regexp: nil, # was: /\A#/,
270
269
  convert_values_to_numeric: true,
271
270
  downcase_header: true,
272
271
  file_encoding: 'utf-8',
@@ -329,11 +328,11 @@ module SmarterCSV
329
328
  end
330
329
 
331
330
  # raise exception if none is found
332
- def self.guess_column_separator(filehandle)
331
+ def self.guess_column_separator(filehandle, options)
333
332
  del = [',', "\t", ';', ':', '|']
334
333
  n = Hash.new(0)
335
334
  5.times do
336
- line = filehandle.readline
335
+ line = filehandle.readline(options[:row_sep])
337
336
  del.each do |d|
338
337
  n[d] += line.scan(d).count
339
338
  end
@@ -1,3 +1,3 @@
1
1
  module SmarterCSV
2
- VERSION = "1.4.2"
2
+ VERSION = "1.5.0"
3
3
  end
@@ -0,0 +1,6 @@
1
+ col1,col2
2
+ eins,zwei
3
+ uno,dos,
4
+ one,two ,,,
5
+ ichi, ,,,,,
6
+ un
@@ -0,0 +1,2 @@
1
+ Name,Email,Financial Status,Paid at,Fulfillment Status,Fulfilled at,Accepts Marketing,Currency,Subtotal,Shipping,Taxes,Total,Discount Code,Discount Amount,Shipping Method,Created at,Lineitem quantity,Lineitem name,Lineitem price,Lineitem compare at price,Lineitem sku,Lineitem requires shipping,Lineitem taxable,Lineitem fulfillment status,Billing Name,Billing Street,Billing Address1,Billing Address2,Billing Company,Billing City,Billing Zip,Billing Province,Billing Country,Billing Phone,Shipping Name,Shipping Street,Shipping Address1,Shipping Address2,Shipping Company,Shipping City,Shipping Zip,Shipping Province,Shipping Country,Shipping Phone,Notes,Note Attributes,Cancelled at,Payment Method,Payment Reference,Refunded Amount,Vendor, rece,Tags,Risk Level,Source,Lineitem discount,Tax 1 Name,Tax 1 Value,Tax 2 Name,Tax 2 Value,Tax 3 Name,Tax 3 Value,Tax 4 Name,Tax 4 Value,Tax 5 Name,Tax 5 Value,Phone,Receipt Number,Duties,Billing Province Name,Shipping Province Name,Payment ID,Payment Terms Name,Next Payment Due At
2
+ #MR1220817,foo@bar.com,paid,2022-02-08 22:31:28 +0100,unfulfilled,,yes,EUR,144,0,24,144,VIP,119.6,"Livraison Standard GRATUITE, 2-5 jours avec suivi",2022-02-08 22:31:26 +0100,2,Cire Épilation Nacrée,37,,WAX-200-NAC,true,true,pending,French Fry,64 Boulevard Budgié,64 Boulevard Budgié,,,dootdoot’,'49100,,FR,06 12 34 56 78,French Fry,64 Boulevard Budgi,64 Boulevard Budgié,,,dootdoot,'49100,,FR,06 12 34 56 78,,,,Stripe,c23800013619353.2,0,Goober Rég,4331065802905,902,Low,web,0,FR TVA 20%,24,,,,,,,,,3366012111111,,,,,,,
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ fixture_path = 'spec/fixtures'
4
+
5
+ describe 'handling of additional trailing column separators' do
6
+ let(:file) { "#{fixture_path}/additional_separator.csv" }
7
+
8
+ describe '' do
9
+ let(:data) { SmarterCSV.process(file) }
10
+
11
+ it 'reads all lines' do
12
+ data.size.should eq 5
13
+ end
14
+
15
+ it 'reads regular lines' do
16
+ item = data[0]
17
+ item[:col1].should == 'eins'
18
+ item[:col2].should == 'zwei'
19
+ end
20
+
21
+ it 'strips single trailing col_sep character' do
22
+ item = data[1]
23
+ item[:col1].should == 'uno'
24
+ item[:col2].should == 'dos'
25
+ end
26
+
27
+ it 'strips multiple trailing col_sep characters' do
28
+ item = data[2]
29
+ item[:col1].should == 'one'
30
+ item[:col2].should == 'two'
31
+ end
32
+
33
+ it 'strips multiple trailing col_sep chars' do
34
+ item = data[3]
35
+ item[:col1].should == 'ichi'
36
+ item[:col2].should == nil
37
+ end
38
+
39
+ it 'strips multiple trailing col_sep chars' do
40
+ item = data[4]
41
+ item[:col1].should == 'un'
42
+ item[:col2].should == nil
43
+ end
44
+ end
45
+ end
@@ -12,7 +12,7 @@ describe 'be_able_to' do
12
12
  it 'loads_binary_file_with_strings_as_keys' do
13
13
  options = {:col_sep => "\cA", :row_sep => "\cB", :comment_regexp => /^#/, :strings_as_keys => true}
14
14
  data = SmarterCSV.process("#{fixture_path}/binary.csv", options)
15
- data.flatten.size.should == 8
15
+ data.size.should == 8
16
16
  data.each do |item|
17
17
  # all keys should be strings
18
18
  item.keys.each{|x| x.class.should be == String}
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ fixture_path = 'spec/fixtures'
4
+
5
+ describe 'can handle the difficult CSV file' do
6
+
7
+ it 'loads the data with default values' do
8
+ data = SmarterCSV.process("#{fixture_path}/hard_sample.csv")
9
+ data.size.should eq 1
10
+ item = data.first
11
+ item.keys.count.should == 48
12
+ item[:name].should == '#MR1220817'
13
+ item[:shipping_method].should == 'Livraison Standard GRATUITE, 2-5 jours avec suivi'
14
+ item[:lineitem_name].should == 'Cire Épilation Nacrée'
15
+ item[:phone].should == 3366012111111
16
+ end
17
+
18
+ # the main problem is the data line starting with a # character, but not being a comment
19
+ it 'fails to load the CSV file with incorrectly set comment_regexp' do
20
+ options = {comment_regexp: /\A#/ }
21
+ data = SmarterCSV.process("#{fixture_path}/hard_sample.csv", options)
22
+ data.size.should eq 0
23
+ end
24
+ end
@@ -1,30 +1,45 @@
1
- require 'spec_helper'
2
-
3
- fixture_path = 'spec/fixtures'
4
-
5
- describe 'be_able_to' do
6
- it 'ignore comments in CSV files' do
7
- options = {}
8
- data = SmarterCSV.process("#{fixture_path}/ignore_comments.csv", options)
9
-
10
- data.size.should eq 5
11
-
12
- # all the keys should be symbols
13
- data.each{|item| item.keys.each{|x| x.is_a?(Symbol).should be_truthy}}
14
- data.each do |h|
15
- h.keys.each do |key|
16
- [:"not_a_comment#first_name", :last_name, :dogs, :cats, :birds, :fish].should include( key )
17
- end
18
- end
19
- end
20
-
21
- it 'ignore comments in CSV files with CRLF' do
22
- options = {row_sep: "\r\n"}
23
- data = SmarterCSV.process("#{fixture_path}/ignore_comments2.csv", options)
24
-
25
- # all the keys should be symbols
26
- data.size.should eq 1
27
- data.first[:h1].should eq 'a'
28
- data.first[:h2].should eq "b\r\n#c"
29
- end
30
- end
1
+ require 'spec_helper'
2
+
3
+ fixture_path = 'spec/fixtures'
4
+
5
+ describe 'be_able_to' do
6
+ it 'by default does not ignore comments in CSV files' do
7
+ options = {}
8
+ data = SmarterCSV.process("#{fixture_path}/ignore_comments.csv", options)
9
+
10
+ data.size.should eq 8
11
+
12
+ # all the keys should be symbols
13
+ data.each{|item| item.keys.each{|x| x.is_a?(Symbol).should be_truthy}}
14
+ data.each do |h|
15
+ h.keys.each do |key|
16
+ [:"not_a_comment#first_name", :last_name, :dogs, :cats, :birds, :fish].should include( key )
17
+ end
18
+ end
19
+ end
20
+
21
+ it 'ignore comments in CSV files using comment_regexp' do
22
+ options = {comment_regexp: /\A#/}
23
+ data = SmarterCSV.process("#{fixture_path}/ignore_comments.csv", options)
24
+
25
+ data.size.should eq 5
26
+
27
+ # all the keys should be symbols
28
+ data.each{|item| item.keys.each{|x| x.is_a?(Symbol).should be_truthy}}
29
+ data.each do |h|
30
+ h.keys.each do |key|
31
+ [:"not_a_comment#first_name", :last_name, :dogs, :cats, :birds, :fish].should include( key )
32
+ end
33
+ end
34
+ end
35
+
36
+ it 'ignore comments in CSV files with CRLF' do
37
+ options = {row_sep: "\r\n"}
38
+ data = SmarterCSV.process("#{fixture_path}/ignore_comments2.csv", options)
39
+
40
+ # all the keys should be symbols
41
+ data.size.should eq 1
42
+ data.first[:h1].should eq 'a'
43
+ data.first[:h2].should eq "b\r\n#c"
44
+ end
45
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smarter_csv
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.2
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tilo Sloboda
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-15 00:00:00.000000000 Z
11
+ date: 2022-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -62,6 +62,7 @@ files:
62
62
  - lib/smarter_csv/smarter_csv.rb
63
63
  - lib/smarter_csv/version.rb
64
64
  - smarter_csv.gemspec
65
+ - spec/fixtures/additional_separator.csv
65
66
  - spec/fixtures/basic.csv
66
67
  - spec/fixtures/binary.csv
67
68
  - spec/fixtures/carriage_returns_n.csv
@@ -73,6 +74,7 @@ files:
73
74
  - spec/fixtures/empty.csv
74
75
  - spec/fixtures/empty_columns_1.csv
75
76
  - spec/fixtures/empty_columns_2.csv
77
+ - spec/fixtures/hard_sample.csv
76
78
  - spec/fixtures/ignore_comments.csv
77
79
  - spec/fixtures/ignore_comments2.csv
78
80
  - spec/fixtures/key_mapping.csv
@@ -101,6 +103,7 @@ files:
101
103
  - spec/fixtures/valid_unicode.csv
102
104
  - spec/fixtures/with_dashes.csv
103
105
  - spec/fixtures/with_dates.csv
106
+ - spec/smarter_csv/additional_separator_spec.rb
104
107
  - spec/smarter_csv/binary_file2_spec.rb
105
108
  - spec/smarter_csv/binary_file_spec.rb
106
109
  - spec/smarter_csv/blank_spec.rb
@@ -111,6 +114,7 @@ files:
111
114
  - spec/smarter_csv/convert_values_to_numeric_spec.rb
112
115
  - spec/smarter_csv/empty_columns_spec.rb
113
116
  - spec/smarter_csv/extenstions_spec.rb
117
+ - spec/smarter_csv/hard_sample_spec.rb
114
118
  - spec/smarter_csv/header_transformation_spec.rb
115
119
  - spec/smarter_csv/ignore_comments_spec.rb
116
120
  - spec/smarter_csv/invalid_headers_spec.rb
@@ -164,6 +168,7 @@ specification_version: 4
164
168
  summary: Ruby Gem for smarter importing of CSV Files (and CSV-like files), with lots
165
169
  of optional features, e.g. chunked processing for huge CSV files
166
170
  test_files:
171
+ - spec/fixtures/additional_separator.csv
167
172
  - spec/fixtures/basic.csv
168
173
  - spec/fixtures/binary.csv
169
174
  - spec/fixtures/carriage_returns_n.csv
@@ -175,6 +180,7 @@ test_files:
175
180
  - spec/fixtures/empty.csv
176
181
  - spec/fixtures/empty_columns_1.csv
177
182
  - spec/fixtures/empty_columns_2.csv
183
+ - spec/fixtures/hard_sample.csv
178
184
  - spec/fixtures/ignore_comments.csv
179
185
  - spec/fixtures/ignore_comments2.csv
180
186
  - spec/fixtures/key_mapping.csv
@@ -203,6 +209,7 @@ test_files:
203
209
  - spec/fixtures/valid_unicode.csv
204
210
  - spec/fixtures/with_dashes.csv
205
211
  - spec/fixtures/with_dates.csv
212
+ - spec/smarter_csv/additional_separator_spec.rb
206
213
  - spec/smarter_csv/binary_file2_spec.rb
207
214
  - spec/smarter_csv/binary_file_spec.rb
208
215
  - spec/smarter_csv/blank_spec.rb
@@ -213,6 +220,7 @@ test_files:
213
220
  - spec/smarter_csv/convert_values_to_numeric_spec.rb
214
221
  - spec/smarter_csv/empty_columns_spec.rb
215
222
  - spec/smarter_csv/extenstions_spec.rb
223
+ - spec/smarter_csv/hard_sample_spec.rb
216
224
  - spec/smarter_csv/header_transformation_spec.rb
217
225
  - spec/smarter_csv/ignore_comments_spec.rb
218
226
  - spec/smarter_csv/invalid_headers_spec.rb