eco-helpers 3.0.21 → 3.0.23

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 (154) hide show
  1. checksums.yaml +4 -4
  2. data/.idea/.gitignore +10 -0
  3. data/CHANGELOG.md +44 -2
  4. data/eco-helpers.gemspec +5 -3
  5. data/lib/eco/api/common/class_helpers.rb +2 -1
  6. data/lib/eco/api/common/class_hierarchy.rb +6 -9
  7. data/lib/eco/api/common/loaders/case_base.rb +12 -4
  8. data/lib/eco/api/common/loaders/config/workflow/cases_extension.rb +53 -0
  9. data/lib/eco/api/common/loaders/config/workflow/mailer.rb +2 -14
  10. data/lib/eco/api/common/loaders/config/workflow.rb +4 -0
  11. data/lib/eco/api/common/loaders/error_handler.rb +3 -2
  12. data/lib/eco/api/common/loaders/policy.rb +3 -2
  13. data/lib/eco/api/common/loaders/use_case/cli_identify.rb +28 -0
  14. data/lib/eco/api/common/loaders/use_case/target_model.rb +25 -0
  15. data/lib/eco/api/common/loaders/use_case/type.rb +37 -0
  16. data/lib/eco/api/common/loaders/use_case.rb +16 -43
  17. data/lib/eco/api/error/handler.rb +6 -4
  18. data/lib/eco/api/error/handlers.rb +12 -5
  19. data/lib/eco/api/microcases/people/apply_changes/set_account/account_excluded.rb +34 -0
  20. data/lib/eco/api/microcases/people/apply_changes/set_account.rb +28 -0
  21. data/lib/eco/api/microcases/people/apply_changes/set_core/core_excluded.rb +28 -0
  22. data/lib/eco/api/microcases/people/apply_changes/set_core.rb +27 -0
  23. data/lib/eco/api/microcases/people/apply_changes/set_core_with_supervisor.rb +38 -0
  24. data/lib/eco/api/microcases/people/apply_changes/set_supervisor.rb +69 -0
  25. data/lib/eco/api/microcases/people/apply_changes.rb +19 -0
  26. data/lib/eco/api/microcases/people/fetch/with_each.rb +109 -0
  27. data/lib/eco/api/microcases/people/fetch/with_each_leaver.rb +33 -0
  28. data/lib/eco/api/microcases/people/fetch/with_each_present.rb +42 -0
  29. data/lib/eco/api/microcases/people/fetch/with_each_starter.rb +43 -0
  30. data/lib/eco/api/microcases/people/fetch/with_each_subordinate.rb +41 -0
  31. data/lib/eco/api/microcases/people/fetch/with_supervisor.rb +46 -0
  32. data/lib/eco/api/microcases/people/fetch.rb +23 -0
  33. data/lib/eco/api/microcases/people/integrity/fix_default_group.rb +39 -0
  34. data/lib/eco/api/microcases/people/integrity/fix_filter_tags.rb +55 -0
  35. data/lib/eco/api/microcases/people/integrity/refresh_default_tag.rb +32 -0
  36. data/lib/eco/api/microcases/people/integrity.rb +17 -0
  37. data/lib/eco/api/microcases/people/macro/take_email.rb +141 -0
  38. data/lib/eco/api/microcases/people/macro.rb +13 -0
  39. data/lib/eco/api/microcases/people/manage/cache.rb +36 -0
  40. data/lib/eco/api/microcases/people/manage/load.rb +90 -0
  41. data/lib/eco/api/microcases/people/manage/refresh.rb +59 -0
  42. data/lib/eco/api/microcases/people/manage/search.rb +118 -0
  43. data/lib/eco/api/microcases/people/manage.rb +19 -0
  44. data/lib/eco/api/microcases/people/preserve/default_tag.rb +29 -0
  45. data/lib/eco/api/microcases/people/preserve/filter_tags.rb +34 -0
  46. data/lib/eco/api/microcases/people/preserve/policy_groups.rb +36 -0
  47. data/lib/eco/api/microcases/people/preserve.rb +17 -0
  48. data/lib/eco/api/microcases/people.rb +21 -0
  49. data/lib/eco/api/microcases/person_update.rb +1 -1
  50. data/lib/eco/api/microcases/s3upload_targets.rb +1 -1
  51. data/lib/eco/api/microcases/with_each_contractor_present.rb +40 -0
  52. data/lib/eco/api/microcases.rb +3 -23
  53. data/lib/eco/api/organization/people/multiple_search_results.rb +48 -0
  54. data/lib/eco/api/organization/{people_similarity.rb → people/similarity.rb} +89 -72
  55. data/lib/eco/api/organization/people.rb +40 -66
  56. data/lib/eco/api/organization.rb +0 -1
  57. data/lib/eco/api/policies/policy.rb +7 -5
  58. data/lib/eco/api/policies.rb +9 -4
  59. data/lib/eco/api/session/batch/feedback/generate.rb +60 -0
  60. data/lib/eco/api/session/batch/feedback/getters.rb +28 -0
  61. data/lib/eco/api/session/batch/feedback/identifiers.rb +20 -0
  62. data/lib/eco/api/session/batch/feedback/job_dependencies.rb +45 -0
  63. data/lib/eco/api/session/batch/feedback/request_stat.rb +27 -0
  64. data/lib/eco/api/session/batch/feedback/request_stats.rb +270 -0
  65. data/lib/eco/api/session/batch/feedback.rb +45 -119
  66. data/lib/eco/api/session/batch/job/sets.rb +23 -0
  67. data/lib/eco/api/session/batch/job/type.rb +22 -0
  68. data/lib/eco/api/session/batch/job.rb +8 -18
  69. data/lib/eco/api/session/batch/jobs.rb +6 -2
  70. data/lib/eco/api/session/batch/launcher/mode_size.rb +1 -1
  71. data/lib/eco/api/session/batch/launcher/retry.rb +4 -4
  72. data/lib/eco/api/session/batch/launcher.rb +2 -2
  73. data/lib/eco/api/session/batch/policies.rb +4 -4
  74. data/lib/eco/api/session/batch/searcher.rb +2 -1
  75. data/lib/eco/api/session/batch.rb +0 -1
  76. data/lib/eco/api/session/config/workflow.rb +19 -9
  77. data/lib/eco/api/usecases/base_case/model.rb +54 -0
  78. data/lib/eco/api/usecases/base_case/type.rb +52 -0
  79. data/lib/eco/api/usecases/base_case.rb +5 -29
  80. data/lib/eco/api/usecases/base_io/chaining.rb +48 -0
  81. data/lib/eco/api/usecases/base_io/validations.rb +114 -0
  82. data/lib/eco/api/usecases/base_io.rb +65 -115
  83. data/lib/eco/api/usecases/cli/dsl.rb +3 -1
  84. data/lib/eco/api/usecases/default/people/treat/analyse_people_case.rb +7 -4
  85. data/lib/eco/api/usecases/default/people/treat/supers_cyclic_identify_case.rb +1 -3
  86. data/lib/eco/api/usecases/default/people/treat/supers_hierarchy_case.rb +1 -5
  87. data/lib/eco/api/usecases/default_cases/entries_to_csv_case.rb +2 -2
  88. data/lib/eco/api/usecases/default_cases/hris_case.rb +0 -2
  89. data/lib/eco/api/usecases/default_cases/samples/sftp.rb +3 -0
  90. data/lib/eco/api/usecases/default_cases/samples.rb +1 -1
  91. data/lib/eco/api/usecases/default_cases/to_csv_case.rb +3 -6
  92. data/lib/eco/api/usecases/graphql/base.rb +3 -2
  93. data/lib/eco/api/usecases/graphql/helpers/base/case_env.rb +1 -1
  94. data/lib/eco/api/usecases/graphql/helpers/base/error_handling.rb +3 -3
  95. data/lib/eco/api/usecases/graphql/helpers/contractors/base/load.rb +17 -0
  96. data/lib/eco/api/usecases/graphql/helpers/contractors/base.rb +8 -0
  97. data/lib/eco/api/usecases/graphql/helpers/contractors.rb +6 -0
  98. data/lib/eco/api/usecases/graphql/helpers/location/base.rb +5 -4
  99. data/lib/eco/api/usecases/graphql/helpers/location/command.rb +2 -2
  100. data/lib/eco/api/usecases/graphql/helpers.rb +1 -0
  101. data/lib/eco/api/usecases/graphql/samples/contractors/dsl.rb +5 -0
  102. data/lib/eco/api/usecases/graphql/samples/contractors.rb +17 -0
  103. data/lib/eco/api/usecases/graphql/samples/location/service/base.rb +1 -1
  104. data/lib/eco/api/usecases/graphql/samples/location.rb +1 -1
  105. data/lib/eco/api/usecases/graphql/samples.rb +1 -0
  106. data/lib/eco/api/usecases/ooze_samples/ooze_base_case.rb +0 -1
  107. data/lib/eco/api/usecases/ooze_samples/ooze_run_base_case.rb +8 -8
  108. data/lib/eco/api/usecases/{default_cases/samples → samples/drivers}/cli/sftp_cli.rb +1 -1
  109. data/lib/eco/api/usecases/samples/drivers/cli/url_pull_cli.rb +15 -0
  110. data/lib/eco/api/usecases/{default_cases/samples/sftp_case.rb → samples/drivers/sftp_sample.rb} +8 -8
  111. data/lib/eco/api/usecases/samples/drivers/url_pull_sample.rb +110 -0
  112. data/lib/eco/api/usecases/samples/drivers.rb +13 -0
  113. data/lib/eco/api/usecases/samples.rb +11 -0
  114. data/lib/eco/api/usecases/use_case/chainer.rb +12 -0
  115. data/lib/eco/api/usecases/use_case.rb +32 -23
  116. data/lib/eco/api/usecases/use_case_chain/chaining.rb +88 -0
  117. data/lib/eco/api/usecases/use_case_chain.rb +17 -62
  118. data/lib/eco/api/usecases/use_case_io/chain.rb +24 -0
  119. data/lib/eco/api/usecases/use_case_io.rb +17 -22
  120. data/lib/eco/api/usecases.rb +15 -6
  121. data/lib/eco/assets.rb +1 -1
  122. data/lib/eco/cli/config/filters/people_filters.rb +6 -5
  123. data/lib/eco/cli/config/input.rb +6 -2
  124. data/lib/eco/cli/config/use_cases.rb +4 -2
  125. data/lib/eco/cli_default/people_filters.rb +1 -0
  126. data/lib/eco/cli_default/workflow.rb +149 -138
  127. data/lib/eco/data/mapper.rb +51 -19
  128. data/lib/eco/language/methods/dsl_able.rb +10 -0
  129. data/lib/eco/version.rb +1 -1
  130. metadata +87 -35
  131. data/lib/eco/api/microcases/account_excluded.rb +0 -26
  132. data/lib/eco/api/microcases/core_excluded.rb +0 -20
  133. data/lib/eco/api/microcases/fix_default_group.rb +0 -33
  134. data/lib/eco/api/microcases/fix_filter_tags.rb +0 -49
  135. data/lib/eco/api/microcases/people_cache.rb +0 -30
  136. data/lib/eco/api/microcases/people_load.rb +0 -84
  137. data/lib/eco/api/microcases/people_refresh.rb +0 -53
  138. data/lib/eco/api/microcases/people_search.rb +0 -112
  139. data/lib/eco/api/microcases/preserve_default_tag.rb +0 -23
  140. data/lib/eco/api/microcases/preserve_filter_tags.rb +0 -28
  141. data/lib/eco/api/microcases/preserve_policy_groups.rb +0 -30
  142. data/lib/eco/api/microcases/refresh_default_tag.rb +0 -26
  143. data/lib/eco/api/microcases/set_account.rb +0 -18
  144. data/lib/eco/api/microcases/set_core.rb +0 -17
  145. data/lib/eco/api/microcases/set_core_with_supervisor.rb +0 -32
  146. data/lib/eco/api/microcases/set_supervisor.rb +0 -63
  147. data/lib/eco/api/microcases/take_email_from_account.rb +0 -129
  148. data/lib/eco/api/microcases/with_each.rb +0 -103
  149. data/lib/eco/api/microcases/with_each_leaver.rb +0 -27
  150. data/lib/eco/api/microcases/with_each_present.rb +0 -36
  151. data/lib/eco/api/microcases/with_each_starter.rb +0 -37
  152. data/lib/eco/api/microcases/with_each_subordinate.rb +0 -33
  153. data/lib/eco/api/microcases/with_supervisor.rb +0 -35
  154. data/lib/eco/api/session/batch/request_stats.rb +0 -266
