csv2hash 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|