eco-helpers 3.0.18 → 3.0.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +34 -3
  4. data/eco-helpers.gemspec +3 -3
  5. data/lib/eco/api/common/loaders/config/session.rb +12 -0
  6. data/lib/eco/api/common/loaders/config/workflow/mailer.rb +17 -4
  7. data/lib/eco/api/common/loaders/config.rb +10 -2
  8. data/lib/eco/api/common/loaders/parser.rb +10 -0
  9. data/lib/eco/api/common/people/default_parsers/csv_parser.rb +21 -208
  10. data/lib/eco/api/common/people/default_parsers/helpers/expected_headers.rb +206 -0
  11. data/lib/eco/api/common/people/default_parsers/helpers/null_parsing.rb +36 -0
  12. data/lib/eco/api/common/people/default_parsers/helpers.rb +15 -0
  13. data/lib/eco/api/common/people/default_parsers/json_parser.rb +56 -0
  14. data/lib/eco/api/common/people/default_parsers/xls_parser.rb +13 -14
  15. data/lib/eco/api/common/people/default_parsers.rb +2 -0
  16. data/lib/eco/api/common/people/entry_factory.rb +15 -4
  17. data/lib/eco/api/common/session/sftp.rb +5 -0
  18. data/lib/eco/api/custom/mailer.rb +1 -0
  19. data/lib/eco/api/error.rb +4 -0
  20. data/lib/eco/api/session/batch/job.rb +14 -16
  21. data/lib/eco/api/session/batch/jobs.rb +6 -8
  22. data/lib/eco/api/session/batch/launcher/mode_size.rb +5 -2
  23. data/lib/eco/api/session/batch/launcher/retry.rb +6 -1
  24. data/lib/eco/api/session/batch/launcher/status_handling.rb +4 -2
  25. data/lib/eco/api/session/batch/launcher.rb +3 -3
  26. data/lib/eco/api/session/config/api.rb +1 -0
  27. data/lib/eco/api/session/config/apis/one_off.rb +6 -6
  28. data/lib/eco/api/session/config/workflow.rb +16 -3
  29. data/lib/eco/api/session.rb +13 -7
  30. data/lib/eco/api/usecases/default/locations/tagtree_extract_case.rb +1 -0
  31. data/lib/eco/api/usecases/default/locations/tagtree_upload_case.rb +2 -0
  32. data/lib/eco/api/usecases/default/utils/cli/group_csv_cli.rb +26 -0
  33. data/lib/eco/api/usecases/default/utils/cli/json_to_csv_cli.rb +10 -0
  34. data/lib/eco/api/usecases/default/utils/cli/sort_csv_cli.rb +17 -0
  35. data/lib/eco/api/usecases/default/utils/cli/split_json_cli.rb +15 -0
  36. data/lib/eco/api/usecases/default/utils/group_csv_case.rb +213 -0
  37. data/lib/eco/api/usecases/default/utils/json_to_csv_case.rb +71 -0
  38. data/lib/eco/api/usecases/default/utils/sort_csv_case.rb +127 -0
  39. data/lib/eco/api/usecases/default/utils/split_json_case.rb +224 -0
  40. data/lib/eco/api/usecases/default/utils.rb +4 -0
  41. data/lib/eco/api/usecases/default_cases/samples/sftp_case.rb +22 -15
  42. data/lib/eco/api/usecases/ooze_cases/export_register_case.rb +6 -6
  43. data/lib/eco/api/usecases/ooze_samples/helpers/exportable_register.rb +1 -0
  44. data/lib/eco/api/usecases/ooze_samples/ooze_base_case.rb +1 -1
  45. data/lib/eco/api/usecases/ooze_samples/ooze_run_base_case.rb +8 -5
  46. data/lib/eco/cli_default/workflow.rb +10 -4
  47. data/lib/eco/csv/stream.rb +2 -0
  48. data/lib/eco/csv.rb +3 -2
  49. data/lib/eco/language/methods/delegate_missing.rb +4 -3
  50. data/lib/eco/version.rb +1 -1
  51. metadata +22 -9
