csvbuilder-importer 0.1.4 → 0.1.5

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
  SHA256:
3
- metadata.gz: 52cdbeae4314f705e797a216730c276ccc68f57140f3c06ae86109fa9a9b6902
4
- data.tar.gz: 45c9d16608cc0e86e920333bf9e08db34f98f9ca2fa17354c95323132e8afb43
3
+ metadata.gz: b630db32ac5aff6725cbdb9f66414aed575f0b7e5529dd982af31f2002c0ca88
4
+ data.tar.gz: d474369caa5696069c0273ca414e27e7f4aeb281e20312682fd99ec96d5880cc
5
5
  SHA512:
6
- metadata.gz: ae94d692fbfa627cdd37952a47b7db183414095e206d1bbd908d01a2e3e4ff0e719673a7f0fc8a1545bc2316bcce7d17d542ddcbe9b565f0f0d68137f5c25f23
7
- data.tar.gz: a7c914fff4abb75256af5f3f996a13116db6408ff64290bf22430c75ab45503c85561bd1b959657dba6b95a6fb5975b76988a2f749d2a2ddb51ab52012de187e
6
+ metadata.gz: d188fde51bb5aafa126c10b0493f49ea085141d752cce03a4ed34c33ecbbc21712d3a06a3cb3232d2c56f9c40bd3b400224015ac42139e502844bdca497b1c06
7
+ data.tar.gz: c58f400d80291c30e4b9198381240b7a7ecfa4ddb0db4266b4fcd6eb0a744a0d7a7902a3f448ba8b73f8438a0c913c7195794750d2388aecee868fdccf8a3ba6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [Released]
4
+
5
+ ## [0.1.5] - 2023-07-26
6
+
7
+ - Add a way to abort at the importer level, handy to handle wrong headers check https://github.com/joel/csvbuilder-importer/pull/12
8
+ - Using Less Memory And Quicker Line Counter https://github.com/joel/csvbuilder-importer/pull/11
9
+
3
10
  ## [0.1.4] - 2023-04-21
4
11
 
5
12
  - Potential Security Fix
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- csvbuilder-importer (0.1.4)
4
+ csvbuilder-importer (0.1.5)
5
5
  activemodel (>= 5.2)
6
6
  activesupport (>= 5.2)
7
7
  csvbuilder-core
data/README.md CHANGED
@@ -40,13 +40,14 @@ The import takes the CSV file and the Import class.
40
40
 
41
41
  ```ruby
42
42
  rows = Csvbuilder::Import::File.new(file.path, UserCsvImportModel).each
43
- row = rows.next
43
+ row_enumerator = rows.each # It's essential to go through the Enumerator to benefit from the callbacks. See References[^1]
44
+ row_model_instance = row_enumerator.next
44
45
  ```
45
46
 
46
47
  `Csvbuilder::Import` implement two essential methods:
47
48
 
48
49
  1. skip?
49
- 2. abort?
50
+ 2. abort? # NOTE: abort can be trigger at the importer level too.
50
51
 
51
52
  You have to provide your implementation of the method `abort?`. If the method `abort?` returns true, the iteration will stop.
52
53
 
@@ -183,6 +184,42 @@ Thanks to the callback mechanism, the opportunities to interact with the import
183
184
 
184
185
  For long imports, you can show a progress bar to help customers cope with the import time; as you know, if errors have occurred, you can change the colour of the progress bar accordingly and offer the possibility to stop the import earlier.
185
186
 
