csv2hash 0.2.1 → 0.3.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: 9ab8b867d5257761c23fb310ad45eab25d5eebe9
4
- data.tar.gz: ffec55a91cb1ccd853e641b65f965cc0a51c0350
3
+ metadata.gz: 712c36523387610b2faba0dfb934e772a281ee19
4
+ data.tar.gz: 9275f05691e92eda1e32f08395bae382282515fd
5
5
  SHA512:
6
- metadata.gz: 801f045f211e3dffaafad4c27dffd922132b40be5bc98b2013fafa676f7c3a7584bfad7f5c39ce96dc34a7ace3033cfd54f5505812d61e58ba0c20b6b956228c
7
- data.tar.gz: d446c104f67af25a884fabfa3784b2baaaeaf559de8cb8d901c55acef7762966a4aa1ff80b637cfbda25e18c75bcc725b29fd3a1b97212ef9d3b7719ae628b78
6
+ metadata.gz: f37e0262f38b234f2b0b092f8e9f9a048e43e91dbd732d27e83911097989956567cc9482547ed868bdaf3240d5f149f55024b8721d2d5c5b24365a610ab239c6
7
+ data.tar.gz: 5d0bf911880893b7af380c61b9339bd6820a82b862bc2af4214e1453ca1abe7013b85a837a467d1ca8f491c6f0fad7bdc86bca74382e627d20bc8faa189b204b
data/.coveralls.yml CHANGED
@@ -1 +1 @@
1
- repo_token: N3Ql9kjuVUDMaof2gKqn1TiNXt4bYfRUw
1
+ service_name: travis-ci
data/.travis.yml CHANGED
@@ -1,3 +1,4 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.0.0
3
+ - 2.1.2
4
+ script: bundle exec rspec spec
data/Gemfile CHANGED
@@ -3,7 +3,6 @@ source 'http://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  group :test do
6
- gem 'guard'
7
- gem 'guard-rspec'
8
6
  gem 'coveralls', require: false
