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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 042aadb2bc5426a07a64f09e781bccbd728e8052
4
- data.tar.gz: ba48c2e303591d4027e05d1208c225381d362857
3
+ metadata.gz: 251eb1eff306211d163c6be6880ba45e3eb29985
4
+ data.tar.gz: 9e16d1d4aaab86df7a65d73e6a23ace8f481ba4e
5
5
  SHA512:
6
- metadata.gz: 58cb92edabb46bdcb48598d4b4b02b5f0f09cc63378e818ac672daf8d722b5fbf1b246df5db262dff306e87943a2bb2bebbb753944adc5449b19cd5a1475c00b
7
- data.tar.gz: 31fe30f2b2027274a5252c55b234b120327be6ce652f7ad71232bd8a920e33d30cbae42577fff398d0a61574dc17b3016cd3fa1d520eec3dd4636569cc62860e
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
@@ -1,3 +1,3 @@
1
1
  module SmarterCSV
2
- VERSION = "1.1.5"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -0,0 +1,3 @@
1
+ email,firstname,lastname,email,age
2
+ tom@bla.com,Tom,Sawyer,mike@bla.com,34
3
+ eri@bla.com,Eri Chan,tom@bla.com,21
@@ -0,0 +1,3 @@
1
+ email,firstname,lastname,manager_email,department
2
+ tom@bla.com,Tom,Sawyer,mike@bla.com,IT
3
+ eri@bla.com,Eri Chan,tom@bla.com,IT
@@ -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.1.5
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: 2017-11-06 00:00:00.000000000 Z
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