csv2hash 0.6.8 → 0.7.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: 7c09804fb3f85eacdc90cbfa95ccee0acc8a4fb8
4
- data.tar.gz: d29ac384ef4275b13e087fd0eb504eba2f93d337
3
+ metadata.gz: d0017cb5da55df2b12a7a2a859cb6735dcfe2e17
4
+ data.tar.gz: a720666766679ea852bd1337f6d0795073d30f3f
5
5
  SHA512:
6
- metadata.gz: f2b07b5cfcb24197dec4195873a285f353974960ba29deee2a805da2ee45ce5c8a09838ec04b49fab4e6683672226b46587808ffdaacf066b3c6770f139451e1
7
- data.tar.gz: 5f2fda3e1d08e971ad39ad05bcfbf094f29d1d2e5ca9a86a42cf413d5c7eb502a2ce08bdcfca25c0f1afa5ccd31fe4410bea0cc190ff53fec83e1b7bc319dc54
6
+ metadata.gz: 686218a873857c290b1352f83313031cc29bfb6fb23871eb83c2d3f2b520a59d654c0bc30be9141ea43f83816bc36828b7a44fca86a7e071541dab7186ff6cab
7
+ data.tar.gz: 7d77cc8c42c5facd840c4b8aa34bb9c140822f0947ab54bb229c1866e98993eb9e0b48cc8b6242451538ef8bd27e239c06cf0447b1b77195c3306b786038aff5
data/CHANGELOG.md CHANGED
@@ -1,8 +1,15 @@
1
+ ### VERSION 0.7.0
2
+
3
+ * feature
4
+ * Auto discover is also available for collection.
5
+
6
+ * [fullchanges](https://github.com/FinalCAD/csv2hash/pull/20)
7
+
1
8
  ### VERSION 0.6.8
2
9
 
3
10
  * bug fix
4
11
  * fix typo on generator
5
-
12
+
6
13
  ### VERSION 0.6.7
7
14
 
8
15
  * enhancements
@@ -10,7 +17,7 @@
10
17
 
11
18
  * refactoring
12
19
  * following rails way for naming file
13
-
20
+
14
21
  * [fullchanges](https://github.com/FinalCAD/csv2hash/pull/17)
15
22
 
16
23
  ### VERSION 0.6.6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- csv2hash (0.6.8)
4
+ csv2hash (0.7.0)
5
5
  activesupport (~> 4.1)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -26,8 +26,9 @@ It is a DSL to validate and map a CSV to a Ruby Hash.
26
26
  * [define where your data are expected](#define-where-your-data-are-expected)
27
27
  * [Samples](#samples)
28
28
  * [[MAPPING] Validation of cells with defined precision](#mapping-validation-of-cells-with-defined-precision)
29
- * [Auto discover position feature](#auto-discover-position-feature)
29
+ * [Auto discover position feature in Mapping](#auto-discover-position-feature-in-mapping)
30
30
  * [[COLLECTION] Validation of a collection (Regular CSV)](#collection-validation-of-a-collection-regular-csv)
31
+ * [Auto discover position feature in Collection](#auto-discover-position-feature-in-collection)
31
32
  * [Structure validation rules](#structure-validation-rules)
32
33
  * [CSV Headers](#csv-headers)
33
34
  * [Parser and configuration](#parser-and-configuration)
@@ -210,7 +211,7 @@ class MyParser
210
211
  end
211
212
  ```
212
213
 
213
- ### Auto discover position feature
214
+ ### Auto discover position feature in Mapping
214
215
 
215
216
  This is a special feature for finding the Y index of row where you data start. For instance you have this following data :
216
217
 
@@ -242,6 +243,7 @@ became
242
243
  cell position: [[0, /Employment/],1], key: 'employment'
243
244
  ```
244
245
 
246
+
245
247
  ### [COLLECTION] Validation of a collection (Regular CSV)
246
248
 
247
249
  Consider the following CSV:
@@ -288,6 +290,34 @@ class MyParser
288
290
  end
289
291
  ```
290
292
 
293
+ ### Auto discover position feature in Collection
294
+
295
+ This is a special feature for finding a specific column index on header. For example you have the following data:
296
+
297
+
298
+ ```
299
+ | Name | Age |
300
+ |---------------|---------------|
301
+ | John Doe | 23 |
302
+ | Jane Doe | 28 |
303
+ | | |
304
+ | | |
305
+ ```
306
+
307
+ You want to extract `Name` and 'Age' for all rows but you want the order of the columns to be able to change.
308
+ You change the position to the regex of column index you are looking for. So this how the position
309
+
310
+ ```
311
+ cell position: 0, key: 'name'
312
+ ```
313
+
314
+ can be change to
315
+
316
+ ```
317
+ cell position: /Name/ key: 'name'
318
+ ```
319
+
320
+
291
321
  ### Structure validation rules
292
322
 
293
323
  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.
data/UPGRADE.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Upgrading
2
2
 
3
+ # Upgrading from 0.6.8 to 0.7.0
4
+
5
+ nothing
6
+
3
7
  # Upgrading from 0.6.7 to 0.6.8
4
8
 
5
9
  nothing
@@ -1,22 +1,42 @@
1
1
  module Csv2hash
2
2
  module Discover
3
3
 
4
- def find_dynamic_position cell
5
- y, x = cell.rules.fetch :position
6
- column, matcher = y
7
- dynamic_y_axe = data_source.index { |entries| entries[column] =~ matcher }
4
+ def find_dynamic_position cell, header = nil
5
+ header.present? ? find_dynamic_position_x(cell, header) : find_dynamic_position_y(cell)
6
+ end
7
+
8
+ private
9
+ def find_dynamic_position_y cell
10
+ y, x = cell.rules.fetch :position
11
+ column, matcher = y
12
+ dynamic_y_axe = data_source.index { |entries| entries[column] =~ matcher }
8
13
 
9
- if dynamic_y_axe.nil?
10
- if cell.rules.fetch(:allow_blank)
11
- return nil
14
+ if dynamic_y_axe.nil?
15
+ if cell.rules.fetch(:allow_blank)
16
+ return nil
17
+ else
18
+ raise "Y doesn't found for #{cell.rules[:position]} on :#{cell.rules.fetch(:key)}"
19
+ end
12
20
  else
13
- raise "Y doesn't found for #{cell.rules[:position]} on :#{cell.rules.fetch(:key)}"
21
+ cell.rules[:position] = [dynamic_y_axe, x]
22
+ cell
14
23
  end
15
- else
16
- cell.rules[:position] = [dynamic_y_axe, x]
17
- cell
18
24
  end
19
- end
20
25
 
26
+ def find_dynamic_position_x cell, header
27
+ x = cell.rules.fetch :position
28
+ dynamic_x_axe = header.index { |column| column =~ x }
29
+
30
+ if dynamic_x_axe.nil?
31
+ if cell.rules.fetch(:allow_blank)
32
+ return nil
33
+ else
34
+ raise "Column doesn't found in #{definition.name}"
35
+ end
36
+ else
37
+ cell.rules[:position] = dynamic_x_axe
38
+ cell
39
+ end
40
+ end
21
41
  end
22
42
  end
@@ -5,8 +5,7 @@ module Csv2hash
5
5
  include Discover
6
6
 
7
7
  def validate_rules y=nil
8
- find_or_remove_dynamic_fields! if definition.type == Definition::MAPPING
9
-
8
+ definition.type == Definition::MAPPING ? find_or_remove_dynamic_fields_on_mapping! : find_or_remove_dynamic_fields_on_collection!(y)
10
9
  definition.cells.each do |cell|
11
10
  _y, x = position cell.rules.fetch(:position)
12
11
  begin
@@ -75,14 +74,14 @@ module Csv2hash
75
74
  end
76
75
  end
77
76
 
78
- def find_or_remove_dynamic_fields!
77
+ def find_or_remove_dynamic_fields_on_mapping!
79
78
  cells = definition.cells.dup
80
79
  # cells without optional and not found dynamic field
81
80
  definition.cells = [].tap do |_cells|
82
81
  while(!cells.empty?) do
83
82
  cell = cells.pop
84
83
  _y, x = cell.rules.fetch(:position)
85
- if dynamic_field?(_y)
84
+ if dynamic_field_for_mapping?(_y)
86
85
  begin
87
86
  _cell = find_dynamic_position cell
88
87
  _cells << _cell
@@ -98,9 +97,35 @@ module Csv2hash
98
97
  nil
99
98
  end
100
99
 
101
- def dynamic_field? field
100
+ def find_or_remove_dynamic_fields_on_collection! y
101
+ cells = definition.cells.dup
102
+ # cells without optional and not found dynamic field
103
+ definition.cells = [].tap do |_cells|
104
+ while(!cells.empty?) do
105
+ cell = cells.pop
106
+ x = cell.rules.fetch(:position)
107
+ if dynamic_field_for_collection?(x)
108
+ begin
109
+ _cell = find_dynamic_position cell, data_source.first
110
+ _cells << _cell
111
+ rescue => e
112
+ self.errors << { y: y, x: x, message: e.message, key: cell.rules.fetch(:key) }
113
+ raise if break_on_failure
114
+ end
115
+ else
116
+ _cells << cell
117
+ end
118
+ end
119
+ end.compact
120
+ nil
121
+ end
122
+
123
+ def dynamic_field_for_mapping? field
102
124
  field.is_a?(Array)
103
125
  end
104
126
 
127
+ def dynamic_field_for_collection? field
128
+ field.is_a?(Regexp)
129
+ end
105
130
  end
106
131
  end
@@ -1,3 +1,3 @@
1
1
  module Csv2hash
2
- VERSION = '0.6.8'
2
+ VERSION = '0.7.0'
3
3
  end
@@ -34,6 +34,47 @@ module Csv2hash
34
34
  end
35
35
  end
36
36
 
37
+ context 'discover' do
38
+
39
+ context 'when header keyword present' do
40
+ let(:data_source) { [ ['Name','Age'], [ 'John Doe',34 ], [ 'Jane Doe', 25] ] }
41
+ before do
42
+ subject.definition.header_size = 1
43
+ definition.cells << Cell.new({ position: /Age/, key: 'age' })
44
+ definition.cells << Cell.new({ position: /Name/, key: 'name' })
45
+ end
46
+ it {
47
+ expect(subject.tap { |c| c.parse! }.data).to eql(
48
+ { data: [ { 'name' => 'John Doe', 'age' => 34 }, { 'name' => 'Jane Doe', 'age' => 25} ] }
49
+ )
50
+ }
51
+ end
52
+
53
+ context 'when no header keyword found and no break on failure' do
54
+ let(:data_source) { [ [ 'John Doe',34 ], [ 'Jane Doe', 25] ] }
55
+ before do
56
+ subject.break_on_failure = false
57
+ definition.cells << Cell.new({ position: /Name/, key: 'name' })
58
+ subject.parse
59
+ end
60
+ it{ expect(subject.data).to eql(nil)}
61
+ it{ expect(subject.errors.first[:message]).to eql("Column doesn't found in foo")}
62
+ end
63
+
64
+ context 'when no header keyword found and break on failure' do
65
+ let(:data_source) { [ [ 'John Doe',34 ], [ 'Jane Doe', 25] ] }
66
+ before do
67
+ subject.break_on_failure = true
68
+ definition.cells << Cell.new({ position: /Name/, key: 'name' })
69
+ end
70
+ it 'should throw exception' do
71
+ expect {
72
+ subject.parse
73
+ }.to raise_error("Column doesn't found in foo")
74
+ end
75
+ end
76
+ end
77
+
37
78
  context 'with nested' do
38
79
  let(:data_source) { [ [ 'John Doe', 22 ], [ 'Jane Doe', 19 ] ] }
39
80
  before do
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.6.8
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel AZEMAR