csv2hash 0.1.1 → 0.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/Gemfile.lock +1 -1
- data/README.md +51 -4
- data/ReleaseNotes.md +5 -0
- data/csv2hash.gemspec +1 -1
- data/lib/csv2hash/definition.rb +5 -3
- data/lib/csv2hash/structure_validator/max_columns.rb +18 -0
- data/lib/csv2hash/structure_validator/min_columns.rb +18 -0
- data/lib/csv2hash/structure_validator.rb +27 -0
- data/lib/csv2hash/version.rb +1 -1
- data/lib/csv2hash.rb +7 -0
- data/spec/csv2hash/definition_spec.rb +11 -1
- data/spec/csv2hash/structure_validator_spec.rb +64 -0
- data/spec/csv2hash/validator/collection_spec.rb +4 -4
- metadata +6 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8e9db6b93dc1699a3757bb2e9d813285c58e5f4b
|
4
|
+
data.tar.gz: aa03c5a3d6679ac7b1598052dbe8cb38a9ea88ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3aa7cdba3548a4bca5e185ee550fbf3812b0912fd5f0a47b4db131a3245a4e736bfb89a93dbd259118cdd37b405a6958fdf4a58d6e07b1ceab208d69436d232
|
7
|
+
data.tar.gz: 9485aca4d1047db6566e07b8dd87282c505fe4db9ad5d7cd4db6f5b8097819b50aeeea0c381a2beca64ec1e096938713a04f674c973d80a5995fbd5dc49f9d4a
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -120,7 +120,7 @@ Precise position validation sample:
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def definition
|
123
|
-
Csv2Hash::Definition.new(rules, type = Csv2Hash::Definition::MAPPING, 1)
|
123
|
+
Csv2Hash::Definition.new(rules, type = Csv2Hash::Definition::MAPPING, header_size: 1)
|
124
124
|
end
|
125
125
|
|
126
126
|
end
|
@@ -159,11 +159,45 @@ Collection validation sample:
|
|
159
159
|
end
|
160
160
|
|
161
161
|
def definition
|
162
|
-
Csv2Hash::Definition.new(rules, type = Csv2Hash::Definition::
|
162
|
+
Csv2Hash::Definition.new(rules, type = Csv2Hash::Definition::COLLECTION, header_size: 1)
|
163
163
|
end
|
164
164
|
|
165
165
|
end
|
166
166
|
|
167
|
+
|
168
|
+
### Structure validation rules
|
169
|
+
|
170
|
+
You may want to validate some structure, like min or max number of columns, definition accepts structure_rules as a key for the third parameter.
|
171
|
+
Current validations are: MinColumn, MaxColumn
|
172
|
+
|
173
|
+
class MyParser
|
174
|
+
|
175
|
+
attr_accessor :file_path
|
176
|
+
|
177
|
+
def initialize file_path
|
178
|
+
@file_path = file_path
|
179
|
+
end
|
180
|
+
|
181
|
+
def data
|
182
|
+
@data_wrapper ||= Csv2hash.new(definition, file_path).parse
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
def rules
|
188
|
+
[].tap do |mapping|
|
189
|
+
mapping << { position: 0, key: 'nickname' }
|
190
|
+
mapping << { position: 1, key: 'first_name' }
|
191
|
+
mapping << { position: 2, key: 'last_name' }
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def definition
|
196
|
+
Csv2Hash::Definition.new(rules, type = Csv2Hash::Definition::COLLECTION, structure_rules: {'MinColumn' => 2, 'MaxColumn' => 3})
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
|
167
201
|
### CSV Headers
|
168
202
|
|
169
203
|
You can define the number of rows to skip in the header of the CSV.
|
@@ -275,9 +309,22 @@ Csv data
|
|
275
309
|
[ [ 'Foo' ] ]
|
276
310
|
|
277
311
|
|
278
|
-
###
|
312
|
+
### Upgrading from 0.1 to 0.2
|
313
|
+
|
314
|
+
The signature of Definition#initialize changed, as last parameter is a configuration hash, while in versions prior to 0.2 it was an integer (header_size) consider upgrading your code :
|
315
|
+
|
316
|
+
Prior to 0.2 :
|
317
|
+
|
318
|
+
```
|
319
|
+
Csv2Hash::Definition.new(rules, type = Csv2Hash::Definition::COLLECTION, 1)
|
320
|
+
```
|
321
|
+
|
322
|
+
Starting from 0.2 :
|
323
|
+
```
|
324
|
+
Csv2Hash::Definition.new(rules, type = Csv2Hash::Definition::COLLECTION, header_size: 1)
|
325
|
+
```
|
279
326
|
|
280
|
-
|
327
|
+
If no configuration is passed, header_size defaults remains to 0
|
281
328
|
|
282
329
|
## Contributing
|
283
330
|
|
data/ReleaseNotes.md
CHANGED
data/csv2hash.gemspec
CHANGED
data/lib/csv2hash/definition.rb
CHANGED
@@ -6,10 +6,11 @@ class Csv2hash
|
|
6
6
|
|
7
7
|
TYPES = [MAPPING, COLLECTION]
|
8
8
|
|
9
|
-
attr_accessor :rules, :type, :header_size
|
9
|
+
attr_accessor :rules, :type, :header_size, :structure_rules
|
10
10
|
|
11
|
-
def initialize rules, type,
|
12
|
-
self.rules, self.type
|
11
|
+
def initialize rules, type, options = {}
|
12
|
+
self.rules, self.type = rules, type
|
13
|
+
self.header_size, self.structure_rules = options.fetch(:header_size) { 0 }, options.fetch(:structure_rules) { {} }
|
13
14
|
end
|
14
15
|
|
15
16
|
def validate!
|
@@ -17,6 +18,7 @@ class Csv2hash
|
|
17
18
|
raise "not suitable type, please use '#{MAPPING}' or '#{COLLECTION}'"
|
18
19
|
end
|
19
20
|
raise 'rules must be an Array of rules' unless rules.class == Array
|
21
|
+
raise 'structure rules must be a Hash of rules' unless structure_rules.class == Hash
|
20
22
|
end
|
21
23
|
|
22
24
|
def default!
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Csv2hash::StructureValidator
|
2
|
+
class MaxColumns
|
3
|
+
|
4
|
+
include Csv2hash::StructureValidator::Validator
|
5
|
+
|
6
|
+
def initialize max_size
|
7
|
+
@max_size = max_size
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate_line line
|
11
|
+
line.size > @max_size
|
12
|
+
end
|
13
|
+
|
14
|
+
def error_message line
|
15
|
+
"Too many columns (max. #{@max_size}) on line #{line}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Csv2hash::StructureValidator
|
2
|
+
class MinColumns
|
3
|
+
|
4
|
+
include Csv2hash::StructureValidator::Validator
|
5
|
+
|
6
|
+
def initialize min_size
|
7
|
+
@min_size = min_size
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate_line line
|
11
|
+
line.size < @min_size
|
12
|
+
end
|
13
|
+
|
14
|
+
def error_message line
|
15
|
+
"Not enough columns (min. #{@min_size}) on line #{line}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Csv2hash::StructureValidator
|
2
|
+
class ValidationError < StandardError ; end
|
3
|
+
|
4
|
+
def validate_structure!
|
5
|
+
definition.structure_rules.each do |rule, options|
|
6
|
+
begin
|
7
|
+
rule_instance(rule, options).validate! data_source
|
8
|
+
rescue => e
|
9
|
+
self.errors << e.message
|
10
|
+
raise if exception_mode
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def rule_instance rule, options
|
15
|
+
Csv2hash::StructureValidator.const_get(rule).new(options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module Validator
|
20
|
+
def validate! source
|
21
|
+
source.index { |line| validate_line line }.tap do |line|
|
22
|
+
raise Csv2hash::StructureValidator::ValidationError, error_message(line) unless line.nil?
|
23
|
+
end
|
24
|
+
true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/csv2hash/version.rb
CHANGED
data/lib/csv2hash.rb
CHANGED
@@ -3,6 +3,9 @@ require 'csv2hash/definition'
|
|
3
3
|
require 'csv2hash/validator'
|
4
4
|
require 'csv2hash/validator/mapping'
|
5
5
|
require 'csv2hash/validator/collection'
|
6
|
+
require 'csv2hash/structure_validator'
|
7
|
+
require 'csv2hash/structure_validator/max_columns'
|
8
|
+
require 'csv2hash/structure_validator/min_columns'
|
6
9
|
require 'csv2hash/parser'
|
7
10
|
require 'csv2hash/parser/mapping'
|
8
11
|
require 'csv2hash/parser/collection'
|
@@ -15,6 +18,8 @@ require 'csv'
|
|
15
18
|
|
16
19
|
class Csv2hash
|
17
20
|
|
21
|
+
include Csv2hash::StructureValidator
|
22
|
+
|
18
23
|
attr_accessor :definition, :file_path, :data, :notifier, :exception_mode, :errors, :ignore_blank_line
|
19
24
|
|
20
25
|
def initialize definition, file_path, exception_mode=true, data_source=nil, ignore_blank_line=false
|
@@ -26,6 +31,7 @@ class Csv2hash
|
|
26
31
|
self.notifier = Notifier.new
|
27
32
|
self.ignore_blank_line = ignore_blank_line
|
28
33
|
init_plugins
|
34
|
+
|
29
35
|
end
|
30
36
|
|
31
37
|
def init_plugins
|
@@ -42,6 +48,7 @@ class Csv2hash
|
|
42
48
|
|
43
49
|
definition.validate!
|
44
50
|
definition.default!
|
51
|
+
validate_structure!
|
45
52
|
validate_data!
|
46
53
|
|
47
54
|
Csv2hash::DataWrapper.new.tap do |response|
|
@@ -2,10 +2,11 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Csv2hash::Definition do
|
4
4
|
|
5
|
+
let(:valid_rules) { [ { position: [0,0], key: 'name' } ] }
|
5
6
|
context 'regular context' do
|
6
7
|
subject do
|
7
8
|
Csv2hash::Definition.new(
|
8
|
-
|
9
|
+
valid_rules,
|
9
10
|
Csv2hash::Definition::MAPPING
|
10
11
|
)
|
11
12
|
end
|
@@ -36,6 +37,15 @@ describe Csv2hash::Definition do
|
|
36
37
|
expect { subject.validate! }.to raise_error 'rules must be an Array of rules'
|
37
38
|
end
|
38
39
|
end
|
40
|
+
|
41
|
+
context 'structure rules failling validation' do
|
42
|
+
subject do
|
43
|
+
Csv2hash::Definition.new valid_rules, Csv2hash::Definition::MAPPING, { structure_rules: 'invalid structure rule' }
|
44
|
+
end
|
45
|
+
it 'should throw exception' do
|
46
|
+
expect { subject.validate! }.to raise_error 'structure rules must be a Hash of rules'
|
47
|
+
end
|
48
|
+
end
|
39
49
|
end
|
40
50
|
|
41
51
|
describe '#default!' do
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Csv2hash::StructureValidator do
|
4
|
+
|
5
|
+
let(:rules) { [ { position: [0,0], key: 'name' } ] }
|
6
|
+
let(:options) { {} }
|
7
|
+
let(:definition) do
|
8
|
+
Csv2hash::Definition.new(rules, Csv2hash::Definition::MAPPING, options).tap do |definition|
|
9
|
+
definition.validate!
|
10
|
+
definition.default!
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
subject do
|
15
|
+
Csv2hash.new(definition, 'file_path', true, data_source)
|
16
|
+
end
|
17
|
+
|
18
|
+
context '#MaxColumns' do
|
19
|
+
let(:options){ { structure_rules: { 'MaxColumns' => 2 } } }
|
20
|
+
|
21
|
+
context 'valid data' do
|
22
|
+
let(:data_source) do
|
23
|
+
[
|
24
|
+
[ 'John', 'Doe' ]
|
25
|
+
]
|
26
|
+
end
|
27
|
+
it { expect { subject.validate_structure! }.to_not raise_error }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'invalid data' do
|
31
|
+
let(:data_source) do
|
32
|
+
[
|
33
|
+
[ 'John', 'Doe' ],
|
34
|
+
[ 'Jane', 'Doe', 'extra field' ]
|
35
|
+
]
|
36
|
+
end
|
37
|
+
it { expect { subject.validate_structure! }.to raise_error 'Too many columns (max. 2) on line 1' }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context '#MinColumns' do
|
42
|
+
let(:options){ { structure_rules: { 'MinColumns' => 2 } } }
|
43
|
+
|
44
|
+
context 'valid data' do
|
45
|
+
let(:data_source) do
|
46
|
+
[
|
47
|
+
[ 'John', 'Doe', 'foo' ]
|
48
|
+
]
|
49
|
+
end
|
50
|
+
it { expect { subject.validate_structure! }.to_not raise_error }
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'invalid data' do
|
54
|
+
let(:data_source) do
|
55
|
+
[
|
56
|
+
[ 'John' ],
|
57
|
+
[ 'Jane', 'Doe' ]
|
58
|
+
]
|
59
|
+
end
|
60
|
+
it { expect { subject.validate_structure! }.to raise_error 'Not enough columns (min. 2) on line 0' }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Csv2hash::Validator::Collection do
|
4
|
-
|
4
|
+
let(:options) { {} }
|
5
5
|
let(:definition) do
|
6
|
-
Csv2hash::Definition.new([ { position: 0, key: 'name' } ], Csv2hash::Definition::COLLECTION).tap do |definition|
|
6
|
+
Csv2hash::Definition.new([ { position: 0, key: 'name' } ], Csv2hash::Definition::COLLECTION, options).tap do |definition|
|
7
7
|
definition.validate!
|
8
8
|
definition.default!
|
9
9
|
end
|
@@ -17,7 +17,7 @@ describe Csv2hash::Validator::Collection do
|
|
17
17
|
let(:data_source) { [ [ 'John Doe' ] ]}
|
18
18
|
it { expect { subject.validate_data! }.to_not raise_error }
|
19
19
|
context 'with header' do
|
20
|
-
|
20
|
+
let(:options) { { header_size: 1 } }
|
21
21
|
let(:data_source) { [ [ 'Name' ], [ 'John Doe' ] ]}
|
22
22
|
it { expect { subject.validate_data! }.to_not raise_error }
|
23
23
|
end
|
@@ -37,7 +37,7 @@ describe Csv2hash::Validator::Collection do
|
|
37
37
|
let(:data_source) { [ [ ] ] }
|
38
38
|
it { expect { subject.validate_data! }.to raise_error('undefined name on [0, 0]') }
|
39
39
|
context 'with header' do
|
40
|
-
|
40
|
+
let(:options) { { header_size: 1 } }
|
41
41
|
let(:data_source) { [ [ 'Name' ], [ ] ]}
|
42
42
|
it { expect { subject.validate_data! }.to raise_error('undefined name on [1, 0]') }
|
43
43
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csv2hash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joel AZEMAR
|
@@ -83,6 +83,9 @@ files:
|
|
83
83
|
- lib/csv2hash/parser.rb
|
84
84
|
- lib/csv2hash/parser/collection.rb
|
85
85
|
- lib/csv2hash/parser/mapping.rb
|
86
|
+
- lib/csv2hash/structure_validator.rb
|
87
|
+
- lib/csv2hash/structure_validator/max_columns.rb
|
88
|
+
- lib/csv2hash/structure_validator/min_columns.rb
|
86
89
|
- lib/csv2hash/validator.rb
|
87
90
|
- lib/csv2hash/validator/collection.rb
|
88
91
|
- lib/csv2hash/validator/mapping.rb
|
@@ -91,6 +94,7 @@ files:
|
|
91
94
|
- spec/csv2hash/parser/collection_spec.rb
|
92
95
|
- spec/csv2hash/parser/mapping_spec.rb
|
93
96
|
- spec/csv2hash/parser_spec.rb
|
97
|
+
- spec/csv2hash/structure_validator_spec.rb
|
94
98
|
- spec/csv2hash/validator/collection_spec.rb
|
95
99
|
- spec/csv2hash/validator/mapping_spec.rb
|
96
100
|
- spec/csv2hash/validator_spec.rb
|
@@ -125,6 +129,7 @@ test_files:
|
|
125
129
|
- spec/csv2hash/parser/collection_spec.rb
|
126
130
|
- spec/csv2hash/parser/mapping_spec.rb
|
127
131
|
- spec/csv2hash/parser_spec.rb
|
132
|
+
- spec/csv2hash/structure_validator_spec.rb
|
128
133
|
- spec/csv2hash/validator/collection_spec.rb
|
129
134
|
- spec/csv2hash/validator/mapping_spec.rb
|
130
135
|
- spec/csv2hash/validator_spec.rb
|