csv-importer 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +33 -9
- data/README.md +21 -1
- data/lib/csv_importer.rb +4 -1
- data/lib/csv_importer/column_definition.rb +1 -1
- data/lib/csv_importer/csv_reader.rb +12 -1
- data/lib/csv_importer/report.rb +2 -2
- data/lib/csv_importer/row.rb +9 -8
- data/lib/csv_importer/version.rb +1 -1
- metadata +3 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5e17c85aa62e6f2774f1cb86dcea9d7743622b73690fb896228d1bf7ce54951e
|
4
|
+
data.tar.gz: acfd22bf68c1c228a0afecba046cf3cb7231311192ee1ee5c88828a56a51f429
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c5c8894e68eaa33418761a9cad3ab8f0ddfea0eeaa3e62101ab1105a40978b7c206dc7448a4b536f9efc06c06b952935146efe9b4ae010c9a3f98428f649b641
|
7
|
+
data.tar.gz: 66f498dc9d2e62bf413ba35ac362b03fa557640c724cafb8cc38686bfe825334455d936c1c8a4e79b97fc4ec0355887cb0f6dee178b0f3893d0b37c6dc043b09
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,22 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
+
## [0.7.0] - 2019-11-29
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
* Improve algorithm to detect separators. [#88][] by [@brain-geek][]
|
10
|
+
* `to:` accepts anything that responds to `#call` (lambda, procs,
|
11
|
+
classes etc). [#72][] by [@pcreux][] inspired by [#71][] by [@macfanatic][].
|
12
|
+
|
13
|
+
### Fixed
|
14
|
+
|
15
|
+
* `valid_header?` returns `false` when the CSV is malformed instead of
|
16
|
+
raising an exception. [#85][] by [@mltsy][]
|
17
|
+
* Header infos (ex: `extra_columns`) aren't discarded after running an
|
18
|
+
import. [#83][] by [@mltsy][]
|
19
|
+
|
20
|
+
|
5
21
|
## [0.6.0] - 2018-05-22
|
6
22
|
|
7
23
|
### Added
|
@@ -166,19 +182,27 @@ report object instead of raising an exception.
|
|
166
182
|
* Initial Release
|
167
183
|
|
168
184
|
<!--- The following link definition list is generated by PimpMyChangelog --->
|
169
|
-
[#26]: https://github.com/
|
170
|
-
[#38]: https://github.com/
|
171
|
-
[#47]: https://github.com/
|
172
|
-
[#52]: https://github.com/
|
173
|
-
[#63]: https://github.com/
|
174
|
-
[#68]: https://github.com/
|
175
|
-
[#69]: https://github.com/
|
176
|
-
[#
|
185
|
+
[#26]: https://github.com/pcreux/csv-importer/issues/26
|
186
|
+
[#38]: https://github.com/pcreux/csv-importer/issues/38
|
187
|
+
[#47]: https://github.com/pcreux/csv-importer/issues/47
|
188
|
+
[#52]: https://github.com/pcreux/csv-importer/issues/52
|
189
|
+
[#63]: https://github.com/pcreux/csv-importer/issues/63
|
190
|
+
[#68]: https://github.com/pcreux/csv-importer/issues/68
|
191
|
+
[#69]: https://github.com/pcreux/csv-importer/issues/69
|
192
|
+
[#71]: https://github.com/pcreux/csv-importer/issues/71
|
193
|
+
[#72]: https://github.com/pcreux/csv-importer/issues/72
|
194
|
+
[#73]: https://github.com/pcreux/csv-importer/issues/73
|
195
|
+
[#83]: https://github.com/pcreux/csv-importer/issues/83
|
196
|
+
[#85]: https://github.com/pcreux/csv-importer/issues/85
|
197
|
+
[#88]: https://github.com/pcreux/csv-importer/issues/88
|
198
|
+
[@brain-geek]: https://github.com/brain-geek
|
177
199
|
[@danielweinmann]: https://github.com/danielweinmann
|
178
200
|
[@egg-chicken]: https://github.com/egg-chicken
|
179
201
|
[@fxgallego]: https://github.com/fxgallego
|
180
202
|
[@macfanatic]: https://github.com/macfanatic
|
203
|
+
[@mltsy]: https://github.com/mltsy
|
181
204
|
[@paulodeleo]: https://github.com/paulodeleo
|
205
|
+
[@pcreux]: https://github.com/pcreux
|
182
206
|
[@pnomolos]: https://github.com/pnomolos
|
183
207
|
[@shvetsovdm]: https://github.com/shvetsovdm
|
184
|
-
[@stas]: https://github.com/stas
|
208
|
+
[@stas]: https://github.com/stas
|
data/README.md
CHANGED
@@ -187,6 +187,27 @@ Like very advanced stuff? We grant you access to the [`column`](https://github.c
|
|
187
187
|
end
|
188
188
|
```
|
189
189
|
|
190
|
+
Note that `to:` accepts anything that responds to call and take 1, 2 or
|
191
|
+
3 arguments.
|
192
|
+
|
193
|
+
```ruby
|
194
|
+
class ImportUserCSV
|
195
|
+
include CSVImporter
|
196
|
+
|
197
|
+
model User
|
198
|
+
|
199
|
+
column :birth_date, to: DateTransformer
|
200
|
+
column :renewal_date, to: DateTransformer
|
201
|
+
column :next_renewal_at, to: ->(value) { Time.at(value.to_i) }
|
202
|
+
end
|
203
|
+
|
204
|
+
class DateTransformer
|
205
|
+
def self.call(date)
|
206
|
+
Date.strptime(date, '%m/%d/%y')
|
207
|
+
end
|
208
|
+
end
|
209
|
+
```
|
210
|
+
|
190
211
|
Now, what if the user does not provide the email column? It's not worth
|
191
212
|
running the import, we should just reject the CSV file right away.
|
192
213
|
That's easy:
|
@@ -206,7 +227,6 @@ import.report.status # => :invalid_header
|
|
206
227
|
import.report.message # => "The following columns are required: 'email'"
|
207
228
|
```
|
208
229
|
|
209
|
-
|
210
230
|
### Update or Create
|
211
231
|
|
212
232
|
You often want to find-and-update-or-create when importing a CSV file.
|
data/lib/csv_importer.rb
CHANGED
@@ -85,13 +85,16 @@ module CSVImporter
|
|
85
85
|
end
|
86
86
|
|
87
87
|
header.valid?
|
88
|
+
rescue CSV::MalformedCSVError => e
|
89
|
+
@report = Report.new(status: :invalid_csv_file, parser_error: e.message)
|
90
|
+
false
|
88
91
|
end
|
89
92
|
|
90
93
|
# Run the import. Return a Report.
|
91
94
|
def run!
|
92
95
|
if valid_header?
|
93
96
|
@report = Runner.call(rows: rows, when_invalid: config.when_invalid,
|
94
|
-
after_save_blocks: config.after_save_blocks)
|
97
|
+
after_save_blocks: config.after_save_blocks, report: @report)
|
95
98
|
else
|
96
99
|
@report
|
97
100
|
end
|
@@ -29,7 +29,7 @@ module CSVImporter
|
|
29
29
|
attribute :name, Symbol
|
30
30
|
attribute :to # Symbol or Proc
|
31
31
|
attribute :as # Symbol, String, Regexp, Array
|
32
|
-
attribute :required, Boolean
|
32
|
+
attribute :required, Virtus::Attribute::Boolean
|
33
33
|
|
34
34
|
# The model attribute that this column targets
|
35
35
|
def attribute
|
@@ -53,7 +53,18 @@ module CSVImporter
|
|
53
53
|
SEPARATORS = [",", ";", "\t"]
|
54
54
|
|
55
55
|
def detect_separator(csv_content)
|
56
|
-
SEPARATORS.
|
56
|
+
SEPARATORS.min_by do |separator|
|
57
|
+
csv_content.count(separator)
|
58
|
+
|
59
|
+
all_lines = csv_content.lines
|
60
|
+
base_number = all_lines.first.count(separator)
|
61
|
+
|
62
|
+
if base_number.zero?
|
63
|
+
Float::MAX
|
64
|
+
else
|
65
|
+
all_lines.map{|line| line.count(separator) - base_number }.map(&:abs).inject(0) { |sum, i| sum + i }
|
66
|
+
end
|
67
|
+
end
|
57
68
|
end
|
58
69
|
|
59
70
|
# Remove trailing white spaces and ensure we always return a string
|
data/lib/csv_importer/report.rb
CHANGED
@@ -12,8 +12,8 @@ module CSVImporter
|
|
12
12
|
|
13
13
|
attribute :status, Symbol, default: proc { :pending }
|
14
14
|
|
15
|
-
attribute :missing_columns, Array[
|
16
|
-
attribute :extra_columns, Array[
|
15
|
+
attribute :missing_columns, Array[String], default: proc { [] }
|
16
|
+
attribute :extra_columns, Array[String], default: proc { [] }
|
17
17
|
|
18
18
|
attribute :parser_error, String
|
19
19
|
|
data/lib/csv_importer/row.rb
CHANGED
@@ -12,7 +12,7 @@ module CSVImporter
|
|
12
12
|
attribute :model_klass
|
13
13
|
attribute :identifiers # Array[Symbol] or Proc
|
14
14
|
attribute :after_build_blocks, Array[Proc], default: []
|
15
|
-
attribute :skip, Boolean, default: false
|
15
|
+
attribute :skip, Virtus::Attribute::Boolean, default: false
|
16
16
|
|
17
17
|
# The model to be persisted
|
18
18
|
def model
|
@@ -52,18 +52,19 @@ module CSVImporter
|
|
52
52
|
# Set the attribute using the column_definition and the csv_value
|
53
53
|
def set_attribute(model, column, csv_value)
|
54
54
|
column_definition = column.definition
|
55
|
-
|
56
|
-
|
55
|
+
transformer = column_definition.to
|
56
|
+
if transformer.respond_to?(:call)
|
57
|
+
arity = transformer.is_a?(Proc) ? transformer.arity : transformer.method(:call).arity
|
57
58
|
|
58
|
-
case
|
59
|
+
case arity
|
59
60
|
when 1 # to: ->(email) { email.downcase }
|
60
|
-
model.public_send("#{column_definition.name}=",
|
61
|
+
model.public_send("#{column_definition.name}=", transformer.call(csv_value))
|
61
62
|
when 2 # to: ->(published, post) { post.published_at = Time.now if published == "true" }
|
62
|
-
|
63
|
+
transformer.call(csv_value, model)
|
63
64
|
when 3 # to: ->(field_value, post, column) { post.hash_field[column.name] = field_value }
|
64
|
-
|
65
|
+
transformer.call(csv_value, model, column)
|
65
66
|
else
|
66
|
-
raise ArgumentError, "`to`
|
67
|
+
raise ArgumentError, "arity: #{transformer.arity.inspect} - `to` can only have 1, 2 or 3 arguments"
|
67
68
|
end
|
68
69
|
else
|
69
70
|
attribute = column_definition.attribute
|
data/lib/csv_importer/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csv-importer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Philippe Creux
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-11-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: virtus
|
@@ -104,8 +104,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
104
104
|
- !ruby/object:Gem::Version
|
105
105
|
version: '0'
|
106
106
|
requirements: []
|
107
|
-
|
108
|
-
rubygems_version: 2.6.13
|
107
|
+
rubygems_version: 3.0.3
|
109
108
|
signing_key:
|
110
109
|
specification_version: 4
|
111
110
|
summary: CSV Import for humans
|