@@ -0,0 +1,127 @@
1
+ class Eco::API::UseCases::Default::Utils::SortCsv < Eco::API::Custom::UseCase
2
+ name 'sort-csv'
3
+ type :other
4
+
5
+ require_relative 'cli/sort_csv_cli'
6
+
7
+ def main(*_args)
8
+ if simulate?
9
+ count = Eco::CSV.count(input_file)
10
+ log(:info) { "CSV '#{input_file}' has #{count} rows." }
11
+ else
12
+ group_input_rows
13
+ generate_file
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :headers, :headers_rest
20
+
21
+ def group_input_rows
22
+ idx = 0
23
+ first = true
24
+
25
+ Eco::CSV.foreach(input_file, headers: true, skip_blanks: true) do |row|
26
+ idx += 1
27
+
28
+ if first
29
+ first = false
30
+ @output_headers = row.headers
31
+ require_sort_field!(row, file: input_file)
32
+ end
33
+
34
+ pivot_value = row[sort_field]
35
+ (row_groups[pivot_value] ||= []) << row
36
+
37
+ if (idx % 500).zero?
38
+ print "... Tracked #{idx} rows \r"
39
+ $stdout.flush
40
+ end
41
+ end
42
+ ensure
43
+ log(:info) { "Tracked #{idx} rows"}
44
+ end
45
+
46
+ def generate_file
47
+ idx = 0
48
+
49
+ CSV.open(output_filename, 'wb') do |csv|
50
+ csv << @output_headers
51
+
52
+ row_groups.keys.sort.each do |key|
53
+ row_groups[key].each do |row|
54
+ csv << row.values_at(*@output_headers)
55
+
56
+ idx += 1
57
+ if (idx % 500).zero?
58
+ print "... Sorted #{idx} rows \r"
59
+ $stdout.flush
60
+ end
61
+ end
62
+ end
63
+ end
64
+ ensure
65
+ msg = "Generated file '#{output_filename}' with #{idx} rows."
66
+ log(:info) { msg } unless simulate?
67
+ end
68
+
69
+ def row_groups
70
+ @row_groups ||= {}
71
+ end
72
+
73
+ def output_filename
74
+ return nil unless input_name
75
+
76
+ File.join(input_dir, "#{input_name}_sorted#{input_ext}")
77
+ end
78
+
79
+ def input_name
80
+ @input_name ||= File.basename(input_basename, input_ext)
81
+ end
82
+
83
+ def input_ext
84
+ @input_ext ||= input_basename.split('.')[1..].join('.').then do |name|
85
+ ".#{name}"
86
+ end
87
+ end
88
+
89
+ def input_basename
90
+ @input_basename ||= File.basename(input_full_filename)
91
+ end
92
+
93
+ def input_dir
94
+ @input_dir = File.dirname(input_full_filename)
95
+ end
96
+
97
+ def input_full_filename
98
+ @input_full_filename ||= File.expand_path(input_file)
99
+ end
100
+
101
+ def input_file
102
+ options.dig(:input, :file)
103
+ end
104
+
105
+ def require_sort_field!(row, file:)
106
+ return true if row.key?(sort_field)
107
+
108
+ msg = "Sort field '#{sort_field}' missing in header of file '#{file}'"
109
+ log(:error) { msg }
110
+ raise msg
111
+ end
112
+
113
+ def sort_field
114
+ @sort_field ||= opts_sort_by.tap do |pivot|
115
+ next if pivot
116
+
117
+ msg = "The pivot field should be specified with -by option"
118
+
119
+ log(:error) { msg }
120
+ raise msg
121
+ end
122
+ end
123
+
124
+ def opts_sort_by
125
+ options.dig(:input, :sort_by)
126
+ end
127
+ end
@@ -0,0 +1,224 @@
1
+ class Eco::API::UseCases::Default::Utils::SplitJson < Eco::API::Common::Loaders::UseCase
2
+ require_relative 'cli/split_json_cli'
3
+
4
+ MAX_ITEMS = 15_000
5
+
6
+ name "split-json"
7
+ type :other
8
+
9
+ def main(*_args)
10
+ if simulate?
11
+ count = input_json.count
12
+ log(:info) { "JSON '#{input_file}' has #{count} elements." }
13
+ else
14
+ split_json_into_files!
15
+
16
+ msg = []
17
+ msg << "Total elements: #{total_count}"
18
+ msg << "Generated files:"
19
+ out_files.each do |file|
20
+ msg << " * #{file}'"
21
+ end
22
+
23
+ log(:info) { msg.join("\n") }
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def split_json_into_files!
30
+ first = true
31
+
32
+ while pending?
33
+ swap_file! if first
34
+ first = false
35
+
36
+ curr_json << input_json.shift
37
+ next_count!
38
+
39
+ swap_file! if split?
40
+ end
41
+
42
+ generate_file!
43
+ end
44
+
45
+ def split?
46
+ return false unless curr_count > max_items
47
+
48
+ true
49
+ end
50
+
51
+ def max_items
52
+ @max_items ||= max_items_options || self.class::MAX_ITEMS
53
+ end
54
+
55
+
56
+ # OPTIONS
57
+
58
+ def max_items_options
59
+ return unless (num = options.dig(:output, :file, :max_items))
60
+
61
+ num = num.to_i
62
+ num = nil if num.zero?
63
+ num
64
+ end
65
+
66
+ # OUTPUT JSON
67
+
68
+ # Returns the last json array and blanks the variable
69
+ def exporting_json!
70
+ curr_json.tap do
71
+ @curr_json = []
72
+ end
73
+ end
74
+
75
+ def curr_json
76
+ @curr_json ||= []
77
+ end
78
+
79
+ def pending?
80
+ !input_json.empty?
81
+ end
82
+
83
+ def input_json
84
+ @json ||= JSON.load(File.open(input_file, 'r'))
85
+ end
86
+
87
+ # COUNTS
88
+
89
+ def next_count!
90
+ @curr_count = curr_count + 1
91
+ @total_count = total_count + 1
92
+ end
93
+
94
+ def total_count
95
+ @total_count ||= 0
96
+ end
97
+
98
+ def curr_count
99
+ @curr_count ||= 0
100
+ end
101
+
102
+ def new_count!
103
+ @curr_count = 0
104
+ end
105
+
106
+ # FILE GENERATION
107
+
108
+ def swap_file!
109
+ generate_file!
110
+ next_file!
111
+ end
112
+
113
+ def generate_file!
114
+ return unless @curr_file
115
+
116
+ if curr_json.empty?
117
+ log(:info) {
118
+ msg = "No pending elements to be transferred "
119
+ msg << "(skipping creation of file '#{curr_file}')"
120
+ msg
121
+ }
122
+ out_files -= [curr_file]
123
+ return
124
+ end
125
+
126
+ log(:info) {
127
+ msg = "Generating file at elem #{total_count} "
128
+ msg << "(file elements: #{curr_count})"
129
+ msg
130
+ }
131
+
132
+ save_json(exporting_json!, curr_file)
133
+ new_count!
134
+ end
135
+
136
+ def save_json(data, file)
137
+ File.open(file, 'w') do |fd|
138
+ first = true
139
+
140
+ fd << '['
141
+ data.each do |elem|
142
+ fd << "," unless first
143
+ first = false
144
+
145
+ fd << elem.to_json
146
+ end
147
+ fd << ']'
148
+ end.tap do
149
+ log(:info) {
150
+ "Generated file '#{file}'"
151
+ }
152
+ end
153
+ end
154
+
155
+ # OUTPUT FILES
156
+ attr_reader :curr_file
157
+
158
+ def file_count
159
+ @file_count ||= 0
160
+ end
161
+
162
+ def next_file!
163
+ @file_count = file_count + 1
164
+ @curr_file = generate_name(@file_count)
165
+ @curr_file.tap do
166
+ out_files << @curr_file
167
+ end
168
+ end
169
+
170
+ def out_files
171
+ @out_files ||= []
172
+ end
173
+
174
+ def generate_name(fidx)
175
+ File.join(input_dir, "#{input_name}_#{file_number(fidx)}#{input_ext}")
176
+ end
177
+
178
+ def file_number(num)
179
+ "#{zeroed}#{num}"[-5..]
180
+ end
181
+
182
+ def zeroed
183
+ "0" * 5
184
+ end
185
+
186
+ # INPUT FILE
187
+
188
+ def input_name
189
+ @input_name ||= File.basename(input_basename, input_ext)
190
+ end
191
+
192
+ def input_ext
193
+ @input_ext ||= input_basename.split('.')[1..].join('.').then do |name|
194
+ ".#{name}"
195
+ end
196
+ end
197
+
198
+ def input_basename
199
+ @input_basename ||= File.basename(input_full_filename)
200
+ end
201
+
202
+ def input_dir
203
+ @input_dir = File.dirname(input_full_filename)
204
+ end
205
+
206
+ def input_full_filename
207
+ @input_full_filename ||= File.expand_path(input_file)
208
+ end
209
+
210
+ def input_file
211
+ options.dig(:source, :file).tap do |file|
212
+ next if file && File.exist?(file)
213
+
214
+ unless file
215
+ log(:warn) { 'No input file provided' }
216
+ exit 1
217
+ end
218
+
219
+ log(:warn) {
220
+ "File '#{file}' doesn't exist"
221
+ }
222
+ end
223
+ end
224
+ end
@@ -10,3 +10,7 @@ module Eco
10
10
  end