9
- end
7
+ gem 'pry'
8
+ end
data/Gemfile.lock CHANGED
@@ -1,70 +1,56 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- csv2hash (0.2.1)
4
+ csv2hash (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: http://rubygems.org/
8
8
  specs:
9
- celluloid (0.15.2)
10
- timers (~> 1.1.0)
11
9
  coderay (1.1.0)
12
- coveralls (0.7.0)
10
+ coveralls (0.7.1)
13
11
  multi_json (~> 1.3)
14
12
  rest-client
15
13
  simplecov (>= 0.7)
16
14
  term-ansicolor
17
15
  thor
18
16
  diff-lcs (1.2.5)
19
- docile (1.1.1)
20
- ffi (1.9.3)
21
- formatador (0.2.4)
22
- guard (2.2.4)
23
- formatador (>= 0.2.4)
24
- listen (~> 2.1)
25
- lumberjack (~> 1.0)
26
- pry (>= 0.9.12)
27
- thor (>= 0.18.1)
28
- guard-rspec (4.0.4)
29
- guard (>= 2.1.1)
30
- rspec (~> 2.14)
31
- listen (2.2.0)
32
- celluloid (>= 0.15.2)
33
- rb-fsevent (>= 0.9.3)
34
- rb-inotify (>= 0.9)
35
- lumberjack (1.0.4)
17
+ docile (1.1.5)
18
+ its (0.2.0)
19
+ rspec-core
36
20
  method_source (0.8.2)
37
- mime-types (2.0)
38
- multi_json (1.8.2)
39
- pry (0.9.12.4)
40
- coderay (~> 1.0)
41
- method_source (~> 0.8)
21
+ mime-types (2.3)
22
+ multi_json (1.10.1)
23
+ netrc (0.7.7)
24
+ pry (0.10.0)
25
+ coderay (~> 1.1.0)
26
+ method_source (~> 0.8.1)
42
27
  slop (~> 3.4)
43
- rake (10.1.0)
44
- rb-fsevent (0.9.3)
45
- rb-inotify (0.9.2)
46
- ffi (>= 0.5.0)
47
- rest-client (1.6.7)
48
- mime-types (>= 1.16)
49
- rspec (2.14.1)
50
- rspec-core (~> 2.14.0)
51
- rspec-expectations (~> 2.14.0)
52
- rspec-mocks (~> 2.14.0)
53
- rspec-core (2.14.7)
54
- rspec-expectations (2.14.4)
55
- diff-lcs (>= 1.1.3, < 2.0)
56
- rspec-mocks (2.14.4)
57
- simplecov (0.8.2)
28
+ rake (10.3.2)
29
+ rest-client (1.7.2)
30
+ mime-types (>= 1.16, < 3.0)
31
+ netrc (~> 0.7)
32
+ rspec (3.0.0)
33
+ rspec-core (~> 3.0.0)
34
+ rspec-expectations (~> 3.0.0)
35
+ rspec-mocks (~> 3.0.0)
36
+ rspec-core (3.0.4)
37
+ rspec-support (~> 3.0.0)
38
+ rspec-expectations (3.0.4)
39
+ diff-lcs (>= 1.2.0, < 2.0)
40
+ rspec-support (~> 3.0.0)
41
+ rspec-mocks (3.0.4)
42
+ rspec-support (~> 3.0.0)
43
+ rspec-support (3.0.4)
44
+ simplecov (0.9.0)
58
45
  docile (~> 1.1.0)
59
46
  multi_json
60
47
  simplecov-html (~> 0.8.0)
61
48
  simplecov-html (0.8.0)
62
- slop (3.4.7)
63
- term-ansicolor (1.2.2)
64
- tins (~> 0.8)
65
- thor (0.18.1)
66
- timers (1.1.0)
67
- tins (0.13.1)
49
+ slop (3.5.0)
50
+ term-ansicolor (1.3.0)
51
+ tins (~> 1.0)
52
+ thor (0.19.1)
53
+ tins (1.3.2)
68
54
 
69
55
  PLATFORMS
70
56
  ruby
@@ -73,7 +59,7 @@ DEPENDENCIES
73
59
  bundler (~> 1.3)
74
60
  coveralls
75
61
  csv2hash!
76
- guard
77
- guard-rspec
62
+ its
63
+ pry
78
64
  rake
79
65
  rspec
data/README.md CHANGED
@@ -1,13 +1,12 @@
1
1
  # Csv2Hash
2
2
 
3
- [![Code Climate](https://codeclimate.com/github/joel/csv2hash.png)](https://codeclimate.com/github/joel/csv2hash)
3
+ [![Code Climate](https://codeclimate.com/github/FinalCAD/csv2hash.png)](https://codeclimate.com/github/FinalCAD/csv2hash)
4
4
 
5
- [![Dependency Status](https://gemnasium.com/joel/csv2hash.png)](https://gemnasium.com/joel/csv2hash)
5
+ [![Dependency Status](https://gemnasium.com/FinalCAD/csv2hash.png)](https://gemnasium.com/FinalCAD/csv2hash)
6
6
 
7
- [![Build Status](https://travis-ci.org/joel/csv2hash.png?branch=master)](https://travis-ci.org/joel/csv2hash) (Travis CI)
8
-
9
- [![Coverage Status](https://coveralls.io/repos/joel/csv2hash/badge.png)](https://coveralls.io/r/joel/csv2hash)
7
+ [![Build Status](https://travis-ci.org/FinalCAD/csv2hash.png?branch=master)](https://travis-ci.org/FinalCAD/csv2hash) (Travis CI)
10
8
 
9
+ [![Coverage Status](https://coveralls.io/repos/FinalCAD/csv2hash/badge.png)](https://coveralls.io/r/FinalCAD/csv2hash)
11
10
 
12
11
  It is a DSL to validate and map a CSV to a Ruby Hash.
13
12
 
@@ -31,33 +30,45 @@ Parsing is based on rules, you must defined rules of parsing
31
30
 
32
31
  ### Rules
33
32
 
34
- You should declare a definition for you CSV, and then define for each cell what you would expect.
33
+ You should declared a definition for you CSV, and then define for each cell what you would expect.
35
34
 
36
35
  Example :
37
36
 
38
37
  If you want the very first cell, located on the first line and on the first column to be a string with values are either 'yes' either 'no', you can write the following validation rule:
39
38
 
39
+ ```
40
40
  { name: 'aswering', type: 'string', values: ['yes', 'no'], position: [0,0] }
41
+ ```
41
42
 
42
43
  :type attribute has 'string' for default value, therefore you can just write this:
43
44
 
45
+ ```
44
46
  { name: 'aswering', values: ['yes', 'no'], position: [0,0] }
47
+ ```
45
48
 
46
49
  You can define you own message but default message is 'undefined :key on :position'
47
50
 
51
+ ```
48
52
  { name: 'aswering', values: ['yes', 'no'], position: [0,0], message: 'this value is not supported' }
53
+ ```
49
54
 
50
55
  You can also define Range of values
51
56
 
57
+ ```
52
58
  { name: 'score', values: 0..5, position: [0,0] }
59
+ ```
53
60
 
54
61
  The message is parsed:
55
62
 
63
+ ```
56
64
  { ..., message: 'value of :name is not supported, please you one of :values' }
65
+ ```
57
66
 
58
67
  It produces :
59
68
 
69
+ ```
60
70
  value of answering is not supported, please use one of [yes, no]
71
+ ```
61
72
 
62
73
  ### Default values
63
74
 
@@ -77,7 +88,7 @@ All remaining keys are optionals:
77
88
 
78
89
  ## Define where your data is expected
79
90
 
80
- **IMPORTANT!** Position mean [Y, X], where Y is rows, X columns
91
+ **IMPORTANT!** Position means [Y, X], where Y is rows, X columns
81
92
 
82
93
  A definition should be provided. There are 2 types of definitions:
83
94
  * search for data at a precise position in the table: `y,x`
@@ -98,16 +109,17 @@ Consider the following CSV:
98
109
 
99
110
  Precise position validation sample:
100
111
 
112
+ ```
101
113
  class MyParser
102
114
 
103
- attr_accessor :file_path
115
+ attr_accessor :file_path_or_data
104
116
 
105
- def initialize file_path
106
- @file_path = file_path
117
+ def initialize file_path_or_data
118
+ @file_path_or_data = file_path_or_data
107
119
  end
108
120
 
109
121
  def data
110
- @data_wrapper ||= Csv2hash.new(definition, file_path).parse
122
+ @data_wrapper ||= Csv2hash::Main.new(definition, file_path_or_data).parse
111
123
  end
112
124
 
113
125
  private
@@ -124,6 +136,7 @@ Precise position validation sample:
124
136
  end
125
137
 
126
138
  end
139
+ ```
127
140
 
128
141
  ### Validation of a collection (Regular CSV)
129
142
 
@@ -136,16 +149,17 @@ Consider the following CSV:
136
149
 
137
150
  Collection validation sample:
138
151
 
152
+ ```
139
153
  class MyParser
140
154
 
141
- attr_accessor :file_path
155
+ attr_accessor :file_path_or_data
142
156
 
143
- def initialize file_path
144
- @file_path = file_path
157
+ def initialize file_path_or_data
158
+ @file_path_or_data = file_path_or_data
145
159
  end
146
160
 
147
161
  def data
148
- @data_wrapper ||= Csv2hash.new(definition, file_path).parse
162
+ @data_wrapper ||= Csv2hash::Main.new(definition, file_path_or_data).parse
149
163
  end
150
164
 
151
165
  private
@@ -163,68 +177,79 @@ Collection validation sample:
163
177
  end
164
178
 
165
179
  end
180
+ ```
166
181
 
167
182
  ### Structure validation rules
168
183
 
169
184
  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.
170
185
  Current validations are: MinColumn, MaxColumn
171
186
 
172
- class MyParser
187
+ ```
188
+ class MyParser
173
189
 
174
- attr_accessor :file_path
190
+ attr_accessor :file_path_or_data
175
191
 
176
- def initialize file_path
177
- @file_path = file_path
178
- end
192
+ def initialize file_path_or_data
193
+ @file_path_or_data = file_path_or_data
194
+ end
179
195
 
180
- def data
181
- @data_wrapper ||= Csv2hash.new(definition, file_path).parse
182
- end
196
+ def data
197
+ @data_wrapper ||= Csv2hash::Main.new(definition, file_path_or_data).parse
198
+ end
183
199
 
184
- private
200
+ private
185
201
 
186
- def rules
187
- [].tap do |mapping|
188
- mapping << { position: 0, key: 'nickname' }
189
- mapping << { position: 1, key: 'first_name' }
190
- mapping << { position: 2, key: 'last_name' }
191
- end
192
- end
202
+ def rules
203
+ [].tap do |mapping|
204
+ mapping << { position: 0, key: 'nickname' }
205
+ mapping << { position: 1, key: 'first_name' }
206
+ mapping << { position: 2, key: 'last_name' }
207
+ end
208
+ end
193
209
 
194
- def definition
195
- Csv2Hash::Definition.new(rules, type = Csv2Hash::Definition::COLLECTION, structure_rules: { 'MinColumns' => 2, 'MaxColumns' => 3 })
210
+ def definition
211
+ Csv2Hash::Definition.new(rules, type = Csv2Hash::Definition::COLLECTION,
212
+ structure_rules: { 'MinColumns' => 2, 'MaxColumns' => 3 })
213
+ end
196
214
  end
197
- end
198
-
215
+ ```
199
216
 
200
217
  ### CSV Headers
201
218
 
202
219
  You can define the number of rows to skip in the header of the CSV.
203
220
 
221
+ ```
204
222
  Definition.new(rules, type, header_size: 0)
223
+ ```
205
224
 
206
225
  ### Parser and configuration
207
226
 
208
227
  Pasrer can take several parameters like that:
209
228
 
210
- definition, file_path, exception_mode=true, data_source=nil, ignore_blank_line=false
229
+ ```
230
+ definition, file_path_or_data, exception_mode=true, ignore_blank_line=false
231
+ ```
211
232
 
212
- you can pass directly Array of data (Array at 2 dimensions) really useful for testing, if you don't care about blank lines in your CSV you can ignore them.
233
+ in file_path_or_data attribubte you can pass directly an Array of data (Array with 2 dimensions) really useful for testing, if you don't care about blank lines in your CSV you can ignore them.
213
234
 
214
235
  ### Response
215
236
 
216
237
  The parser return values wrapper into DataWrapper Object, you can call ```.valid?``` method on this Object and grab either data or errors like that :
217
238
 
239
+ ```
218
240
  response = parser.parse
219
241
  if response.valid?
220
242
  response.data
221
243
  else
222
244
  response.errors
223
245
  end
246
+ ```
224
247
 
225
248
  data or errors are Array, but errors can be formatted on csv format with .to_csv call
226
249
 
250
+ ```
227
251
  response.errors.to_csv
252
+ ```
228
253
 
229
254
  ## Exception or Not !
230
255
 
@@ -236,13 +261,16 @@ You can choose into 2 different modes of parsing, either **exception mode** for
236
261
 
237
262
  in your code
238
263
 
239
- parser = Csv2hash.new(definition, 'file_path').new
264
+ ```
265
+ parser = Csv2hash::Main.new(definition, file_path_or_data, exception_mode=true, ignore_blank_line=false).new
240
266
  response = parser.parse
241
267
  return response if response.valid?
242
268
  # Whatever
269
+ ```
243
270
 
244
271
  In the same time Csv2hash call **notify(response)** method when CSV parsing fail, you can add your own Notifier:
245
272
 
273
+ ```
246
274
  module Csv2hash
247
275
  module Plugins
248
276
  class Notifier
@@ -262,6 +290,7 @@ In the same time Csv2hash call **notify(response)** method when CSV parsing fail
262
290
  end
263
291
  end
264
292
  end
293
+ ```
265
294
 
266
295
  Or other implementation
267
296
 
@@ -269,7 +298,9 @@ Or other implementation
269
298
 
270
299
  errors is a Array of Hash
271
300
 
301
+ ```
272
302
  { y: 1, x: 0, message: 'message', key: 'key', value: '' }
303
+ ```
273
304
 
274
305
  ## Sample
275
306
 
@@ -281,11 +312,15 @@ errors is a Array of Hash
281
312
 
282
313
  ### Rule
283
314
 
315
+ ```
284
316
  { position: [1,1], key: 'nickname', allow_blank: false }
317
+ ```
285
318
 
286
319
  ### Error
287
320
 
321
+ ```
288
322
  { y: 1, x: 1, message: 'undefined nikcname on [0, 0]', key: 'nickname', value: nil }
323
+ ```
289
324
 
290
325
  ## Personal Validator Rule
291
326
 
@@ -293,20 +328,43 @@ You can define your own Validator
293
328
 
294
329
  For downcase validation
295
330
 
331
+ ```
296
332
  class DowncaseValidator < Csv2hash::ExtraValidator
297
333
  def valid? value
298
334
  !!(value.match /^[a-z]+$/)
299
335
  end
300
336
  end
337
+ ```
301
338
 
302
339
  in your rule
303
340
 
341
+ ```
304
342
  { position: [0,0], key: 'name', extra_validator: DowncaseValidator.new,
305
343
  message: 'your data should be written in lowercase only.' }
344
+ ```
306
345
 
307
346
  Csv data
308
347
 
348
+ ```
309
349
  [ [ 'Foo' ] ]
350
+ ```
351
+
352
+ # Upgrading from 0.2 to 0.3
353
+
354
+ ```Csv2hash``` become an ```Module```, ```Csv2hash.new``` no longer works, please use ```Csv2hash::Main.new``` instead.
355
+ Signature of ```Csv2hash::Main#new``` has changed too
356
+
357
+ Prior to 0.3 :
358
+
359
+ ```
360
+ Csv2Hash.new(definition, file_path, exception_mode=true, data_source=nil, ignore_blank_line=false)
361
+ ```
362
+
363
+ Starting from 0.3 :
364
+
365
+ ```
366
+ Csv2Hash::Main.new(definition, file_path_or_data, exception_mode=true, ignore_blank_line=false)
367
+ ```
310
368
 
311
369
  # Upgrading from 0.1 to 0.2
312
370
 
@@ -319,6 +377,7 @@ Prior to 0.2 :
319
377
  ```
320
378
 
321
379
  Starting from 0.2 :
380
+
322
381
  ```
323
382
  Csv2Hash::Definition.new(rules, type = Csv2Hash::Definition::COLLECTION, header_size: 1)
324
383
  ```
@@ -331,4 +390,4 @@ If no configuration is passed, header_size defaults remains to 0
331
390
  2. Create your feature branch (`git checkout -b my-new-feature`)
332
391
  3. Commit your changes (`git commit -am 'Added some feature'`)
333
392
  4. Push to the branch (`git push origin my-new-feature`)
334
- 5. Create new Pull Request
393
+ 5. Create new Pull Request
data/ReleaseNotes.md CHANGED
@@ -1,25 +1,42 @@
1
- VERSION 0.2.1
1
+ ### VERSION 0.3.0
2
2
 
3
- * Correct little bug on error mode.
3
+ * backwards incompatible changes
4
+ * Csv2hash is module now, call Csv2hash::Main.new
5
+ * The signature of Csv2hash::Main#new has changed.
4
6
 
5
- VERSION 0.2
7
+ * refactoring
8
+ * Use adapter to select source of data, either file.csv or Array of data, is more transparently, not impact signature of Csv2Hash constructor
6
9
 
7
- * The signature of Definition#new
8
- * Add checking of number of columns
10
+ ### VERSION 0.2.1
9
11
 
10
- VERSION 0.1
12
+ * bug fix
13
+ * Correct little bug on error mode.
11
14
 
12
- * Add csv errors mode
13
- * Add Extra Validator
14
- * Add Notifier Plugin
15
- * Add Data Wrapper Response
16
- * Add possibility to pass directly data in constructor, for more testing
17
- * You can ignore blank line
15
+ ### VERSION 0.2
18
16
 
19
- VERSION 0.0.2
17
+ * backwards incompatible changes
18
+ * The signature of Definition#new
20
19
 
21
- * Liitle enhancement
20
+ * enhancements
21
+ * Add checking of number of columns
22
22
 
23
- VERSION 0.0.1
23
+ * deprecations
24
24
 
25
- * Skeleton and first parsing
25
+ ### VERSION 0.1
26
+
27
+ * enhancements
28
+ * Add csv errors mode
29
+ * Add Extra Validator
30
+ * Add Notifier Plugin
31
+ * Add Data Wrapper Response
32
+ * Add possibility to pass directly data in constructor, for more testing
33
+ * You can ignore blank line
34
+
35
+ ### VERSION 0.0.2
36
+
37
+ * enhancements
38
+ * Liitle enhancement
39
+
40
+ ### VERSION 0.0.1
41
+
42
+ * Skeleton and first parsing
File without changes
data/csv2hash.gemspec CHANGED
@@ -1,7 +1,8 @@
1
- Gem::Specification.new do |spec|
1
+ require_relative 'lib/csv2hash/version'
2
2
 
3
+ Gem::Specification.new do |spec|
3
4
  spec.name = 'csv2hash'
4
- spec.version = '0.2.1'
5
+ spec.version = Csv2hash::VERSION
5
6
  spec.date = '2013-11-26'
6
7
  spec.summary = %q{Mapping a CSV to a Ruby Hash}
7
8
  spec.description = %q{DSL to map a CSV to a Ruby Hash}
@@ -19,6 +20,6 @@ Gem::Specification.new do |spec|
19
20
  spec.add_development_dependency 'bundler', '~> 1.3'
20
21
  spec.add_development_dependency 'rake'
21
22
  spec.add_development_dependency 'rspec'
22
-
23
- spec.required_ruby_version = '~> 2.0'
23
+ spec.add_development_dependency 'its'
24
+ spec.required_ruby_version = '~> 2.1'
24
25
  end
@@ -0,0 +1,11 @@
1
+ module Csv2hash
2
+ module Adapter
3
+ class Abstract
4
+
5
+ def source
6
+ raise NotImplementedError
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ module Csv2hash
2
+ module Adapter
3
+ class Base
4
+
5
+ class UnsupportedAdapter < StandardError ; end
6
+
7
+ def self.create adapter_name, file_path_or_data
8
+ # binding.pry
9
+ load "csv2hash/adapters/#{adapter_name}_adapter.rb"
10
+ class_eval("Csv2hash::Adapter::#{klass_adapter(adapter_name)}").new file_path_or_data
11
+ end
12
+
13
+ private
14
+
15
+ def self.klass_adapter adapter_symbol
16
+ case adapter_symbol
17
+ when :memory then :MemoryAdapter
18
+ when :csv then :CsvAdapter
19
+ else raise UnsupportedAdapter.new
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ require_relative 'abstract'
2
+
3
+ require 'csv'
4
+
5
+ module Csv2hash
6
+ module Adapter
7
+ class CsvAdapter < Abstract
8
+
9
+ attr_accessor :file_path
10
+
11
+ def initialize file_path
12
+ self.file_path = file_path
13
+ end
14
+
15
+ def source
16
+ CSV.read self.file_path
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ require_relative 'abstract'
2
+
3
+ module Csv2hash
4
+ module Adapter
5
+ class MemoryAdapter < Abstract
6
+
7
+ attr_accessor :data
8
+
9
+ def initialize data
10
+ self.data = data
11
+ end
12
+
13
+ def source
14
+ self.data
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -1,4 +1,4 @@
1
- class Csv2hash
1
+ module Csv2hash
2
2
  class DataWrapper
3
3
 
4
4
  attr_accessor :data, :errors, :valid
@@ -10,4 +10,4 @@ class Csv2hash
10
10
 
11
11
  def valid?() valid ; end
12
12
  end
13
- end
13
+ end
@@ -1,8 +1,8 @@
1
- class Csv2hash
1
+ module Csv2hash
2
2
  class Definition
3
3
 
4
- MAPPING = 'mapping'
5
- COLLECTION = 'collection'
4
+ MAPPING = 'mapping'.freeze
5
+ COLLECTION = 'collection'.freeze
6
6
 
7
7
  TYPES = [MAPPING, COLLECTION]
8
8
 
@@ -1,4 +1,4 @@
1
- class Csv2hash
1
+ module Csv2hash
2
2
  class ExtraValidator
3
3
  def valid?(rule, value) raise 'method parse!() should be implemented in sub class'; end
4
4
  end
@@ -1,4 +1,4 @@
1
- class Csv2hash
1
+ module Csv2hash
2
2
  class Notifier
3
3
  def notify response
4
4
  # puts 'Csv with errors'