eco-helpers 3.0.18 → 3.0.20

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.
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,206 @@
1
+ module Eco::API::Common::People
2
+ class DefaultParsers
3
+ module Helpers
4
+ module ExpectedHeaders
5
+ include Eco::Language::AuxiliarLogger
6
+
7
+ private
8
+
9
+ def require_headers!(raw_headers)
10
+ abort("Missing headers in CSV") unless raw_headers&.any?
11
+
12
+ empty = []
13
+ raw_headers.each_with_index do |header, idx|
14
+ empty << idx if header.to_s.strip.empty?
15
+ end
16
+
17
+ abort("Empty headers in column(s): #{empty.join(', ')}") if empty.any?
18
+
19
+ true
20
+ end
21
+
22
+ def check_headers!(raw_headers, order_check: false) # rubocop:disable Metrics/AbcSize
23
+ unmatch = []
24
+ unmatch = unmatched_headers(raw_headers) if order_check
25
+ missing = missing_headers(raw_headers)
26
+ unknown = unknown_headers(raw_headers)
27
+
28
+ criteria = [unknown, missing[:direct], missing[:indirect], unmatch]
29
+ return if criteria.all?(&:empty?)
30
+
31
+ msg = "Detected possible HEADER / FIELD ISSUES !!!\n"
32
+
33
+ # requires exact match
34
+ unless unmatch.empty?
35
+ msg << "File headers/fields do NOT exactly match the expected:\n"
36
+ msg << " * Expected: #{expected_headers}\n"
37
+
38
+ expected, given = unmatch.first
39
+ msg << " * First unmatch => Given: '#{given}' where expected '#{expected}'\n"
40
+
41
+ missed = expected_headers - raw_headers
42
+
43
+ unless missed.empty?
44
+ msg << " * Missing headers/fields:\n"
45
+ msg << " - #{missed.join("\n - ")}\n"
46
+ end
47
+ end
48
+
49
+ msg << "Missing or Wrong HEADER names in the file:\n"
50
+ msg << " * UNKNOWN (or not used?): #{unknown}\n" unless unknown.empty?
51
+ msg << " * MISSING HEADER/FIELD: #{missing[:direct]}\n" unless missing[:direct].empty?
52
+
53
+ unless (data = missing[:indirect]).empty?
54
+ msg << " * MISSING INDIRECTLY:\n"
55
+
56
+ data.each do |ext, info|
57
+ msg << " - '#{ext}' => "
58
+ msg << (info[:attrs] || {}).map do |status, attrs|
59
+ if status == :inactive
60
+ "makes inactive: #{attrs}"
61
+ elsif status == :active
62
+ "there could be missing info in: #{attrs}"
63
+ end
64
+ end.compact.join("; ")
65
+
66
+ msg << "\n"
67
+ end
68
+ end
69
+
70
+ log(:warn) { msg }
71
+
72
+ msg = "There were issues identified on the file header/field names. Aborting..."
73
+ abort(msg) if options.dig(:input, :header_check, :must_be_valid)
74
+
75
+ sleep(2)
76
+ end
77
+
78
+
79
+ # @return [Hash] with missing `:direct` and `:indirect` attrs, where
80
+ # - `:direct` [Array] refers to direct attrs
81
+ # - `:indirect` [Hash] refers to indirect attrs that are `:active` or `:inactive`.
82
+ def missing_headers(raw_headers) # rubocop:disable Metrics/AbcSize
83
+ int_head = internal_present_or_active(raw_headers)
84
+
85
+ external = raw_headers.select do |e|
86
+ i = fields_mapper.to_internal(e)
87
+ int_head.include?(i)
88
+ end
89
+
90
+ ext_present = present_internal_expected_headers(int_head) | external
91
+ ext_miss = expected_headers - ext_present
92
+
93
+ {
94
+ direct: [],
95
+ indirect: {}
96
+ }.tap do |missing|
97
+ ext_miss.each do |ext|
98
+ next unless (int = fields_mapper.to_internal(ext))
99
+
100
+ missing[:direct] << ext if all_internal_attrs.include?(int)
101
+
102
+ related_attrs_requirements = required_attrs.values.select do |req|
103
+ dep = req.dependant?(int)
104
+ affects = dep && !int_head.include?(int)
105
+ in_header = int_head.include?(req.attr)
106
+ affects || (dep && !in_header)
107
+ end
108
+
109
+ next if related_attrs_requirements.empty?
110
+
111
+ data = missing[:indirect][ext] = {}
112
+ data[:int] = int
113
+ data[:attrs] = {}
114
+
115
+ related_attrs_requirements.each_with_object(data[:attrs]) do |req, attrs|
116
+ status = req.active?(*int_head) ? :active : :inactive
117
+ attrs[status] ||= []
118
+ attrs[status] << req.attr
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+
125
+ # The input file header names as expected
126
+ def expected_headers
127
+ @expected_headers ||= fields_mapper.list(:external).compact.uniq
128
+ end
129
+
130
+ def present_internal_expected_headers(internal_headers)
131
+ expected_headers.select do |ext|
132
+ int = fields_mapper.to_internal(ext)
133
+ internal_headers.include?(int)
134
+ end
135
+ end
136
+
137
+ def unmatched_headers(raw_headers)
138
+ expected_headers.zip(raw_headers).reject do |(expected, given)|
139
+ expected == given
140
+ end
141
+ end
142
+
143
+ def unknown_headers(raw_headers)
144
+ (raw_headers - expected_headers) - all_internal_attrs
145
+ end
146
+
147
+ def fields_mapper
148
+ session.fields_mapper
149
+ end
150
+
151
+ def required_attrs
152
+ @required_attrs ||= person_parser.required_attrs.to_h {|ra| [ra.attr, ra]}
153
+ end
154
+
155
+ def all_internal_attrs
156
+ @all_internal_attrs ||= [].tap do |int_attrs|
157
+ known_int_attrs = person_parser.all_attrs(include_defined_parsers: true)
158
+ known_int_attrs |= fields_mapper.list(:internal).compact
159
+ int_attrs.concat(known_int_attrs)
160
+ end
161
+ end
162
+
163
+ # Scopes what internal attrs appear in headers as they are
164
+ def internal_present_or_active(raw_headers, inactive_requirements = {}) # rubocop:disable Metrics/AbcSize
165
+ # internal attrs that are not being mapped
166
+ int_all = all_internal_attrs.reject {|i| fields_mapper.external?(i)}
167
+ hint = raw_headers & int_all
168
+ hext = raw_headers - hint
169
+ int_present = hint + hext.map {|e| fields_mapper.to_internal(e)}.compact
170
+
171
+ update_inactive = proc do
172
+ inactive_requirements.dup.each do |attr, req|
173
+ next unless req.active?(*int_present)
174
+
175
+ inactive_requirements.delete(attr)
176
+ int_present << attr
177
+ update_inactive.call
178
+ end
179
+ end
180
+
181
+ required_attrs.each_value do |req|
182
+ next if int_present.include?(req)
183
+
184
+ if req.active?(*int_present)
185
+ inactive_requirements.delete(req.attr)
186
+ int_present << req.attr
187
+ update_inactive.call
188
+ else
189
+ inactive_requirements[req.attr] = req
190
+ end
191
+ end
192
+
193
+ int_present
194
+ end
195
+
196
+ def person_parser
197
+ session.entry_factory.person_parser
198
+ end
199
+
200
+ def abort(msg)
201
+ super(msg, raising: false) if defined?(super)
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,36 @@
1
+ module Eco::API::Common::People
2
+ class DefaultParsers
3
+ module Helpers
4
+ module NullParsing
5
+ private
6
+
7
+ def parse_null(value)
8
+ return if null?(value)
9
+ return parse_null_on_hash(value) if value.is_a?(Hash)
10
+ return value unless value.is_a?(Array)
11
+
12
+ value.map {|val| parse_null(val)}
13
+ end
14
+
15
+ def parse_null_on_hash(value)
16
+ return value unless value.is_a?(Hash)
17
+
18
+ value.dup do |out|
19
+ value.each do |key, val|
20
+ next out.delete(key) unless (out[key] = parse_null(val))
21
+ end
22
+ end
23
+ end
24
+
25
+ def null?(value)
26
+ return true if value.nil?
27
+ return false unless value.is_a?(String)
28
+ return true if value.strip.to_s.empty?
29
+
30
+ str = value.strip.upcase
31
+ ['NULL'].any? {|token| str == token}
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,15 @@
1
+ require_relative 'helpers/expected_headers'
2
+ require_relative 'helpers/null_parsing'
3
+
4
+ module Eco
5
+ module API
6
+ module Common
7
+ module People
8
+ class DefaultParsers
9
+ module Helpers
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,56 @@
1
+ class Eco::API::Common::People::DefaultParsers::JsonParser < Eco::API::Common::Loaders::Parser
2
+ attribute :json
3
+
4
+ include Eco::API::Common::People::DefaultParsers::Helpers::ExpectedHeaders
5
+ include Eco::API::Common::People::DefaultParsers::Helpers::NullParsing
6
+
7
+ def parser(filename, deps)
8
+ parse_json_file(filename).tap do |data|
9
+ # Don't enable header checks for now
10
+ next
11
+
12
+ puts 'Identifying unified json object keys...'
13
+ raw_headers = data.each_with_object([]) do |item, head|
14
+ head.concat(item.keys - head)
15
+ end
16
+
17
+ require_headers!(raw_headers)
18
+
19
+ next unless deps[:check_headers]
20
+ next unless check_headers?
21
+
22
+ check_headers!(
23
+ data,
24
+ order_check: false
25
+ )
26
+ end.each_with_object([]) do |item, arr_hash|
27
+ item_hash = item.keys.each_with_object({}) do |attr, hash|
28
+ next if attr.to_s.strip.empty?
29
+
30
+ hash[attr.strip] = parse_null(item[attr])
31
+ end
32
+
33
+ arr_hash.push(item_hash)
34
+ end
35
+ end
36
+
37
+ def serializer(array_hash, _deps)
38
+ array_hash.to_json
39
+ end
40
+
41
+ private
42
+
43
+ def check_headers?
44
+ !options.dig(:input, :header_check, :skip)
45
+ end
46
+
47
+ def parse_json_file(filename)
48
+ fd = File.open(filename)
49
+ JSON.load fd # rubocop:disable Security/JSONLoad
50
+ rescue JSON::ParserError => err
51
+ log(:error) { "Parsing error on file '#{filename}'" }
52
+ raise err
53
+ ensure
54
+ fd&.close
55
+ end
56
+ end
@@ -2,12 +2,9 @@ class Eco::API::Common::People::DefaultParsers::XLSParser < Eco::API::Common::Lo
2
2
  attribute :xls