11
11
 
12
12
  require_relative 'utils/split_csv_case'
13
+ require_relative 'utils/split_json_case'
14
+ require_relative 'utils/json_to_csv_case'
15
+ require_relative 'utils/sort_csv_case'
16
+ require_relative 'utils/group_csv_case'
@@ -7,7 +7,7 @@ class Eco::API::UseCases::DefaultCases::Samples::Sftp < Eco::API::Common::Loader
7
7
  name "sftp"
8
8
  type :other
9
9
 
10
- CONST_REFERRAL = /^(?:::)?(?:[A-Z][a-zA-Z0-9_]*(?:::[A-Z][a-zA-Z0-9_]*)*)$/.freeze
10
+ CONST_REFERRAL = /^(?:::)?(?:[A-Z][a-zA-Z0-9_]*(?:::[A-Z][a-zA-Z0-9_]*)*)$/
11
11
 
12
12
  def main(session, options, _usecase)
13
13
  options[:end_get] = false
@@ -31,7 +31,7 @@ class Eco::API::UseCases::DefaultCases::Samples::Sftp < Eco::API::Common::Loader
31
31
  def file_pattern(require: true)
32
32
  fpc = file_pattern_const
33
33
  return fpc if fpc
34
- return unless require
34
+ return unless require
35
35
 
