smarter_csv 1.1.5 → 1.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/README.md +6 -0
- data/lib/smarter_csv/smarter_csv.rb +19 -2
- data/lib/smarter_csv/version.rb +1 -1
- data/spec/fixtures/duplicate_headers.csv +3 -0
- data/spec/fixtures/user_import.csv +3 -0
- data/spec/smarter_csv/invalid_headers_spec.rb +52 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 251eb1eff306211d163c6be6880ba45e3eb29985
|
4
|
+
data.tar.gz: 9e16d1d4aaab86df7a65d73e6a23ace8f481ba4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e2ad758ddb7d644777df1b9f38b73c7c4c0753d76507834bf68e86394ae017b1f5caa16867efd82f4c0443d4a7c1b4c1d7f704d9c3796e71083bde689ee7aeba
|
7
|
+
data.tar.gz: 8f7126500628a17fda587a05678aca9140d0ebb7ca168fc3144b1d9c00d2be6ec901a43900bd3d558aceb0a8dcfc139aba7347e6dbad01b2ff83c19dc3816763
|
data/README.md
CHANGED
@@ -193,6 +193,8 @@ The options and the block are optional.
|
|
193
193
|
| :chunk_size | nil | if set, determines the desired chunk-size (defaults to nil, no chunk processing) |
|
194
194
|
---------------------------------------------------------------------------------------------------------------------------------
|
195
195
|
| :key_mapping | nil | a hash which maps headers from the CSV file to keys in the result hash |
|
196
|
+
| :required_headers | nil | An array. Eacn of the given headers must be present in the CSV file, |
|
197
|
+
| | | or an exception is raised No validation if nil is given. |
|
196
198
|
| :remove_unmapped_keys | false | when using :key_mapping option, should non-mapped keys / columns be removed? |
|
197
199
|
| :downcase_header | true | downcase all column headers |
|
198
200
|
| :strings_as_keys | false | use strings instead of symbols as the keys in the result hashes |
|
@@ -293,6 +295,10 @@ Planned in the next releases:
|
|
293
295
|
|
294
296
|
## Changes
|
295
297
|
|
298
|
+
#### 1.2.0 (2018-01-20)
|
299
|
+
* add default validation that a header can only appear once
|
300
|
+
* add option `required_headers`
|
301
|
+
|
296
302
|
#### 1.1.5 (2017-11-05)
|
297
303
|
* fix issue with invalid byte sequences in header (issue #103, thanks to Dave Myron)
|
298
304
|
* fix issue with invalid byte sequences in multi-line data (thanks to Ivan Ushakov)
|
@@ -1,8 +1,10 @@
|
|
1
1
|
module SmarterCSV
|
2
2
|
|
3
3
|
class HeaderSizeMismatch < Exception; end
|
4
|
-
|
5
4
|
class IncorrectOption < Exception; end
|
5
|
+
class DuplicateHeaders < Exception; end
|
6
|
+
class MissingHeaders < Exception; end
|
7
|
+
|
6
8
|
|
7
9
|
def SmarterCSV.process(input, options={}, &block) # first parameter: filename or input object with readline method
|
8
10
|
default_options = {:col_sep => ',' , :row_sep => $/ , :quote_char => '"', :force_simple_split => false , :verbose => false ,
|
@@ -10,7 +12,7 @@ module SmarterCSV
|
|
10
12
|
:convert_values_to_numeric => true, :strip_chars_from_headers => nil , :user_provided_headers => nil , :headers_in_file => true,
|
11
13
|
:comment_regexp => /^#/, :chunk_size => nil , :key_mapping_hash => nil , :downcase_header => true, :strings_as_keys => false, :file_encoding => 'utf-8',
|
12
14
|
:remove_unmapped_keys => false, :keep_original_headers => false, :value_converters => nil, :skip_lines => nil, :force_utf8 => false, :invalid_byte_sequence => '',
|
13
|
-
:auto_row_sep_chars => 500
|
15
|
+
:auto_row_sep_chars => 500, :required_headers => nil
|
14
16
|
}
|
15
17
|
options = default_options.merge(options)
|
16
18
|
options[:invalid_byte_sequence] = '' if options[:invalid_byte_sequence].nil?
|
@@ -93,6 +95,21 @@ module SmarterCSV
|
|
93
95
|
end
|
94
96
|
end
|
95
97
|
|
98
|
+
# header_validations
|
99
|
+
duplicate_headers = []
|
100
|
+
headerA.compact.each do |k|
|
101
|
+
duplicate_headers << k if headerA.select{|x| x == k}.size > 1
|
102
|
+
end
|
103
|
+
raise SmarterCSV::DuplicateHeaders , "ERORR [smarter_csv]: duplicate headers: #{duplicate_headers.join(',')}" unless duplicate_headers.empty?
|
104
|
+
|
105
|
+
if options[:required_headers] && options[:required_headers].is_a?(Array)
|
106
|
+
missing_headers = []
|
107
|
+
options[:required_headers].each do |k|
|
108
|
+
missing_headers << k unless headerA.include?(k)
|
109
|
+
end
|
110
|
+
raise SmarterCSV::MissingHeaders , "ERORR [smarter_csv]: missing headers: #{missing_headers.join(',')}" unless missing_headers.empty?
|
111
|
+
end
|
112
|
+
|
96
113
|
# in case we use chunking.. we'll need to set it up..
|
97
114
|
if ! options[:chunk_size].nil? && options[:chunk_size].to_i > 0
|
98
115
|
use_chunks = true
|
data/lib/smarter_csv/version.rb
CHANGED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
fixture_path = 'spec/fixtures'
|
4
|
+
|
5
|
+
describe 'test exceptions for invalid headers' do
|
6
|
+
it 'raises error on duplicate headers' do
|
7
|
+
expect {
|
8
|
+
SmarterCSV.process("#{fixture_path}/duplicate_headers.csv", {})
|
9
|
+
}.to raise_exception(SmarterCSV::DuplicateHeaders)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'raises error on duplicate given headers' do
|
13
|
+
expect {
|
14
|
+
options = {:user_provided_headers => [:a,:b,:c,:d,:a]}
|
15
|
+
SmarterCSV.process("#{fixture_path}/duplicate_headers.csv", options)
|
16
|
+
}.to raise_exception(SmarterCSV::DuplicateHeaders)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'raises error on duplicate mapped headers' do
|
20
|
+
expect {
|
21
|
+
# the mapping is right, but the underlying csv file is bad
|
22
|
+
options = {:key_mapping => {:email => :a, :firstname => :b, :lastname => :c, :manager_email => :d, :age => :e} }
|
23
|
+
SmarterCSV.process("#{fixture_path}/duplicate_headers.csv", options)
|
24
|
+
}.to raise_exception(SmarterCSV::DuplicateHeaders)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
it 'does not raise an error if no required headers are given' do
|
29
|
+
options = {:required_headers => nil} # order does not matter
|
30
|
+
data = SmarterCSV.process("#{fixture_path}/user_import.csv", options)
|
31
|
+
data.size.should eq 2
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'does not raise an error if no required headers are given' do
|
35
|
+
options = {:required_headers => []} # order does not matter
|
36
|
+
data = SmarterCSV.process("#{fixture_path}/user_import.csv", options)
|
37
|
+
data.size.should eq 2
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'does not raise an error if the required headers are present' do
|
41
|
+
options = {:required_headers => [:lastname,:email,:firstname,:manager_email]} # order does not matter
|
42
|
+
data = SmarterCSV.process("#{fixture_path}/user_import.csv", options)
|
43
|
+
data.size.should eq 2
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'raises an error if a required header is missing' do
|
47
|
+
expect {
|
48
|
+
options = {:required_headers => [:lastname,:email,:employee_id,:firstname,:manager_email]} # order does not matter
|
49
|
+
SmarterCSV.process("#{fixture_path}/user_import.csv", options)
|
50
|
+
}.to raise_exception(SmarterCSV::MissingHeaders)
|
51
|
+
end
|
52
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smarter_csv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 'Tilo Sloboda
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2018-01-20 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec
|
@@ -56,6 +56,7 @@ files:
|
|
56
56
|
- spec/fixtures/carriage_returns_r.csv
|
57
57
|
- spec/fixtures/carriage_returns_rn.csv
|
58
58
|
- spec/fixtures/chunk_cornercase.csv
|
59
|
+
- spec/fixtures/duplicate_headers.csv
|
59
60
|
- spec/fixtures/empty.csv
|
60
61
|
- spec/fixtures/line_endings_n.csv
|
61
62
|
- spec/fixtures/line_endings_r.csv
|
@@ -70,6 +71,7 @@ files:
|
|
70
71
|
- spec/fixtures/quoted.csv
|
71
72
|
- spec/fixtures/separator.csv
|
72
73
|
- spec/fixtures/skip_lines.csv
|
74
|
+
- spec/fixtures/user_import.csv
|
73
75
|
- spec/fixtures/valid_unicode.csv
|
74
76
|
- spec/fixtures/with_dashes.csv
|
75
77
|
- spec/fixtures/with_dates.csv
|
@@ -82,6 +84,7 @@ files:
|
|
82
84
|
- spec/smarter_csv/convert_values_to_numeric_spec.rb
|
83
85
|
- spec/smarter_csv/extenstions_spec.rb
|
84
86
|
- spec/smarter_csv/header_transformation_spec.rb
|
87
|
+
- spec/smarter_csv/invalid_headers_spec.rb
|
85
88
|
- spec/smarter_csv/keep_headers_spec.rb
|
86
89
|
- spec/smarter_csv/key_mapping_spec.rb
|
87
90
|
- spec/smarter_csv/line_ending_spec.rb
|
@@ -138,6 +141,7 @@ test_files:
|
|
138
141
|
- spec/fixtures/carriage_returns_r.csv
|
139
142
|
- spec/fixtures/carriage_returns_rn.csv
|
140
143
|
- spec/fixtures/chunk_cornercase.csv
|
144
|
+
- spec/fixtures/duplicate_headers.csv
|
141
145
|
- spec/fixtures/empty.csv
|
142
146
|
- spec/fixtures/line_endings_n.csv
|
143
147
|
- spec/fixtures/line_endings_r.csv
|
@@ -152,6 +156,7 @@ test_files:
|
|
152
156
|
- spec/fixtures/quoted.csv
|
153
157
|
- spec/fixtures/separator.csv
|
154
158
|
- spec/fixtures/skip_lines.csv
|
159
|
+
- spec/fixtures/user_import.csv
|
155
160
|
- spec/fixtures/valid_unicode.csv
|
156
161
|
- spec/fixtures/with_dashes.csv
|
157
162
|
- spec/fixtures/with_dates.csv
|
@@ -164,6 +169,7 @@ test_files:
|
|
164
169
|
- spec/smarter_csv/convert_values_to_numeric_spec.rb
|
165
170
|
- spec/smarter_csv/extenstions_spec.rb
|
166
171
|
- spec/smarter_csv/header_transformation_spec.rb
|
172
|
+
- spec/smarter_csv/invalid_headers_spec.rb
|
167
173
|
- spec/smarter_csv/keep_headers_spec.rb
|
168
174
|
- spec/smarter_csv/key_mapping_spec.rb
|
169
175
|
- spec/smarter_csv/line_ending_spec.rb
|