3
3
 
4
4
  attr_accessor :already_required
5
- attr_reader :file
6
5
 
7
- def parser(file, _deps)
8
- @file = file
9
- rows.tap do |rws|
10
- @file = nil
6
+ def parser(filename, _deps)
7
+ rows(file: filename).tap do |rws|
11
8
  rws.each do |row|
12
9
  to_string!(row)
13
10
  end
@@ -22,13 +19,14 @@ class Eco::API::Common::People::DefaultParsers::XLSParser < Eco::API::Common::Lo
22
19
 
23
20
  def to_string!(row)
24
21
  row.transform_values! do |val|
25
- next nil unless val
22
+ next unless val
26
23
  next val if val.is_a?(String)
24
+
27
25
  val.to_s
28
26
  end
29
27
  end
30
28
 
31
- def headers
29
+ def expected_headers
32
30
  log(:warn) {
33
31
  "Headers detection is using your fields_map.json file (native behaviour)"
34
32
  }
@@ -39,30 +37,31 @@ class Eco::API::Common::People::DefaultParsers::XLSParser < Eco::API::Common::Lo
39
37
  0
40
38
  end
41
39
 
42
- def workbook
40
+ def workbook(file)
43
41
  require_reading_libs!
44
42
  Roo::Spreadsheet.open(file)