36
36
  msg = "(#{self.class}) You should redefine the file_pattern function "
37
37
  msg << "as a RegEx expression that matches the target remote file"
@@ -41,6 +41,7 @@ class Eco::API::UseCases::DefaultCases::Samples::Sftp < Eco::API::Common::Loader
41
41
  def file_pattern_const
42
42
  if (fpc = options.dig(:sftp, :file_pattern_const))
43
43
  raise WrongConst, "(#{self.class}) Invalid file pattern const referral: #{fpc}" unless fpc.match(CONST_REFERRAL)
44
+
44
45
  begin
45
46
  self.eval(fpc)
46
47
  rescue NameError
@@ -54,6 +55,7 @@ class Eco::API::UseCases::DefaultCases::Samples::Sftp < Eco::API::Common::Loader
54
55
  # Ex: "/IN/Personnel"
55
56
  def remote_subfolder(require: true)
56
57
  rm_sf = options.dig(:sftp, :remote_subfolder)
58
+
57
59
  return rm_sf if rm_sf
58
60
  return unless require
59
61
 
@@ -78,7 +80,7 @@ class Eco::API::UseCases::DefaultCases::Samples::Sftp < Eco::API::Common::Loader
78
80
  options.dig(:sftp, :local_folder) || "."
79
81
  end
