simple_csv 0.1.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7f379384bc15e489a0bbb1a8d7a28026e58162a3
4
- data.tar.gz: c239e1ebccf33ed4fe0f9051f7c1a5a65a44f6da
3
+ metadata.gz: accda7d430cbe5c71e9a775bac95f9f8f7c01038
4
+ data.tar.gz: c06a504dbdeaed0f91ee652655ce871a8ef5b18b
5
5
  SHA512:
6
- metadata.gz: 1404a5abbf6bbc700ddcc53ad3edc8e3428c1316c547d516d146202a50b98fde7951a853bb4c21449b090512423ce36644e34e44c545b1234466bf089c7bcad3
7
- data.tar.gz: 432d6aac54b96f6e2775f869484b4ac61ffc1b39927a30c0e334f2f7e3b87068e9bea1ec9267e9219ade9771666552b2f87a1c03b8cd55f6cacddaddc77a311f
6
+ metadata.gz: a979d33a0aab1573a75f7e8f8c98f4fea21b7bd4752b3ef80945f7ccaccb06f289efc947e537929e22d05c3db081ae9b267fb4ba89a562b8067133d07875a2a4
7
+ data.tar.gz: d217b4ccea541d1136d5b2a6381720eb9defdf4d7232445b5d24c5870c3530a2cf3b84fab8266955a1c18cdba59786a6ab3d513a45f4b9fb9e7c61400061772f
data/.gitignore CHANGED
@@ -7,5 +7,5 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
- output.csv
11
- input.csv
10
+ /**/output.csv
11
+ /**/input.csv
data/.rubocop.yml ADDED
@@ -0,0 +1,2 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.3
data/.travis.yml CHANGED
@@ -1,6 +1,10 @@
1
1
  sudo: false
2
2
  language: ruby
3
+ cache: bundler
3
4
  rvm:
5
+ - 2.1.0
6
+ - 2.2.0
4
7
  - 2.2.2
5
8
  - 2.3.0
9
+ - 2.3.3
6
10
  before_install: gem install bundler -v 1.13.6
data/README.md CHANGED
@@ -29,17 +29,84 @@ Or install it yourself as:
29
29
 
30
30
  ## Usage
31
31
 
32
- ### Generating a CSV file
32
+ ### General
33
+
34
+ By default, the settings used will be those of `CSV::DEFAULT_OPTIONS` generally.
35
+ `SimpleCsv` sets the `:headers` property to true by default, this is due to the nature of `SimpleCsv`.
36
+
37
+ Headers have to be defined either before reading or generating a CSV.
38
+ Since `:headers` is now `true` by default, `SimpleCsv` will allow `CSV` to parse the first line as headers.
39
+ These headers are then converted in method calls to use within an `SimpleCsv::Reader#each_row` loop.
40
+
41
+ If however, your file lacks headers, you have the ability to set `:has_headers` to false and supply headers manually before calling `SimpleCsv::Reader#each_row`.
42
+ The headers will be picked up and used instead of the first line.
43
+
44
+ #### SimpleCsv default settings
45
+
46
+ These are the settings that will be merged with settings passed throogh either `SimpleCsv#generate` or `SimpleCsv#read`
47
+
48
+ | setting | value |
49
+ |----------------------|---------------------------------------|
50
+ |`:col_sep` | `","` |
51
+ |`:row_sep` | `:auto` |
52
+ |`:quote_char` | `"\"` |
53
+ |`:field_size_limit` | `nil` |
54
+ |`:converters` | `[:all, :blank_to_nil, :null_to_nil]` |
55
+ |`:unconverted_fields` | `nil` |
56
+ |`:headers` | `true` |
57
+ |`:return_headers` | `false` |
58
+ |`:header_converters` | `nil` |
59
+ |`:skip_blanks` | `false` |
60
+ |`:force_quotes` | `true` |
61
+ |`:skip_lines` | `nil` |
62
+
63
+ The following settings differ from the `CSV::DEFAULT_OPTIONS`
64
+
65
+ * `:converters` is set to `[:all, :blank_to_nil, :null_to_nil]`
66
+ * `:headers` is `true` by default
67
+ * `:force_quotes` is `true` by default
68
+
69
+ This essentially means that when reading a CSV file, headers are required otherwise a `SimpleCsv::HeadersNotSet` exception will be thrown.
70
+ Also, when reading a CSV, all values will be parsed to their respective types, so `"1"` would become `1` as end value.
71
+
72
+ #### SimpleCsv::Writer additional default settings
73
+
74
+ Additionally, `SimpleCsv::Writer` has one additional default setting that ensures an entire row is written before being able to write another one.
75
+ This setting enforces you to call each method once before calling one of them again, if this condition is not met a `SimpleCsv::RowNotComplete` exception will be thrown
33
76
 