45
43
  end
46
44
 
47
- def spreadheet(name_or_index = sheet_name)
48
- workbook.sheet(name_or_index)
45
+ def spreadheet(name_or_index = sheet_name, file:)
46
+ workbook(file).sheet(name_or_index)
49
47
  end
50
48
 
51
- def rows(target = headers)
52
- spreadheet.parse(header_search: target, clean: true)
49
+ def rows(target = expected_headers, file:)
50
+ spreadheet(file: file).parse(header_search: target, clean: true)
53
51
  rescue Roo::HeaderRowNotFoundError => e
54
52
  missing = JSON.parse(e.message)
55
53
 
56
54
  log(:warn) {
57
- "The input file is missing these headers: #{missing}"
55
+ "The input file is missing these expected headers: #{missing}"
58
56
  }
59
57
 
60
58
  present = target - missing
61
- rows(present)
59
+ rows(present, file: file)
62
60
  end
63
61
 
64
62
  def require_reading_libs!
65
63
  return if already_required
64
+
66
65
  require 'roo'
67
66
  require 'roo-xls'
68
67
  self.already_required = true
@@ -12,6 +12,7 @@ module Eco
12
12
  end
13
13
  end
14
14
 
15
+ require_relative 'default_parsers/helpers'
15
16
  require_relative 'default_parsers/select_parser'