80
82
 
81
- def with_remote_files(folder: self.remote_folder, pattern: self.file_pattern)
83
+ def with_remote_files(folder: remote_folder, pattern: file_pattern)
82
84
  sftp.files(folder, pattern: pattern).each do |remote_file|
83
85
  yield(remote_file) if block_given?
84
86
  end
@@ -100,22 +102,25 @@ class Eco::API::UseCases::DefaultCases::Samples::Sftp < Eco::API::Common::Loader
100
102
 
101
103
  def get_files
102
104
  with_remote_files.tap do |files|
103
- unless files.empty?
104
- file_names = files.map {|file| to_remote_path(file.name)}
105
- puts "Getting the following files into the local folder '#{local_folder}':"
106
- puts file_names
107
- sftp.download(file_names, local_folder: local_folder)
108
- end
105
+ next if files.empty?
106
+
107
+ file_names = files.map {|file| to_remote_path(file.name)}
108
+
109
+ puts "Getting the following files into the local folder '#{local_folder}':"
110
+ puts file_names
111
+
112
+ sftp.download(file_names, local_folder: local_folder)
109
113
  end
110
114
  end
111
115
 
112
116
  def get_last
113
117
  with_remote_files.last.tap do |file|
114
- if file
115
- file_name = to_remote_path(file.name)
116
- puts "Getting the following file: #{file_name}"
117
- sftp.download(file_name, local_folder: local_folder)
118
- end
118
+ next unless file
119
+
120
+ file_name = to_remote_path(file.name)
121
+ puts "Getting the following file: #{file_name}"
122
+
123
+ sftp.download(file_name, local_folder: local_folder)
119
124
  end
120
125
  end
121
126
 
@@ -125,7 +130,9 @@ class Eco::API::UseCases::DefaultCases::Samples::Sftp < Eco::API::Common::Loader
125
130
  dest = to_remote_path("#{archive_subfolder}/#{file.name}")
126
131
  move_file(source, dest)
127
132
  end.tap do |files|
128
- puts "Moved the file(s) to the #{archive_subfolder} folder" unless files.empty?
133
+ next if files.empty?
134
+
135
+ puts "Moved the file(s) to the #{archive_subfolder} folder"
129
136
  end
130
137
  end
131
138
 
@@ -40,7 +40,7 @@ class Eco::API::UseCases::OozeCases::ExportRegisterCase < Eco::API::UseCases::Oo
40
40
 
41
41
  def build_tags_filter(mode = :any)
42
42
  tags = option_tags(mode)
43
- return nil if !tags || tags.empty?
43
+ return if !tags || tags.empty?
44
44
 
45
45
  tags_filter(tags, any: mode == :any)
46
46
  end
@@ -48,7 +48,7 @@ class Eco::API::UseCases::OozeCases::ExportRegisterCase < Eco::API::UseCases::Oo
48
48
  def build_range_filter(key = :update_at)
49
49
  from = from_date(key)
50
50
  to = to_date(key)
51
- return nil unless from || to
51
+ return unless from || to
52
52
 
53
53
  date_range_filter(from: from, to: to, key: key)
54
54
  end
@@ -92,10 +92,10 @@ class Eco::API::UseCases::OozeCases::ExportRegisterCase < Eco::API::UseCases::Oo
92
92
 
93
93
  def filename