@@ -1,37 +0,0 @@
1
- module Eco
2
- module API
3
- class MicroCases
4
- # Detects who in the `entries` is new in the organization and `yield` s them one by one to the given block.
5
- # @note
6
- # - it also links to `person.entry` the input data `entry`.
7
- # @param entries [Eco::API::Common::People::Entries] the input entries with the data.
8
- # @param people [Eco::API::Organization::People] target existing _People_ of the current update.
9
- # @param options [Hash] the options.
10
- # @param log_present [Boolean] log error message if an `entry` has match in `people`.
11
- # @param append_created [Boolean] whether or not a new person will be added to the `people` object.
12
- # @yield [entry, person] gives each **new** `person` of `entries` that is not present in `people`.
13
- # @yieldparam entry [PersonEntry] the input entry with the data we should set on person.
14
- # @yieldparam person [Ecoportal::API::V1::Person] the **new** person.
15
- # @return [Eco::API::Organization::People] the starters.
16
- def with_each_starter(entries, people, options, log_present: false, append_created: true)
17
- starters = []
18
- micro.with_each(entries, people, options, append_created: append_created) do |entry, person|
19
- unless person.new?
20
- if log_present
21
- log(:error) {
22
- "This person (id: '#{person.id}') already exists: #{entry.to_s(:identify)}"
23
- }
24
- end
25
-
26
- next
27
- end
28
-
29
- starters << person
30
- yield(entry, person) if block_given?
31
- end
32
-
33
- people.newFrom starters
34
- end
35
- end
36
- end
37
- end
@@ -1,33 +0,0 @@
1
- module Eco
2
- module API
3
- class MicroCases
4
- # Finds all the subordinates of `supervisor`.
5
- # @note if `supervisor` is `nil`, it will return all people with no supervisor.
6
- # @param supervisor [String, Ecoportal::API::V1::Person, Hash] the `supervisor` or the `id` / `external_id` thereof.
7
- # @param people [Eco::API::Organization::People] target existing _People_ of the current update.
8
- # @yield [subordinate] block that does some stuff with `subordinate`.
9
- # @yieldparam subordinate [Ecoportal::API::V1::Person] each one of the suborinates of `supervisor`.
10
- # @return [Eco::API::Organization::People] the **subordinates** of `supervisor`.
11
- def with_each_subordinate(supervisor, people)
12
- people.supervisor_id(_person_id(supervisor, people)).tap do |subordinates|
13
- subordinates.each do |subordinate|
14
- yield(subordinate) if block_given?
15
- end
16
- end
17
- end
18
-
19
- private
20
-
21
- def _person_id(value, people)
22
- case value
23
- when Hash
24
- _person_id(value["id"] || value["external_id"], people)
25
- when Ecoportal::API::V1::Person
26
- _person_id(value.id || value.external_id, people)
27
- when String
28
- micro.with_supervisor(value, people)&.id
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,35 +0,0 @@
1
- module Eco
2
- module API
3
- class MicroCases
4
- # Finds the supervisor among `people` by using the `supervisor_id` of `value`.
5
- # @param value [String, Ecoportal::API::V1::Person, Hash] the subordinate person,
6
- # or the unique identifier of the supervisor to be found (preferably the `external_id`).
7
- # @param people [Eco::API::Organization::People] target existing _People_ of the current update.
8
- # @param strict [Boolean] specifies if the search should be `strict` (see {Eco::API::Organization::People#person}).
9
- # @yield [supervisor] block that does some stuff with supevisor.
10
- # @yieldparam supervisor [Ecoportal::API::V1::Person] the person object of the supervisor, or `nil` if not found.
11
- # @return [nil, Ecoportal::API::V1::Person] found `supervisor` of `value`.
12
- def with_supervisor(value, people, strict: false)
13
- if sup_id = with_supervisor_supervisor_id(value)
14
- people.person(id: sup_id, external_id: sup_id, email: sup_id, strict: strict)
15
- end.tap do |supervisor|
16
- yield(supervisor) if block_given?
17
- end
18
- end
19
-
20
- private
21
-
22
- def with_supervisor_supervisor_id(value)
23
- return nil if value.to_s.strip.empty?
24
- case
25
- when value.respond_to?(:supervisor_id)
26
- value.supervisor_id
27
- when value.is_a?(Hash)
28
- value["supervisor_id"]
29
- else
30
- value
31
- end
32
- end
33
- end
34
- end
35
- end
@@ -1,266 +0,0 @@
1
- module Eco
2
- module API
3
- class Session
4
- class Batch
5
- # @attr_reader count [Integer] the total number of requests
6
- # @attr_reader stats [Hash] plain `Hash` with the number of requests that include an attribute
7
- class RequestStats
8
- CORE_ATTRS = Eco::API::Common::People::PersonParser::CORE_ATTRS
9
- ACCOUNT_ATTRS = (Eco::API::Common::People::PersonParser::ACCOUNT_ATTRS + ['permissions_custom']).uniq
10
- DETAILS_ATTRS = ['fields'].freeze
11
- BLANKED_PREFIX = 'blanked_'.freeze
12
- DETAILS_FIELDS = 'details_fields'.freeze
13
-
14
- class << self
15
- def valid_type?(type)
16
- Eco::API::Session::Batch::Job.valid_type?(type.to_sym)
17
- end
18
-
19
- def core_attrs(stats: false, all: false)
20
- CORE_ATTRS.dup.tap do |attrs|
21
- next unless stats || all
22
-
23
- attrs.unshift('core')
24
- attrs.concat(blank_attrs(CORE_ATTRS))
25
- end
26
- end
27
-
28
- def account_attrs(stats: false, all: false)
29
- ACCOUNT_ATTRS.dup.tap do |attrs|
30
- next unless stats || all
31
-
32
- attrs.unshift('account_remove')
33
- attrs.unshift('account') if all
34
- attrs.concat(blank_attrs(ACCOUNT_ATTRS))
35
- end
36
- end
37
-
38
- def details_attrs(stats: false, all: false)
39
- DETAILS_ATTRS.dup.tap do |attrs|
40
- next unless stats || all
41
-
42
- attrs.unshift('details_remove')
43
- attrs.unshift('details') if all
44
- end
45
- end
46
-
47
- def blanked_prefix(attr = nil)
48
- @blanked_prefix ||= BLANKED_PREFIX
49
- return @blanked_prefix unless attr
50
-
51
- "#{blanked_prefix}#{attr}"
52
- end
53
-
54
- def blanked_prefix=(value)
55
- @blanked_prefix = value || blanked_prefix
56
- end
57
-
58
- def blank_attrs(attrs)
59
- attrs.map {|attr| "#{blanked_prefix}#{attr}"}
60
- end
61
- end
62
-
63
- attr_reader :type, :count
64
-
65
- def initialize(type:, requests: [])
66
- msg = "Type should be one of #{Eco::API::Session::Batch::Job.types}. Given: #{type}"
67
- raise msg unless self.class.valid_type?(type.to_sym)
68
-
69
- @type = type.to_sym
70
- @count = requests&.length
71
- @stats = build(requests)
72
- end
73
-
74
- def to_h
75
- @stats
76
- end
77
-
78
- def message(percent: false)
79
- lines = []
80
- lines << pairs_to_line(core_pairs(percent: percent))
81
- lines << pairs_to_line(account_pairs(percent: percent))
82
- lines << pairs_to_line(details_pairs(percent: percent))
83
- lines.join("\n")
84
- end
85
-
86
- private
87
-
88
- def attr_value(attr, percent: false, total: count, details: false)
89
- target = details ? (@stats[DETAILS_FIELDS] || {}) : @stats
90
- i = target[attr.to_s]
91
- return i unless percent
92
-
93
- percentage(i, total: total)
94
- end
95
-
96
- def core(percent: false)
97
- attr_value('core', percent: percent)
98
- end
99
-
100
- def account(percent: false)
101
- attr_value('account', percent: percent)
102
- end
103
-
104
- def details(percent: false)
105
- attr_value('details', percent: percent)
106
- end
107
-
108
- def stats
109
- @stats ||= Hash.new(0)
110
- end
111
-
112
- def build(requests)
113
- stats.tap do |stats|
114
- stats[type] = count
115
-
116
- no_requests =
117
- !requests ||
118
- !requests.is_a?(Enumerable) ||
119
- requests.empty?
120
-
121
- next if no_requests
122
-
123
- stats[DETAILS_FIELDS] = Hash.new(0)
124
-
125
- requests.each do |request|
126
- add_core_stats(stats, request || {})
127
- add_account_stats(stats, request || {})
128
- add_details_stats(stats, request || {})
129
- end
130
- end
131
- end
132
-
133
- def attrs_to_stat(stats, hash, attrs)
134
- stats.tap do |st|
135
- attrs.each do |attr|
136
- next unless hash.key?(attr)
137
-
138
- st[attr] += 1
139
- next unless blanked_value?(hash[attr])
140
-
141
- st[blanked_prefix(attr)]+= 1
142
- end
143
- end
144
- end
145
-
146
- def add_core_stats(stats, request)
147
- any_core = !(request.keys & core_attrs).empty? # rubocop:disable Style/ArrayIntersect
148
- stats['core'] += 1 if any_core
149
-
150
- attrs_to_stat(stats, request, core_attrs)
151
- end
152
-
153
- def add_account_stats(stats, request)
154
- return unless request.key?('account')
155
-
156
- stats['account'] += 1
157
- stats['account_remove'] += 1 unless request['account']
158
-
159
- attrs_to_stat(stats, request['account'] || {}, account_attrs)
160
- end
161
-
162
- def add_details_stats(stats, request)
163
- return unless request.key?('details')
164
-
165
- stats['details'] += 1
166
- stats['details_remove'] += 1 unless request['details']
167
-
168
- det_attrs = {}
169
- if (fields = request.dig('details', 'fields'))
170
- stats['fields'] += fields.length
171
-
172
- det_attrs = fields.each_with_object(det_attrs) do |fld, hash|
173
- hash[fld['alt_id']] = fld['value']
174
- end
175
- end
176
-
177
- attrs_to_stat(stats[DETAILS_FIELDS], det_attrs, det_attrs.keys)
178
- end
179
-
180
- def core_pairs(percent: false)
181
- cattrs = core_attrs + blank_attrs(core_attrs)
182
- [['core', core(percent: percent)]] + pairs(cattrs, percent: percent, total: core)
183
- end
184
-
185
- def account_pairs(percent: false)
186
- aattrs = ['account_remove'] + account_attrs + blank_attrs(account_attrs)
187
- [['account', account(percent: percent)]] + pairs(aattrs, percent: percent, total: account)
188
- end
189
-
190
- def details_pairs(percent: false)
191
- det_pairs = [['details', details(percent: percent)]]
192
- det_pairs += [['fields', fields_average]] if attr_value('fields') && fields_average
193
- det_pairs += pairs(['details_remove'], percent: percent, total: details)
194
- det_pairs += pairs(details_field_attrs, percent: percent, total: details, details: true)
195
- det_pairs
196
- end
197
-
198
- def pairs(attrs, percent: false, total: count, details: false)
199
- attrs.map do |a|
200
- value = attr_value(a, percent: percent, total: total, details: details)
201
- value.positive? ? [a, value] : nil
202
- end.compact
203
- end
204
-
205
- def pairs_to_line(pairs, percent: false)
206
- key_val_delimiter = ': '; attr_delimiter = ' ++ '
207
- pairs.map do |p|
208
- [p.first.to_s, "#{p.last}#{percent ? '%' : ''}"].join(key_val_delimiter)
209
- end.join(attr_delimiter)
210
- end
211
-
212
- def core_attrs
213
- @core_attrs ||= self.class.core_attrs
214
- end
215
-
216
- def account_attrs
217
- @account_attrs ||= self.class.account_attrs
218
- end
219
-
220
- def details_attrs
221
- @details_attrs ||= self.class.details_attrs
222
- end
223
-
224
- def details_field_attrs
225
- @stats[DETAILS_FIELDS].keys
226
- end
227
-
228
- def blank_attrs(attrs)
229
- self.class.blank_attrs(attrs)
230
- end
231
-
232
- def blanked_prefix(attr = nil)
233
- self.class.blanked_prefix(attr)
234
- end
235
-
236
- def blanked_value?(value)
237
- case value
238
- when nil, false
239
- true
240
- when Numeric
241
- value.zero?
242
- when Array
243
- value.compact.empty?
244
- when String
245
- value.to_s.strip.empty?
246
- end
247
- end
248
-
249
- def fields_average
250
- fields_num = attr_value('fields')
251
- return unless fields_num && (total = details).positive?
252
-
253
- (fields_num / total.to_f).round(2)
254
- end
255
-
256
- def percentage(num, total: count)
257
- return unless num
258
-
259
- total ||= count
260
- (num.to_f / total * 100).round(2)
261
- end
262
- end
263
- end
264
- end
265
- end
266
- end