16
17
  require_relative 'default_parsers/boolean_parser'
17
18
  require_relative 'default_parsers/numeric_parser'
@@ -22,4 +23,5 @@ require_relative 'default_parsers/freemium_parser'
22
23
  require_relative 'default_parsers/policy_groups_parser'
23
24
  require_relative 'default_parsers/login_providers_parser'
24
25
  require_relative 'default_parsers/csv_parser'
26
+ require_relative 'default_parsers/json_parser'
25
27
  require_relative 'default_parsers/xls_parser'
@@ -28,6 +28,7 @@ module Eco
28
28
  # to translate external names into internal ones and _vice versa_.
29
29
  def initialize(e, schema:, person_parser: nil, default_parser: nil, attr_map: nil)
30
30
  super(e)
31
+
31
32
  msg = "Constructor needs a PersonSchema. Given: #{schema.class}"
32
33
  fatal msg unless schema.is_a?(Ecoportal::API::V1::PersonSchema)
33
34
 
@@ -133,9 +134,10 @@ module Eco
133
134
  out.concat(curr)
134
135
  end
135
136
  end
136
- # Get content only when it's not :xls
137
+
138
+ # Get content only when it's not :xls, nor :json
137
139
  # note: even if content was provided, file takes precedence
138
- if (format != :xls) && file # rubocop:disable Style/IfUnlessModifier
140
+ if get_content?(format) && file # rubocop:disable Style/IfUnlessModifier
139
141
  content = get_file_content(file, encoding: encoding)
140
142
  end
141
143
 
@@ -166,8 +168,10 @@ module Eco
166
168
  end
167
169
  end.tap do |out_array|
168
170
  start_from_two = (format == :csv) || format == :xls
169
- out_array.each_with_index do |entry_hash, i|
170
- entry_hash["idx"] = start_from_two ? i + 2 : i + 1
171
+ first_idx = start_from_two ? 2 : 1
172
+
173
+ out_array.each.with_index(first_idx) do |entry_hash, idx|
174
+ entry_hash["idx"] = idx
171
175
  entry_hash["source_file"] = file
172
176
  end
173
177
  end
@@ -222,6 +226,13 @@ module Eco
222
226
 
223
227
  private
224
228
 
229
+ def get_content?(format)
230
+ return false if format == :xls
231
+ return false if format == :json
232
+
233
+ true
234
+ end
235
+
225
236
  def abort(message)
226
237
  log(:error) { message }
227
238
  exit(1)
@@ -8,6 +8,7 @@ module Eco
8
8
  def initialize(enviro:)
9
9
  invalid_env = enviro && !enviro.is_a?(Eco::API::Common::Session::Environment)
10
10
  raise "Required Environment object (enviro:). Given: #{enviro}" if invalid_env
11
+
11
12
  @enviro = enviro
12
13
  end
13
14
 
@@ -103,6 +104,7 @@ module Eco
103
104
  def download(files, local_folder: nil, &block)
104
105
  puts "Creating local files:"
105
106
  created_files = []
107
+
106
108
  [files].flatten.compact.map do |fullname|
107
109
  basename = windows_basename(fullname)
