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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 204d73b513134e022dd8e3529869e8f9c63602d7
4
- data.tar.gz: 46b7b9e27dab7add3abfd117959f8919f71b5f22
2
+ SHA256:
3
+ metadata.gz: 5e17c85aa62e6f2774f1cb86dcea9d7743622b73690fb896228d1bf7ce54951e
4
+ data.tar.gz: acfd22bf68c1c228a0afecba046cf3cb7231311192ee1ee5c88828a56a51f429
5
5
  SHA512:
6
- metadata.gz: 586def4222cccb61d571e4904d76d1f055537e25529be90552aad206fa527845f6de0ee99ba8fccea786817c961d3b7366e3fc64456df32cefdc25a44e8bd730
7
- data.tar.gz: ae9443c1998169329c5c432b9df9b7480206c32bcc2da4cd733cd1351a4586823bf0b05b205e74a7a5645308e5e39016930a537fa30ccd45bb1b7d6e708c3f07
6
+ metadata.gz: c5c8894e68eaa33418761a9cad3ab8f0ddfea0eeaa3e62101ab1105a40978b7c206dc7448a4b536f9efc06c06b952935146efe9b4ae010c9a3f98428f649b641
7
+ data.tar.gz: 66f498dc9d2e62bf413ba35ac362b03fa557640c724cafb8cc38686bfe825334455d936c1c8a4e79b97fc4ec0355887cb0f6dee178b0f3893d0b37c6dc043b09
@@ -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/BrewhouseTeam/csv-importer/issues/26
170
- [#38]: https://github.com/BrewhouseTeam/csv-importer/issues/38
171
- [#47]: https://github.com/BrewhouseTeam/csv-importer/issues/47
172
- [#52]: https://github.com/BrewhouseTeam/csv-importer/issues/52
173
- [#63]: https://github.com/BrewhouseTeam/csv-importer/issues/63
174
- [#68]: https://github.com/BrewhouseTeam/csv-importer/issues/68
175
- [#69]: https://github.com/BrewhouseTeam/csv-importer/issues/69
176
- [#73]: https://github.com/BrewhouseTeam/csv-importer/issues/73
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.
@@ -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.sort_by { |separator| csv_content.count(separator) }.last
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
@@ -12,8 +12,8 @@ module CSVImporter
12
12
 
13
13
  attribute :status, Symbol, default: proc { :pending }
14
14
 
15
- attribute :missing_columns, Array[Symbol], default: proc { [] }
16
- attribute :extra_columns, Array[Symbol], default: proc { [] }
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
 
@@ -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
- if column_definition.to && column_definition.to.is_a?(Proc)
56
- to_proc = column_definition.to
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 to_proc.arity
59
+ case arity
59
60
  when 1 # to: ->(email) { email.downcase }
60
- model.public_send("#{column_definition.name}=", to_proc.call(csv_value))
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
- to_proc.call(csv_value, model)
63
+ transformer.call(csv_value, model)
63
64
  when 3 # to: ->(field_value, post, column) { post.hash_field[column.name] = field_value }
64
- to_proc.call(csv_value, model, column)
65
+ transformer.call(csv_value, model, column)
65
66
  else
66
- raise ArgumentError, "`to` proc can only have 1 or 2 arguments"
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
@@ -1,3 +1,3 @@
1
1
  module CSVImporter
2
- VERSION = "0.6.0"
2
+ VERSION = "0.7.0"
3
3
  end
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.6.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: 2018-05-22 00:00:00.000000000 Z
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
- rubyforge_project:
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