94
94
  @filename ||= (options[:file] || options.dig(:export, :file, :name)).tap do |filename|
95
- unless filename
96
- log(:error) { "Destination file not specified" }
97
- return false
98
- end
95
+ next if filename
96
+
97
+ log(:error) { "Destination file not specified" }
98
+ return false
99
99
  end
100
100
  end
101
101
  end
@@ -48,6 +48,7 @@ module Eco
48
48
 
49
49
  def header(refresh: false)
50
50
  return @header if instance_variable_defined?(:@header) && !refresh
51
+
51
52
  @header = typed_header.map do |name|
52
53
  ExportableOoze.key_to_label(name)
53
54
  end
@@ -234,7 +234,7 @@ class Eco::API::UseCases::OozeSamples::OozeBaseCase < Eco::API::Common::Loaders:
234
234
 
235
235
  def dry_count
236
236
  @dry_count ||= 0
237
- @dry_count += 1
237
+ @dry_count += 1
238
238
  end
239
239
 
240
240
  def dry_run_feedback(entry = target)
@@ -3,17 +3,19 @@ class Eco::API::UseCases::OozeSamples::OozeRunBaseCase < Eco::API::UseCases::Ooz
3
3
  name "ooze-run-base"
4
4
  type :other
5
5
 
6
- SAVE_PATCH = "ooze_patch_update.json"
6
+ SAVE_PATCH = "ooze_patch_update.json".freeze
7
7
 
8
8
  def main(session, options, usecase)
9
9
  super(session, options, usecase) do
10
- if method(:process_ooze).parameters.count == 0
10
+ if method(:process_ooze).parameters.count.zero?
11
11
  ooze # retrieve ooze
12
12
  process_ooze
13
13
  else
14
14
  process_ooze(ooze)
15
15
  end
16
+
16
17
  yield(target) if block_given?
18
+
17
19
  exit_if_no_changes!
18
20
  update_ooze(target)
19
21
  end
@@ -30,7 +32,7 @@ class Eco::API::UseCases::OozeSamples::OozeRunBaseCase < Eco::API::UseCases::Ooz
30
32
  end
31
33
 
32
34
  def stage(stage_id_name = stage_id, ooze: target)
33
- super(stage_id_name, ooze: ooze)
35
+ super
34
36
  end
35
37
 
36
38
  def ooze_id
@@ -43,11 +45,12 @@ class Eco::API::UseCases::OozeSamples::OozeRunBaseCase < Eco::API::UseCases::Ooz
43
45
 
44
46
  def update_ooze(ooz = target)
45
47
  prompt_to_confirm!
46
- super(ooz)
48
+
49
+ super
47
50
  end
48
51
 
49
52
  def exit_if_no_changes!
50
- return if (changes = !!patch_doc["page"])
53
+ return if !!patch_doc["page"]
51
54
 
52
55
  log(:info) { "No Changes!!" }
53
56
  exit(0)
@@ -1,12 +1,14 @@
1
1
  ASSETS.cli do |cli| # rubocop:disable Metrics/BlockLength
2
2
  ASSETS.config.workflow do |wf| # rubocop:disable Metrics/BlockLength
3
3
  rescued = false
4
+
4
5
  # default rescue
5
6
  wf.rescue do |err, io|
6
7
  next io if rescued
7
8
 
8
9
  rescued = true
9
10
  log(:debug) { err.patch_full_message }
11
+
10
12
  wf.run(:close, io: io)
11
13
  rescue StandardError => e
12
14
  puts "Some problem in workflow.rescue: #{e}"
@@ -74,10 +76,10 @@ ASSETS.cli do |cli| # rubocop:disable Metrics/BlockLength
74
76
  end
75
77
 
76
78
  wf.on(:usecases) do |_wf_ca, io|
77
- unless cli.config.usecases.process(io: io)
78
- log(:info) { "No update operation specified... quitting" }
79
- exit 0
80
- end
79
+ next if cli.config.usecases.process(io: io)
80
+
81
+ log(:info) { "No update operation specified... quitting" }
82
+ exit 0
81
83
  end