187
+ ## Aborting an import
188
+
189
+ There is a design challenge to handling an import line-by-line. If it makes the code more efficient and decoupled, we might have cases when we want to check something shared with all lines. The obvious ones are the headers. Let's say we want to check them and abort all imports if something wrong is detected. We probably don't want to add the abort conditioning on every line (Csvbuilder::Model or, more precisely, its extension Csvbuilder::Import). We would rather have it in the Importer itself. In that case, we can stop the Importer from invoking "abort!". Let's consider the following example:
190
+
191
+ ```ruby
192
+ class Importer < Csvbuilder::Import::File
193
+
194
+ after_next do
195
+ if HeaderChecker.new(current_row_model).invalid?
196
+ abort!
197
+ next true # Keep going into #each and hit the callbacks
198
+ end
199
+ end
200
+
201
+ end
202
+ ```
203
+
204
+ ```ruby
205
+ context "with incorrect headers" do
206
+
207
+ should "not import data" do
208
+ importer = Importer.new(@file.path, @importer_class, @context)
209
+
210
+ row_enumerator = importer.each
211
+
212
+ assert_raises StopIteration do
213
+ row_enumerator.next
214
+ end
215
+ end
216
+ end
217
+ ```
218
+
219
+ ## References
220
+
221
+ - [^1] Csvbuilder::Import::File#each https://github.com/joel/csvbuilder-importer/blob/e8e6633a03dda4ae0e5d6775ec9d395dec553fbe/lib/csvbuilder/importer/public/import/file.rb#L66-L68
222
+
186
223
  ## Development
187
224
 
188
225
  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.
@@ -20,10 +20,10 @@ module Csvbuilder
20
20
  reset
21
21
  end
22
22
 
23
- # http://stackoverflow.com/questions/2650517/count-the-number-of-lines-in-a-file-without-reading-entire-file-into-memory
23
+ # https://gist.github.com/guilhermesimoes/d69e547884e556c3dc95?permalink_comment_id=4502636#gistcomment-4502636
24
24
  # @return [Integer] the number of rows in the file, including empty new lines
25
25
  def size
26
- @size ||= ::File.readlines(file_path).length
26
+ @size ||= ::File.read(file_path).count($/)
27
27
  end
28
28
 
29
29
  # If the current position is at the headers, skip it and return it. Otherwise, only return false.
@@ -9,7 +9,7 @@ module Csvbuilder
9
9
  extend ActiveModel::Callbacks
10
10
  include ActiveModel::Validations
11
11
 
12
- attr_reader :csv, :row_model_class, :index, :current_row_model, :previous_row_model, :context # -1 = start of file, 0 to infinity = index of row_model, nil = end of file, no row_model
12
+ attr_reader :interrupt, :csv, :row_model_class, :index, :current_row_model, :previous_row_model, :context # -1 = start of file, 0 to infinity = index of row_model, nil = end of file, no row_model
13
13
 
14
14
  delegate :size, :end_of_file?, :line_number, to: :csv
15
15
 
@@ -26,6 +26,7 @@ module Csvbuilder
26
26
  @csv = ::Csvbuilder::Import::Csv.new(file_path) # Full namespace provided to avoid confusion with Ruby CSV class.
27
27
  @row_model_class = row_model_class
28
28
  @context = context.to_h.symbolize_keys
29
+ @interrupt = false
29
30
  reset
30
31
  end
31
32
 
@@ -39,6 +40,7 @@ module Csvbuilder
39
40
  csv.reset
40
41
  @index = -1
41
42
  @current_row_model = nil
43
+ @interrupt = false
42
44
  end
43
45
 
44
46
  # Gets the next row model based on the context
@@ -74,7 +76,13 @@ module Csvbuilder
74
76
 
75
77
  # @return [Boolean] returns true, if the file should abort reading
76
78
  def abort?
77
- !valid? || !!current_row_model.try(:abort?)
79
+ interrupt || !valid? || !!current_row_model.try(:abort?)
80
+ end
81
+
82
+ def abort!
83
+ @interrupt = true
84
+
85
+ nil
78
86
  end
79
87
 
80
88
  # @return [Boolean] returns true, if the file should skip `current_row_model`
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Csvbuilder
4
4
  module Importer
5
- VERSION = "0.1.4"
5
+ VERSION = "0.1.5"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: csvbuilder-importer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joel Azemar
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-21 00:00:00.000000000 Z
11
+ date: 2023-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -105,7 +105,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
105
  - !ruby/object:Gem::Version
106
106
  version: '0'
107
107
  requirements: []
108
- rubygems_version: 3.4.12
108
+ rubygems_version: 3.4.17
109
109
  signing_key:
110
110
  specification_version: 4
111
111
  summary: Csvbuilder Importer contain the components to handle CSV importing