108
110
  dest_fullname = File.join(local_folder || ".", basename)
@@ -110,6 +112,7 @@ module Eco
110
112
  created_files << dest_fullname
111
113
  sftp_session.download(fullname, dest_fullname)
112
114
  end.each(&:wait)
115
+
113
116
  # run SSH event loop while dw.active?
114
117
  created_files.tap { created_files.each(&block) }
115
118
  end
@@ -155,9 +158,11 @@ module Eco
155
158
  def windows_basename(remote_fullname)
156
159
  dir_sep = /[\\\/]/
157
160
  patr_re = /[<>:\\\/|?*]/
161
+
158
162
  parts = remote_fullname.split(dir_sep).map do |node|
159
163
  node.gsub(patr_re, '_')
160
164
  end
165
+
161
166
  local_fullname = File.join(*parts)
162
167
  File.basename(local_fullname)
163
168
  end
@@ -5,5 +5,6 @@
5
5
  # end
6
6
  class Eco::API::Custom::Mailer < Eco::API::Common::Loaders::Workflow::Mailer
7
7
  extend Eco::Language::Klass::WhenInherited
8
+
8
9
  when_inherited(&config_block)
9
10
  end
data/lib/eco/api/error.rb CHANGED
@@ -96,9 +96,11 @@ module Eco
96
96
  end.sort do |k_1, k_2|
97
97
  next -1 if k_2 < k_1
98
98
  next 1 if k_1 < k_2
99
+
99
100
  0
100
101
  end.tap do |siblings|
101
102
  siblings.delete(Unclassified)
103
+
102
104
  if direct
103
105
  siblings.reject! do |si|
104
106
  siblings.any? {|s| si < s}
@@ -120,8 +122,10 @@ module Eco
120
122
 
121
123
  descendants(direct: true).reverse.each do |klass|
122
124
  next unless klass.err_match?(err_msg)
125
+
123
126
  type = klass
124
127
  next unless klass.descendants?(direct: true)
128
+
125
129
  type = klass.get_type(err_msg, first: false) || type
126
130
  end
127
131
 
@@ -217,6 +217,7 @@ module Eco
217
217
  elsif !pqueue.empty?
218
218
  req_backup = as_update(pqueue, add_feedback: false)
219
219
  backup_update(req_backup)
220
+
220
221
  log(:debug) {
221
222
  "Job ('#{name}':#{type}): going to launch batch against #{pqueue.count} entries"
222
223
  }
@@ -246,28 +247,25 @@ module Eco
246
247
  # 3. error messages in case they were errors from the server
247
248
  # @note if `launch` was not invoked, it specifies so
248
249
  # @return [String] the summary
249
- def summary # rubocop:disable Metrics/AbcSize
250
+ def summary
250
251
  [].tap do |msg|
251
- if pending?
252
- msg << "PENDING - Batch #{type.to_s.upcase} - job '#{name}' - length: #{@queue.length}"
253
- else
254
- msg << feedback.generate(requests, only_stats: true)
252
+ msg << "PENDING Job -------->\n" if pending?
253
+ msg << feedback.generate(requests, only_stats: true)
255
254
 
256
- if batch_policy && !batch_policy.compliant?(request_stats)
257
- msg << "Batch Policy Uncompliance:"
258
- msg << batch_policy.uncompliance(request_stats)
259
- end
260
-
261
- msg << status.errors.message if status
262
- msg << subjobs_summary
255
+ if batch_policy && !batch_policy.compliant?(request_stats)
256
+ msg << 'Batch Policy Uncompliance:'
257
+ msg << batch_policy.uncompliance(request_stats)
263
258
  end
259
+
260
+ msg << status.errors.message if status
261
+ msg << subjobs_summary
264
262
  end.join("\n")
265
263
  end
266
264
 
267
265
  private
268
266
 
269
267
  def subjobs_summary
270
- return "" unless subjobs.count.positive?
268
+ return '' unless subjobs.count.positive?
271
269
 
272
270
  [].tap do |msg|
273
271
  subjobs.map {|subjob| msg << subjob.summary}
@@ -431,7 +429,7 @@ module Eco
431
429
  next unless status.success?(entry)
432
430
 