82
84
 
83
85
  wf.before(:launch_jobs) do |_wf_jobs, _io|
@@ -95,11 +97,13 @@ ASSETS.cli do |cli| # rubocop:disable Metrics/BlockLength
95
97
  run_it = !options[:dry_run] || options.dig(:post_launch, :run)
96
98
  unless run_it
97
99
  wf_post.skip!
100
+
98
101
  log(:info) {
99
102
  msg = "Although there are post_launch cases, they will NOT be RUN"
100
103
  msg << ", because we are in dry-run (simulate)." if options[:dry_run]
101
104
  msg
102
105
  }
106
+
103
107
  next
104
108
  end
105
109
 
@@ -117,6 +121,7 @@ ASSETS.cli do |cli| # rubocop:disable Metrics/BlockLength
117
121
  end
118
122
  msg
119
123
  }
124
+
120
125
  next
121
126
  end
122
127
 
@@ -131,6 +136,7 @@ ASSETS.cli do |cli| # rubocop:disable Metrics/BlockLength
131
136
  use.launch(io: io).base
132
137
  rescue Eco::API::UseCases::BaseIO::MissingParameter => e
133
138
  raise unless e.required == :people
139
+
134
140
  log(:debug) {
135
141
  "Skipping use case '#{use.name}' -- no base people detected for the current run"
136
142
  }
@@ -7,6 +7,7 @@ module Eco
7
7
 
8
8
  def initialize(filename, **kargs)
9
9
  raise ArgumentError, "File '#{filename}' does not exist" unless ::File.exist?(filename)
10
+
10
11
  @filename = filename
11
12
  @params = {
12
13
  headers: true,
@@ -55,6 +56,7 @@ module Eco
55
56
  # see https://dalibornasevic.com/posts/68-processing-large-csv-files-with-ruby
56
57
  def csv
57
58
  return @csv if instance_variable_defined?(:@csv)
59
+
58
60
  @fd = ::File.open(filename, 'r')
59
61
  @csv = Eco::CSV.new(fd, **params)
60
62
  end
data/lib/eco/csv.rb CHANGED
@@ -5,9 +5,9 @@ module Eco
5
5
  include Eco::Data::Files
6
6
 
7
7
  # @return [Eco::CSV::Table]
8
- def parse(data, **kargs, &block)
8
+ def parse(data, **kargs)
9
9
  kargs = {headers: true, skip_blanks: true}.merge(kargs)
10
- Eco::CSV::Table.new(super(data, **kargs, &block))
10
+ Eco::CSV::Table.new(super)
11
11
  end
12
12
 
13
13
  # @return [Eco::CSV::Table]
@@ -51,6 +51,7 @@ module Eco
51
51
  included = yield(row) if block_given?
52
52
  count += 1 if included
53
53
  end
54
+
54
55
  count
55
56
  end
56
57
  end
@@ -7,7 +7,7 @@ module Eco
7
7
  end
8
8
 
9
9
  def method_missing(method_name, *args, **kargs, &block)
10
- super unless receiver = object_missing_delegated_to
10
+ super unless (receiver = object_missing_delegated_to)
11
11
  receiver.send(method_name, *args, **kargs, &block)
12
12
  end
13
13
 
@@ -19,8 +19,9 @@ module Eco
19
19
 
20
20
  # retrieve the delegate_missing_to object
21
21
  def object_missing_delegated_to
22
- return nil unless @delegate_missing_to
23
- self.method(@delegate_missing_to).call
22
+ return unless @delegate_missing_to
23
+
24
+ method(@delegate_missing_to).call
24
25
  end
25
26
  end
26
27
  end
data/lib/eco/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Eco
2
- VERSION = '3.0.18'.freeze
2
+ VERSION = '3.0.20'.freeze
3
3
  end