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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4090ad5c8ae287a7993eaa7dd625fb7afbd3e550
4
- data.tar.gz: 005e9fade78e3197a82bc90e22239447b678544a
3
+ metadata.gz: 8e9db6b93dc1699a3757bb2e9d813285c58e5f4b
4
+ data.tar.gz: aa03c5a3d6679ac7b1598052dbe8cb38a9ea88ae
5
5
  SHA512:
6
- metadata.gz: 6451cd53411bbcb95227fba3a24d3022b89e2d739564065a4d4de9aba9b9de341940a21f5437f4700991c011d5cba85ac4e924e4707d0c0bd6baca793c6680d6
7
- data.tar.gz: 70e8675bf35dfa087805d02ac8cd370e1ab8598f8e5763b901b37a578ca7571b3029657fcdf9c8abffaf83c54d6bea5baa6bce595b105f4fe9e1a067f0841a16
6
+ metadata.gz: d3aa7cdba3548a4bca5e185ee550fbf3812b0912fd5f0a47b4db131a3245a4e736bfb89a93dbd259118cdd37b405a6958fdf4a58d6e07b1ceab208d69436d232
7
+ data.tar.gz: 9485aca4d1047db6566e07b8dd87282c505fe4db9ad5d7cd4db6f5b8097819b50aeeea0c381a2beca64ec1e096938713a04f674c973d80a5995fbd5dc49f9d4a
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- csv2hash (0.1.1)
4
+ csv2hash (0.2.0)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
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::MAPPING, 1)
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
- ### Limitations
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
- * Don't manage number of column you expected on collection mode
327
+ If no configuration is passed, header_size defaults remains to 0
281
328
 
282
329
  ## Contributing
283
330
 
data/ReleaseNotes.md CHANGED
@@ -1,3 +1,8 @@
1
+ VERSION 0.2
2
+
3
+ * The signature of Definition#new
4
+ * Add checking of number of columns
5
+
1
6
  VERSION 0.1
2
7
 
3
8
  * Add csv errors mode
data/csv2hash.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |spec|
2
2
 
3
3
  spec.name = 'csv2hash'
4
- spec.version = '0.1.1'
4
+ spec.version = '0.2.0'
5
5
  spec.date = '2013-11-26'
6
6
  spec.summary = %q{Mapping a CSV to a Ruby Hash}
7
7
  spec.description = %q{DSL to map a CSV to a Ruby Hash}
@@ -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, header_size=0
12
- self.rules, self.type, self.header_size = rules, type, header_size
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
@@ -1,3 +1,3 @@
1
1
  module Cvs2hash
2
- VERSION = '0.1.1'
2
+ VERSION = '0.2.0'
3
3
  end
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
- [ { position: [0,0], key: 'name' } ],
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
- before { subject.definition.header_size = 1 }
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
- before { subject.definition.header_size = 1 }
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.1.1
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