34
- The `SimpleCsv#generate` method takes a path and options to use for generating the file.
35
- By default, a CSV is generated using comma's (`,`) as seperator and all fields are quoted.
77
+ | setting | value |
78
+ |------------------------|---------------------------------------|
79
+ |`:force_row_completion` | `true` |
36
80
 
37
- When supplying options they will be merged into the existing defaults rather than overwriting them completely.
81
+ #### Setting aliasses
82
+
83
+ An _alias_ can be used instead of it's respective _setting_.
84
+
85
+ | setting | alias |
86
+ |---------------|---------------|
87
+ | `:col_sep` | `:seperator` |
88
+ | `headers` | `has_headers` |
89
+
90
+ #### Converters
91
+
92
+ The above `:converters` option is set to include `:all` converters and additionally, `:blank_to_nil` and `:null_to_nil`
93
+ The code for these two can be summed up in two lines:
38
94
 
39
95
  ```ruby
40
- SimpleCsv.generate(path, options = { seperator: ',', force_quotes: true })
96
+ CSV::Converters[:blank_to_nil] = ->(f) { f && f.empty? ? nil : f }
97
+ CSV::Converters[:null_to_nil] = ->(f) { f && f == 'NULL' ? nil : f }
41
98
  ```
42
99
 
100
+ What they do replace empty values or the string `'NULL'` by nil within a column when it's being parsed.
101
+ For now, these are the default two and they are always used unless the `:converters` option is set to `nil` within `SimpleCsv#generate` or `SimpleCsv#read`
102
+
103
+ ### Generating a CSV file
104
+
105
+ ```ruby
106
+ SimpleCsv.generate path, options = { ... }, &block
107
+ ```
108
+
109
+ The `SimpleCsv#generate` method takes a (required) path, an (optional) hash of options and a (required) block to start building a CSV file.
43
110
  To generate a CSV file we use `SimpleCsv#generate` (using the [faker](https://github.com/stympy/faker) gem to provide fake data)
44
111
 
45
112
  ```ruby
@@ -63,23 +130,34 @@ end
63
130
 
64
131
  ### Reading a CSV file
65
132
 
66
- The `SimpleCsv#read` method takes a path and options to use for reading the file.
67
- By default, the expected seperator is a comma (`,`), `:headers` is set to `true` so that `CSV` parses the file expecting headers.
68
- The `:converters` option ensures values are converted to a proper type if possible, by default (if this is not set) all values are returned as strings
69
-
70
- When supplying options they will be merged into the existing defaults rather than overwriting them completely.
71
-
72
133
  ```ruby
73
- SimpleCsv.read(path, options = { headers: true, seperator: ',',
74
- converters: [:all, :blank_to_nil, :null_to_nil] })
134
+ SimpleCsv.read path, options = { ... }, &block
75
135
  ```
76
136
 
137
+ The `SimpleCsv#generate` method takes a (required) path, an (optional) hash of options and a (required) block to start building a CSV file.
138
+
77
139
  To read a CSV file we use `SimpleCsv#read`, we will pass it a file path and a block as arguments.
78
140
  Within the block we define the headers present in the file, these will be transformed into methods you can call within `SimpleCsv::Reader#each_row` to get that property's current value
79
141
 
80
142
  ```ruby
81
143
  SimpleCsv.read('input.csv') do
82
- # first define the headers in the file manually
144
+ # assumes headers are set, they will be read and callable within each_row
145
+
146
+ each_row do
147
+ puts [first_name, last_name, birth_date, employed_at].compact.join ', '
148
+ end
149
+ end
150
+ ```
151
+
152
+ ### Reading a CSV file without headers
153
+
154
+ Last but not least, if we have a CSV file that does not contain headers we can use the following setup.
155
+ Setting `:has_headers` to `false` means we do not expect the first line to be headers.
156
+ Therefore we have to explicitly define the headers before looping the CSV.
157
+
158
+ ```ruby
159
+ SimpleCsv.read('headerless.csv', has_headers: false) do
160
+ # first define the headers in the file manually if the file does not have them
83
161
  headers :first_name, :last_name, :birth_date, :employed_at
84
162
 
85
163
  each_row do
@@ -89,18 +167,18 @@ SimpleCsv.read('input.csv') do
89
167
  end
90
168
  ```
91
169
 
92
- If we have a large CSV we might want to batch operations (say, if we are inserting this data into a database).
170
+ ### Batch operations
171
+
172
+ If we have a large CSV we might want to batch operations (say, if we are inserting this data into a database or through an API).
93
173
  For this we can use `SimpleCsv::Reader#in_groups_of` and pass the size of the group.
94
174
  Within that we call `SimpleCsv::Reader#each_row` as usual
95
175
 
96
176
  ```ruby
97
177
  SimpleCsv.read('input.csv') do
98
- # first define the headers in the file manually
99
- headers :first_name, :last_name, :birth_date, :employed_at
178
+ # assumes headers are set, they will be read and callable within each_row
100
179
 
101
180
  in_groups_of(100) do
102
181
  each_row do
103
- # print each field defined in headers (that is not nil)
104
182
  puts [first_name, last_name, birth_date, employed_at].compact.join ', '
105
183
  end
106
184
  # execute after every 100 rows
@@ -109,15 +187,36 @@ SimpleCsv.read('input.csv') do
109
187
  end
110
188
  ```
111
189
 
190
+ ### Aliassing existing headers
191
+
192
+ Should you want to map existing headers to different names, this is possible by passing a hash at the end with key value pairs.
193
+ When generating a CSV file, aliasses are ignored and therefore should not be passed.
194
+
195
+ When defining columns manually using `headers` for a file without headers, ALL columns must be named before defining aliasses.
196
+ This means that if your CSV exists of 3 columns, 3 headers must be defined before aliassing any of those to something shorter or more concise.
197
+
198
+ To create an alias `date_of_birth` of `birth_date` *(In a CSV file without headers)* we would write *(notice `:birth_date` is present twice, once as column entry, and once more as key for an alias)*:
199
+
200
+ ```ruby
201
+ headers :first_name, :last_name, :employed_at, :birth_date, birth_date: :date_of_birth
202
+ ```
203
+
112
204
  ## Development
113
205
 
114
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
206
+ After checking out the repo, run `bundle` to install dependencies. Then, run `rspec` to run the tests. You can also use the `bin/console` file to play around and debug.
207
+
208
+ To install this gem onto your local machine, run `rake install`.
209
+
210
+ To release a new version:
115
211
 
116
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
212
+ * Run CI in dev branch, if tests pass, merge into master
213
+ * Update version number in _lib/simple_csv/version.rb_ according to [symver](http://semver.org/)
214
+ * Update _README.md_ to reflect your changes
215
+ * run `rake release` to push commits, create a tag for the current commit and push the `.gem` file to RubyGems
117
216
 
118
217
  ## Contributing
119
218
 
120
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/simple_csv. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
219
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sidofc/simple_csv. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
121
220
 
122
221
 
123
222
  ## License
data/bin/console CHANGED
@@ -5,27 +5,9 @@ require 'pry'
5
5
  require 'faker'
6
6
  require 'simple_csv'
7
7
 
8
- # CSV generation test
9
- SimpleCsv.generate('spec/files/output.csv') do
10
- headers :first_name, :last_name, :birth_date, :employed_at
11
-
12
- 100.times do
13
- first_name Faker::Name.first_name
14
- last_name Faker::Name.last_name
15
- birth_date Faker::Date.between(Date.today << 1000, Date.today << 200)
16
- employed_at [Faker::Company.name, nil].sample
17
- end
8
+ SimpleCsv.read('spec/files/headerless.csv', has_headers: false) do
9
+ headers :first_name, :last_name, :birth_date, :employed_at, employed_at: :job
10
+ each_row { p job }
18
11
  end
19
12
 
20
- # CSV read test
21
- SimpleCsv.read('spec/files/output.csv') do
22
- headers :first_name, :last_name, :birth_date, :employed_at
23
-
24
- in_groups_of(10) do
25
- each_row :with_index do
26
- puts [index, first_name, last_name,
27
- birth_date, employed_at].compact.join ', '
28
- end
29
- sleep 1
30
- end
31
- end
13
+ # Pry.start
@@ -2,28 +2,38 @@ module SimpleCsv
2
2
  class Base
3
3
  attr_reader :index
4
4
 
5
- COMMON_DELIMITERS = %w(, ; |)
6
- DEFAULTS = { headers: true, col_sep: ',', seperator: ',',
7
- converters: [:all, :blank_to_nil, :null_to_nil] }.freeze
5
+ COMMON_DELIMITERS = %w(, ; |).freeze
6
+
7
+ def debug_headers
8
+ p "@headers is now: #{@headers.join ','}"
9
+ p "@col_map is now #{@col_map}"
10
+ end
8
11
 
9
12
  private
10
13
 
11
14
  def settings(**opts)
12
- @settings ||= DEFAULTS.dup
13
- @settings = @settings.merge opts[:merge] if opts[:merge]
15
+ return @settings.merge opts if opts.any? && @settings
16
+ @settings ||= Settings.new opts
17
+ end
18
+
19
+ def headers(*cols, **col_map)
20
+ @headers ||= []
21
+ @headers.concat cols.map(&:to_s) if cols.any?
22
+
23
+ @col_map ||= {}
24
+ @col_map.merge! stringify_col_map(col_map) if col_map.any?
14
25
 
15
- @settings[:col_sep] = @settings.delete :seperator if @settings[:seperator]
26
+ @headers_set ||= @headers.any?
16
27
 
17
- @settings
28
+ @headers
18
29
  end
19
30
 
20
- def headers(*column_names)
21
- return @headers if column_names.empty?
22
- @headers = column_names.map(&:to_s)
31
+ def stringify_col_map(col_map)
32
+ col_map.to_a.map { |m| m.reverse.map(&:to_s) }.to_h
23
33
  end
24
34
 
25
35
  def respond_to_missing?(mtd, include_private = false)
26
- @headers.include?(mtd) || super
36
+ @headers.include?(mtd) || @col_map.key?(mtd.to_s) || super
27
37
  end
28
38
  end
29
39
  end
@@ -3,15 +3,13 @@ module SimpleCsv
3
3
  attr_reader :index
4
4
 
5
5
  def initialize(path, **opts, &block)
6
- settings merge: opts
6
+ @csv_path = File.expand_path path
7
7
 
8
- unless opts[:seperator]
9
- settings merge: { seperator: detect_delimiter(path) }
10
- end
8
+ opts[:seperator] ||= detect_delimiter
9
+ settings.apply opts
11
10
 
12
- headers(*find_headers(path)) if settings[:headers]
11
+ load_csv_with_auto_headers if settings.for_csv[:headers]
13
12
 
14
- @csv = @original = CSV.open File.expand_path(path), settings
15
13
  instance_eval(&block)
16
14
  end
17
15
 
@@ -27,6 +25,8 @@ module SimpleCsv
27
25
  def each_row(*arr_opts, &block)
28
26
  @index ||= 0 if arr_opts.include?(:with_index)
29
27
 
28
+ load_csv_with_manual_headers unless @csv
29
+
30
30
  @csv.each do |record|
31
31
  @record = record
32
32
  instance_eval(&block)
@@ -34,30 +34,47 @@ module SimpleCsv
34
34
  end
35
35
  end
36
36
 
37
- def respond_to_missing?(mtd, include_private = false)
38
- super
39
- end
37
+ private
40
38
 
41
- def method_missing(mtd, *args, &block)
42
- @headers.include?(mtd.to_s) ? @record[mtd.to_s] : super
39
+ def load_csv_with_auto_headers
40
+ headers(*find_headers)
41
+
42
+ @csv = @original = CSV.open @csv_path, settings.for_csv
43
43
  end
44
44
 
45
- private
45
+ def load_csv_with_manual_headers
46
+ SimpleCsv.csv_manually_set_headers! unless @headers_set
47
+ csv_arr = CSV.open(@csv_path).to_a
46
48
 
47
- def find_headers(csv_path)
48
- sep = detect_delimiter(csv_path)
49
- first_line(csv_path).split(sep).map { |h| h.gsub(/^"*|"*$/, '') }
49
+ if csv_arr.first.size == headers.size
50
+ csv_str = csv_arr.unshift(headers).map(&:to_csv).join
51
+ settings.apply(headers: true)
52
+ @csv = @original = CSV.new csv_str, settings.for_csv
53
+ else
54
+ SimpleCsv.csv_not_enough_headers!
55
+ end
56
+ end
57
+
58
+ def find_headers
59
+ first_line.split(detect_delimiter).map { |h| h.gsub(/^"*|"*$/, '') }
50
60
  end
51
61
 
52
- def detect_delimiter(csv_path)
53
- line = first_line(csv_path)
62
+ def detect_delimiter
63
+ line = first_line
54
64
  @delimiters = COMMON_DELIMITERS.map { |sep| [sep, line.scan(sep).length] }
55
65
  .sort { |a, b| b[1] <=> a[1] }
56
66
  @delimiter ||= @delimiters[0][0]
57
67
  end
58
68
 
59
- def first_line(csv_path)
60
- @first_line ||= File.open(File.expand_path(csv_path), &:readline)
69
+ def first_line
70
+ @first_line ||= File.open @csv_path, &:readline
71
+ end
72
+
73
+ def method_missing(mtd, *args, &block)
74
+ m = mtd.to_s
75
+ return @record[m] if headers.include?(m)
76
+ return @record[@col_map[m]] if @col_map[m]
77
+ super
61
78
  end
62
79
  end
63
80
  end
@@ -0,0 +1,59 @@
1
+ module SimpleCsv
2
+ class Settings
3
+ DEFAULTS = { headers: true, col_sep: ',', seperator: ',',
4
+ force_quotes: true,
5
+ converters: [:all, :blank_to_nil, :null_to_nil] }.freeze
6
+ ALIASSED = { seperator: :col_sep, has_headers: :headers }.freeze
7
+ INVERTED_ALIASSES = ALIASSED.to_a.map(&:reverse).to_h
8
+
9
+ def initialize(**opts)
10
+ @settings = DEFAULTS.dup.merge opts
11
+ end
12
+
13
+ def [](setting)
14
+ send setting
15
+ end
16
+
17
+ def []=(m, val)
18
+ @settings[m] = val
19
+ return @settings[ALIASSED[m]] = val if ALIASSED.key? m
20
+ return @settings[INVERTED_ALIASSES[m]] = val if INVERTED_ALIASSES.key? m
21
+ val
22
+ end
23
+
24
+ def for_csv
25
+ settings = @settings.dup
26
+
27
+ ALIASSED.each do |opt_alias, opt|
28
+ settings[opt] = settings.delete(opt_alias) if settings.key? opt_alias
29
+ end
30
+
31
+ CSV::DEFAULT_OPTIONS.each_with_object({}) do |(prop, default), csv_hash|
32
+ csv_hash[prop] = settings.key?(prop) ? settings[prop] : default
33
+ end
34
+ end
35
+
36
+ def apply(*hashes)
37
+ hashes.each { |opts| opts.each { |k, v| self[k] = v } } && @settings
38
+ end
39
+
40
+ def any?
41
+ @settings && @settings.any?
42
+ end
43
+
44
+ def respond_to_missing?(mtd, include_private = false)
45
+ accepted_method? mtd || super
46
+ end
47
+
48
+ def method_missing(mtd, *args, &block)
49
+ return super unless accepted_method? mtd
50
+ mtd = ALIASSED[mtd] if ALIASSED.key? mtd
51
+ mtd = INVERTED_ALIASSES[mtd] if INVERTED_ALIASSES.key? mtd
52
+ @settings[mtd]
53
+ end
54
+
55
+ def accepted_method?(mtd)
56
+ @settings.key?(mtd) || ALIASSED.key?(mtd) || INVERTED_ALIASSES.key?(mtd)
57
+ end
58
+ end
59
+ end
@@ -1,3 +1,3 @@
1
1
  module SimpleCsv
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,12 +1,10 @@
1
1
  module SimpleCsv
2
2
  class Writer < Base
3
- DEFAULTS = { force_quotes: true }.freeze
4
-
5
3
  def initialize(path, **opts, &block)
6
- settings merge: DEFAULTS.merge(opts)
7
- CSV.open(File.expand_path(path), 'w', @settings) do |csv|
4
+ settings.apply({force_row_completion: true}, opts)
5
+ CSV.open(File.expand_path(path), 'w', settings.for_csv) do |csv|
8
6
  @csv = csv
9
- @current_row = []
7
+ @current_row = {}
10
8
  instance_eval(&block)
11
9
  end
12
10
  end
@@ -18,17 +16,25 @@ module SimpleCsv
18
16
  end
19
17
 
20
18
  def method_missing(mtd, *args, &block)
21
- super unless @headers.include? mtd.to_s
19
+ SimpleCsv.csv_manually_set_headers! unless @headers_written
20
+ super unless headers.include? mtd.to_s
21
+
22
+ if settings.force_row_completion && @current_row.key?(mtd)
23
+ SimpleCsv.row_not_complete!(mtd, args.first)
24
+ end
22
25
 
23
- @current_row << args[0]
24
- row_complete = @current_row.count == @headers.count
25
- (@csv << @current_row) && @current_row = [] if row_complete
26
+ @current_row[mtd] = args.first || ''
27
+
28
+ return unless @current_row.size == headers.size
29
+
30
+ @csv << @current_row.values
31
+ @current_row = {}
26
32
  end
27
33
 
28
- def headers(*column_names)
29
- super
30
- @csv << @headers if @csv
31
- @headers
34
+ def headers(*col_names)
35
+ return @headers if col_names.empty?
36
+ super(*col_names)
37
+ (@csv << @headers) && @headers_written = true if @csv
32
38
  end
33
39
  end
34
40
  end
data/lib/simple_csv.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require 'csv'
2
2
 
3
3
  require 'simple_csv/version'
4
+ require 'simple_csv/settings'
4
5
  require 'simple_csv/base'
5
6
  require 'simple_csv/reader'
6
7
  require 'simple_csv/writer'
@@ -8,6 +9,26 @@ require 'simple_csv/writer'
8
9
  module SimpleCsv
9
10
  @converters_initialized = false
10
11
 
12
+ class RowNotComplete < StandardError; end
13
+ class UnparseableCsv < StandardError; end
14
+ class HeadersNotSet < UnparseableCsv; end
15
+ class NotEnoughHeaders < UnparseableCsv; end
16
+
17
+ def self.row_not_complete!(mtd, value)
18
+ raise RowNotComplete,
19
+ "Row not complete! #{mtd} called twice with value #{value}"
20
+ end
21
+
22
+ def self.csv_not_enough_headers!
23
+ raise NotEnoughHeaders, 'Not enough headers defined!'
24
+ end
25
+
26
+ def self.csv_manually_set_headers!
27
+ raise HeadersNotSet,
28
+ ['CSV does not contain headers',
29
+ 'please add headers in them manually or in the file'].join(', ')
30
+ end
31
+
11
32
  def self.read(path, **options, &block)
12
33
  initialize_converters unless converters_initialized
13
34
  Reader.new path, options, &block
data/simple_csv.gemspec CHANGED
@@ -22,6 +22,8 @@ Gem::Specification.new do |spec|
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ['lib']
24
24
 
25
+ spec.required_ruby_version = '>= 2.1'
26
+
25
27
  spec.add_development_dependency 'bundler', '~> 1.13'
26
28
  spec.add_development_dependency 'rake', '~> 10.0'
27
29
  spec.add_development_dependency 'rspec', '~> 3.0'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_csv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sidney Liebrand
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-12-19 00:00:00.000000000 Z
11
+ date: 2016-12-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -117,6 +117,7 @@ extra_rdoc_files: []
117
117
  files:
118
118
  - ".gitignore"
119
119
  - ".rspec"
120
+ - ".rubocop.yml"
120
121
  - ".travis.yml"
121
122
  - CODE_OF_CONDUCT.md
122
123
  - Gemfile
@@ -128,6 +129,7 @@ files:
128
129
  - lib/simple_csv.rb
129
130
  - lib/simple_csv/base.rb
130
131
  - lib/simple_csv/reader.rb
132
+ - lib/simple_csv/settings.rb
131
133
  - lib/simple_csv/version.rb
132
134
  - lib/simple_csv/writer.rb
133
135
  - simple_csv.gemspec
@@ -143,7 +145,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
143
145
  requirements:
144
146
  - - ">="
145
147
  - !ruby/object:Gem::Version
146
- version: '0'
148
+ version: '2.1'
147
149
  required_rubygems_version: !ruby/object:Gem::Requirement
148
150
  requirements:
149
151
  - - ">="