433
431
  if type == :create && entry.respond_to?(:id=)
434
- entry.id = status[entry].body["id"].tap do |id|
432
+ entry.id = status[entry].body['id'].tap do |id|
435
433
  next unless id.to_s.strip.empty?
436
434
 
437
435
  ref = Eco::API::Session::Batch::Feedback.person_ref(entry)
@@ -503,9 +501,9 @@ module Eco
503
501
 
504
502
  # Keep a copy of the requests for future reference
505
503
  def backup_update(requests, simulate: false)
506
- dry_run = simulate ? "_dry_run" : ""
504
+ dry_run = simulate ? '_dry_run' : ''
507
505
  dir = config.people.requests_folder
508
- filename = name.split(" ").join("-").gsub(/[=\\\/><,"-]+/, "_") # rubocop:disable Style/RedundantArgument
506
+ filename = name.split(' ').join('-').gsub(/[=\\\/><,"-]+/, "_") # rubocop:disable Style/RedundantArgument
509
507
  file = File.join(dir, "#{type}_data_#{filename}#{dry_run}.json")
510
508
  file_manager.save_json(requests, file, :timestamp)
511
509
  end
@@ -81,7 +81,7 @@ module Eco
81
81
  end
82
82
 
83
83
  def pending?
84
- any? {|job| job.pending?}
84
+ any?(&:pending?)
85
85
  end
86
86
 
87
87
  # Launches every `Batch::Job` in the group.
@@ -108,19 +108,17 @@ module Eco
108
108
  end
109
109
  end
110
110
 
111
- def status
111
+ def status(&block)
112
112
  if block_given?
113
- status.each do |job, job_status|
114
- yield(job, job_status)
115
- end
113
+ status.each(&block)
116
114
  self
117
- else # rubocop:disable Naming/MemoizedInstanceVariableName
118
- @jobs_status ||= {}
115
+ else
116
+ @jobs_status ||= {} # rubocop:disable Naming/MemoizedInstanceVariableName
119
117
  end
120
118
  end
121
119
 
122
120
  def errors?
123
- any? {|job| job.errors?}
121
+ any?(&:errors?)
124
122
  end
125
123
 
126
124
  def summary
@@ -18,14 +18,17 @@ module Eco
18
18
  private
19
19
 
20
20
  # Swaps to batch endpoint on specific errors
21
- def batch_mode_on(*error_types, options: self.options, allow_job_mode: true, &block)
21
+ def batch_mode_on(*error_types, options: self.options, allow_job_mode: true)
22
+ msg = "Expecting block. Non given"
23
+ raise ArgumentError, msg unless block_given?
24
+
22
25
  in_job_mode = allow_job_mode && job_mode?(options)
23
26
 
24
27
  yield(in_job_mode, batch_size(options))
25
28
  rescue *error_types
26
29
  raise unless in_job_mode
27
30
 
28
- yield(false , batch_mode_size)
31
+ yield(false, batch_mode_size)
29
32
  end
30
33
 
31
34
  # MODE
@@ -25,7 +25,12 @@ module Eco
25
25
  explanation << "You have #{retries_left} retries left."
26
26
  question = " Do you want to retry (y/N)?"
27
27
 
28
- prompt_user(question, default: "Y", explanation: explanation, timeout: 10) do |response|
28
+ prompt_user(
29
+ question,
30
+ default: "Y",
31
+ explanation: explanation,
32
+ timeout: 10
33
+ ) do |response|
29
34
  raise unless response.upcase.start_with?("Y")
30
35
 
31
36
  puts "\nOkay... let's retry!"
@@ -6,14 +6,16 @@ module Eco
6
6
  module StatusHandling
7
7
  private
8
8
 
9
- def tap_status(enviro:, queue:, method:, status: nil, &block)
9
+ def tap_status(enviro:, queue:, method:, status: nil)
10
10
  status ||= Eco::API::Session::Batch::Status.new(
11
11
  enviro,
12
12
  queue: queue,
13
13
  method: method
14
14
  )
15
15
 
16
- status.tap(&block)
16
+ status.tap do
17
+ yield(status) if block_given?
18
+ end
17
19
  end
18
20
  end
19
21
  end