eco-helpers 3.0.26 → 3.0.28
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +76 -5
- data/eco-helpers.gemspec +2 -1
- data/lib/eco/api/common/class_helpers.rb +1 -136
- data/lib/eco/api/common/loaders/base.rb +1 -1
- data/lib/eco/api/common/loaders/case_base.rb +1 -1
- data/lib/eco/api/common/loaders/config/cli.rb +1 -1
- data/lib/eco/api/common/loaders/config/session.rb +1 -1
- data/lib/eco/api/common/loaders/config/workflow.rb +1 -1
- data/lib/eco/api/common/loaders/config.rb +2 -5
- data/lib/eco/api/common/loaders/error_handler.rb +1 -1
- data/lib/eco/api/common/loaders/parser.rb +2 -2
- data/lib/eco/api/common/loaders/policy.rb +1 -1
- data/lib/eco/api/common/loaders/use_case/target_model.rb +1 -1
- data/lib/eco/api/common/loaders/use_case/type.rb +1 -1
- data/lib/eco/api/common/loaders/use_case.rb +1 -1
- data/lib/eco/api/common/people/default_parsers/archived_parser.rb +19 -0
- data/lib/eco/api/common/people/default_parsers/boolean_parser.rb +4 -4
- data/lib/eco/api/common/people/default_parsers/date_parser.rb +3 -3
- data/lib/eco/api/common/people/default_parsers/freemium_parser.rb +6 -6
- data/lib/eco/api/common/people/default_parsers/login_providers_parser.rb +3 -3
- data/lib/eco/api/common/people/default_parsers/multi_parser.rb +4 -4
- data/lib/eco/api/common/people/default_parsers/policy_groups_parser.rb +9 -6
- data/lib/eco/api/common/people/default_parsers/send_invites_parser.rb +6 -5
- data/lib/eco/api/common/people/default_parsers/xls_parser.rb +2 -2
- data/lib/eco/api/common/people/default_parsers.rb +1 -0
- data/lib/eco/api/common/people/entries.rb +16 -15
- data/lib/eco/api/common/people/person_entry.rb +53 -37
- data/lib/eco/api/common/people/person_parser.rb +8 -6
- data/lib/eco/api/common/people/supervisor_helpers.rb +3 -1
- data/lib/eco/api/common/session/logger/channels.rb +2 -1
- data/lib/eco/api/common/session/logger.rb +2 -2
- data/lib/eco/api/common/session/mailer/aws_provider.rb +3 -2
- data/lib/eco/api/common/session/mailer/provider_base.rb +2 -1
- data/lib/eco/api/common/session/mailer/sendgrid_provider.rb +9 -9
- data/lib/eco/api/common/session/mailer.rb +5 -3
- data/lib/eco/api/common/session/sftp.rb +11 -4
- data/lib/eco/api/common/version_patches/object.rb +2 -1
- data/lib/eco/api/custom/mailer.rb +1 -1
- data/lib/eco/api/error/handlers.rb +3 -3
- data/lib/eco/api/error.rb +17 -17
- data/lib/eco/api/microcases/people/apply_changes/set_account/account_excluded.rb +3 -11
- data/lib/eco/api/microcases/people/apply_changes/set_core/core_excluded.rb +4 -1
- data/lib/eco/api/microcases/people/manage/search.rb +3 -1
- data/lib/eco/api/organization/people.rb +1 -0
- data/lib/eco/api/policies.rb +2 -2
- data/lib/eco/api/session/batch/job/sets.rb +1 -0
- data/lib/eco/api/session/batch/job/type.rb +1 -0
- data/lib/eco/api/session/batch/job.rb +2 -2
- data/lib/eco/api/session/batch/launcher/valid_methods.rb +3 -2
- data/lib/eco/api/session/batch/launcher.rb +4 -5
- data/lib/eco/api/session/batch/searcher.rb +4 -4
- data/lib/eco/api/session/config/api.rb +2 -2
- data/lib/eco/api/session/config/apis/enviro_spaces.rb +2 -2
- data/lib/eco/api/session/config/post_launch.rb +7 -4
- data/lib/eco/api/session/config/sftp.rb +1 -1
- data/lib/eco/api/session/config/tagtree.rb +1 -1
- data/lib/eco/api/session/config/workflow.rb +4 -4
- data/lib/eco/api/session/config.rb +25 -24
- data/lib/eco/api/session.rb +4 -4
- data/lib/eco/api/usecases/base_case/model.rb +2 -1
- data/lib/eco/api/usecases/base_case/type.rb +2 -1
- data/lib/eco/api/usecases/base_io/validations.rb +6 -4
- data/lib/eco/api/usecases/cli/option.rb +5 -2
- data/lib/eco/api/usecases/default/people/amend/clear_abilities_case.rb +2 -2
- data/lib/eco/api/usecases/default/people/amend/restore_db_case.rb +16 -9
- data/lib/eco/api/usecases/default/people/treat/analyse_people_case.rb +20 -20
- data/lib/eco/api/usecases/default.rb +5 -5
- data/lib/eco/api/usecases/default_cases/to_csv_case.rb +8 -8
- data/lib/eco/api/usecases/default_cases/upsert_case.rb +4 -4
- data/lib/eco/api/usecases/graphql/helpers/base.rb +1 -1
- data/lib/eco/api/usecases/graphql/helpers/location/base/tree_tracking.rb +5 -1
- data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/commandable.rb +5 -3
- data/lib/eco/api/usecases/graphql/helpers/location/command/result.rb +3 -3
- data/lib/eco/api/usecases/graphql/helpers/location/command.rb +3 -0
- data/lib/eco/api/usecases/graphql/samples/location/command/dsl.rb +2 -2
- data/lib/eco/api/usecases/graphql/samples/location/command/service/tree_update.rb +9 -3
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/inputable.rb +5 -4
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/parsing.rb +5 -2
- data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff.rb +3 -3
- data/lib/eco/api/usecases/graphql/utils/sftp.rb +1 -1
- data/lib/eco/api/usecases/lib/{file_pattern.rb → files/file_pattern.rb} +1 -1
- data/lib/eco/api/usecases/lib/{sftp.rb → files/sftp.rb} +19 -7
- data/lib/eco/api/usecases/lib/files.rb +7 -0
- data/lib/eco/api/usecases/lib.rb +1 -2
- data/lib/eco/api/usecases/ooze_cases/export_register_case.rb +5 -5
- data/lib/eco/api/usecases/ooze_samples/helpers/exportable_ooze.rb +14 -11
- data/lib/eco/api/usecases/ooze_samples/helpers_migration/copying.rb +14 -23
- data/lib/eco/api/usecases/ooze_samples/helpers_migration/typed_fields_pairing.rb +49 -27
- data/lib/eco/api/usecases/ooze_samples/ooze_base_case.rb +9 -9
- data/lib/eco/api/usecases/ooze_samples/ooze_run_base_case.rb +1 -1
- data/lib/eco/api/usecases/ooze_samples/register_export_case.rb +25 -17
- data/lib/eco/api/usecases/ooze_samples/register_migration_case.rb +41 -24
- data/lib/eco/api/usecases/ooze_samples/register_update_case.rb +16 -15
- data/lib/eco/api/usecases/samples/drivers/cli/sftp_cli.rb +15 -15
- data/lib/eco/api/usecases/samples/drivers/cli/url_pull_cli.rb +5 -5
- data/lib/eco/api/usecases/samples/drivers/sftp_sample.rb +5 -3
- data/lib/eco/api/usecases/use_case.rb +6 -6
- data/lib/eco/api/usecases/use_case_chain/chaining.rb +6 -6
- data/lib/eco/api/usecases/use_case_chain.rb +4 -4
- data/lib/eco/api/usecases/use_case_io.rb +2 -1
- data/lib/eco/api/usecases.rb +9 -9
- data/lib/eco/cli/config/options_set.rb +4 -4
- data/lib/eco/cli/config/use_cases.rb +3 -3
- data/lib/eco/cli/scripting/argument.rb +1 -1
- data/lib/eco/cli_default/input.rb +9 -9
- data/lib/eco/cli_default/options.rb +125 -100
- data/lib/eco/cli_default/people.rb +3 -3
- data/lib/eco/cli_default/usecases.rb +83 -83
- data/lib/eco/cli_default/workflow.rb +7 -7
- data/lib/eco/data/files/helpers.rb +7 -5
- data/lib/eco/data/fuzzy_match/result.rb +69 -26
- data/lib/eco/data/fuzzy_match/results.rb +10 -10
- data/lib/eco/data/fuzzy_match/score.rb +13 -8
- data/lib/eco/data/fuzzy_match.rb +69 -50
- data/lib/eco/data/hashes/diff_result/meta.rb +2 -1
- data/lib/eco/data/locations/node_base/treeify.rb +13 -11
- data/lib/eco/data/locations/node_diff/accessors.rb +2 -1
- data/lib/eco/data/mapper.rb +4 -4
- data/lib/eco/language/auxiliar_logger.rb +4 -4
- data/lib/eco/language/delegation/chainable_delegator.rb +18 -0
- data/lib/eco/language/delegation/delegating_missing.rb +104 -0
- data/lib/eco/language/delegation/delegating_missing_const.rb +53 -0
- data/lib/eco/language/delegation/delegating_missing_on_class.rb +53 -0
- data/lib/eco/language/delegation/for_delegator/const_delegator.rb +66 -0
- data/lib/eco/language/delegation/for_delegator/const_lookup_hooks.rb +99 -0
- data/lib/eco/language/delegation/for_delegator/delegated_class.rb +71 -0
- data/lib/eco/language/delegation/for_delegator.rb +11 -0
- data/lib/eco/language/delegation.rb +10 -0
- data/lib/eco/language/klass/builder.rb +29 -0
- data/lib/eco/language/klass/helpers_built.rb +9 -0
- data/lib/eco/language/klass/hierarchy.rb +34 -0
- data/lib/eco/language/klass/inheritable_class_vars.rb +45 -0
- data/lib/eco/language/klass/naming.rb +21 -0
- data/lib/eco/language/klass/resolver.rb +30 -0
- data/lib/eco/language/klass/when_inherited.rb +11 -13
- data/lib/eco/language/klass.rb +6 -0
- data/lib/eco/language/methods.rb +0 -1
- data/lib/eco/language/models/class_helpers.rb +25 -23
- data/lib/eco/language/models/collection.rb +12 -2
- data/lib/eco/language/strings/underscore.rb +17 -0
- data/lib/eco/language/strings.rb +8 -0
- data/lib/eco/language.rb +2 -0
- data/lib/eco/version.rb +1 -1
- metadata +39 -7
- data/lib/eco/language/methods/delegate_missing.rb +0 -29
data/lib/eco/data/fuzzy_match.rb
CHANGED
@@ -11,8 +11,10 @@ module Eco
|
|
11
11
|
|
12
12
|
class << self
|
13
13
|
def included(base)
|
14
|
-
|
15
|
-
|
14
|
+
super
|
15
|
+
|
16
|
+
base.send :include, InstanceMethods
|
17
|
+
base.extend ClassMethods
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
@@ -23,7 +25,7 @@ module Eco
|
|
23
25
|
include CharsPositionScore
|
24
26
|
include NGramsScore
|
25
27
|
|
26
|
-
def jaro_winkler(
|
28
|
+
def jaro_winkler(str_1, str_2, **options)
|
27
29
|
return 0 if !str1 || !str2
|
28
30
|
options = {
|
29
31
|
ignore_case: true,
|
@@ -31,26 +33,26 @@ module Eco
|
|
31
33
|
}.merge(options)
|
32
34
|
|
33
35
|
require 'jaro_winkler'
|
34
|
-
JaroWinkler.distance(
|
36
|
+
JaroWinkler.distance(str_1, str_2, **options)
|
35
37
|
end
|
36
38
|
|
37
39
|
end
|
38
40
|
|
39
41
|
module InstanceMethods
|
40
|
-
FUZZY_MATCH_OPTIONS = [
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
]
|
42
|
+
FUZZY_MATCH_OPTIONS = %i[
|
43
|
+
identities groupings stop_words read
|
44
|
+
must_match_grouping must_match_at_least_one_word
|
45
|
+
gather_last_result threshold
|
46
|
+
].freeze
|
45
47
|
|
46
|
-
JARO_OPTIONS = [
|
47
|
-
NGRAMS_OPTIONS = [
|
48
|
-
POSITION_OPTIONS = [
|
49
|
-
RESULTS_OPTIONS = [
|
48
|
+
JARO_OPTIONS = %i[ignore_case weight].freeze
|
49
|
+
NGRAMS_OPTIONS = %i[range].freeze
|
50
|
+
POSITION_OPTIONS = %i[max_distance].freeze
|
51
|
+
RESULTS_OPTIONS = %i[order threshold].freeze
|
50
52
|
|
51
53
|
include StopWords
|
52
54
|
|
53
|
-
|
55
|
+
attr_writer :fuzzy_options
|
54
56
|
|
55
57
|
def fuzzy_options
|
56
58
|
@fuzzy_options ||= {}
|
@@ -58,60 +60,71 @@ module Eco
|
|
58
60
|
|
59
61
|
def fuzzy_match(haystack_data = nil, **options)
|
60
62
|
if instance_variable_defined?(:@fuzzy_match) && !haystack_data
|
61
|
-
return @fuzzy_match if fuzzy_match_options == fuzzy_match_options(options)
|
63
|
+
return @fuzzy_match if fuzzy_match_options == fuzzy_match_options(options) # rubocop:disable Style/SoleNestedConditional
|
62
64
|
end
|
65
|
+
|
63
66
|
@fuzzy_options = options
|
64
67
|
|
65
68
|
# make it run with a native C extension (for better performance: ~130 % increase of performance)
|
66
69
|
require 'fuzzy_match'
|
67
70
|
require 'amatch'
|
71
|
+
|
68
72
|
::FuzzyMatch.engine = :amatch
|
69
73
|
@fuzzy_match = ::FuzzyMatch.new(haystack(haystack_data), fuzzy_match_options)
|
70
74
|
end
|
71
75
|
|
72
|
-
#
|
76
|
+
# @todo integration for options[:unique_words] => to ensure repeated words do not bring down
|
77
|
+
# the score are cut by threshold
|
73
78
|
# @note
|
74
79
|
# - When the `haystack` elements are **non** `String` objects, it excludes the needle itself from the results
|
75
80
|
# @param needle [String, Object] object is allowed when `fuzzy_options` includes `read:` key.
|
76
81
|
# @param needle_str [String, nil] the actual value of needle_str to be used.
|
77
82
|
# @param haystack [Enumerable] the items to find `needle` among.
|
78
83
|
# @return [Eco::Data::FuzzyMatch::Results]
|
79
|
-
def find_all_with_score(needle, needle_str: nil, haystack: nil, **options)
|
84
|
+
def find_all_with_score(needle, needle_str: nil, haystack: nil, **options) # rubocop:disable Metrics/AbcSize
|
80
85
|
base_match = fuzzy_match(haystack, **options)
|
81
86
|
match_results = base_match.find_all_with_score(needle_str || needle)
|
82
87
|
needle_str ||= item_string(needle)
|
83
88
|
results = match_results.each_with_object([]) do |fuzzy_results, results|
|
84
89
|
item, dice, lev = fuzzy_results
|
85
|
-
|
86
|
-
item_str = item_string(item)
|
90
|
+
next if item == needle
|
87
91
|
|
88
|
-
|
89
|
-
dice = lev = jaro_res = ngram_res = ngram_res = wngram_res = pos_res = 0
|
90
|
-
end
|
92
|
+
item_str = item_string(item)
|
91
93
|
|
92
|
-
|
93
|
-
ngram_res
|
94
|
-
wngram_res ||= words_ngram(needle_str, item_str)
|
95
|
-
pos_res ||= position(needle_str, item_str)
|
96
|
-
|
97
|
-
results << Result.new(item, item_str, needle_str, dice, lev, jaro_res, ngram_res, wngram_res, pos_res)
|
94
|
+
if item_str.to_s.strip.empty? || needle_str.to_s.strip.empty?
|
95
|
+
dice = lev = jaro_res = ngram_res = ngram_res = wngram_res = pos_res = 0
|
98
96
|
end
|
97
|
+
|
98
|
+
jaro_res ||= jaro(needle_str, item_str)
|
99
|
+
ngram_res ||= ngram(needle_str, item_str)
|
100
|
+
wngram_res ||= words_ngram(needle_str, item_str)
|
101
|
+
pos_res ||= position(needle_str, item_str)
|
102
|
+
|
103
|
+
results << Result.new(item, item_str, needle_str, dice, lev, jaro_res, ngram_res, wngram_res, pos_res)
|
99
104
|
end
|
105
|
+
|
100
106
|
Results.new(needle, needle_str, results).tap do |res|
|
101
107
|
res.order = fuzzy_options[:order] if fuzzy_options[:order]
|
102
108
|
res.threshold = fuzzy_options[:threshold] if fuzzy_options[:threshold]
|
103
109
|
end.relevant_results
|
104
110
|
end
|
105
111
|
|
106
|
-
def recalculate_results(results, needle_str: nil, **options)
|
107
|
-
|
112
|
+
def recalculate_results(results, needle_str: nil, **options) # rubocop:disable Metrics/AbcSize
|
113
|
+
msg = "You should provide a block |needle_str, item_str, needle, item|"
|
114
|
+
raise msg unless block_given?
|
115
|
+
|
108
116
|
new_results = results.each_with_object([]) do |result, new_results|
|
109
|
-
nstr, istr = yield(
|
117
|
+
nstr, istr = yield(
|
118
|
+
needle_str || results.value,
|
119
|
+
result.value,
|
120
|
+
results.needle,
|
121
|
+
result.match
|
122
|
+
)
|
110
123
|
|
111
124
|
if istr.to_s.strip.empty?
|
112
125
|
dice = lev = jaro_res = ngram_res = ngram_res = wngram_res = pos_res = 1
|
113
126
|
elsif nstr.to_s.strip.empty?
|
114
|
-
unless istr = needle_str
|
127
|
+
unless (istr = needle_str)
|
115
128
|
dice = lev = jaro_res = ngram_res = ngram_res = wngram_res = pos_res = 0
|
116
129
|
end
|
117
130
|
end
|
@@ -119,7 +132,7 @@ module Eco
|
|
119
132
|
require 'fuzzy_match'
|
120
133
|
require 'amatch'
|
121
134
|
res = ::FuzzyMatch.score_class.new(nstr, istr) unless dice && lev
|
122
|
-
|
135
|
+
|
123
136
|
dice ||= res&.dices_coefficient_similar || 0
|
124
137
|
lev ||= res&.levenshtein_similar || 0
|
125
138
|
jaro_res ||= jaro(nstr, istr)
|
@@ -129,6 +142,7 @@ module Eco
|
|
129
142
|
|
130
143
|
new_results << Result.new(*result.values_at(:match, :value, :needle_str), dice, lev, jaro_res, ngram_res, wngram_res, pos_res)
|
131
144
|
end
|
145
|
+
|
132
146
|
Results.new(results.needle, results.value, new_results).tap do |res|
|
133
147
|
res.order = options[:order] if options[:order]
|
134
148
|
res.threshold = options[:threshold] if options[:threshold]
|
@@ -137,24 +151,24 @@ module Eco
|
|
137
151
|
|
138
152
|
private
|
139
153
|
|
140
|
-
def jaro(
|
154
|
+
def jaro(str_1, str_2)
|
141
155
|
options = fuzzy_options.slice(*JARO_OPTIONS)
|
142
|
-
self.class.jaro_winkler(
|
156
|
+
self.class.jaro_winkler(str_1, str_2, **options)
|
143
157
|
end
|
144
158
|
|
145
|
-
def ngram(
|
159
|
+
def ngram(str_1, str_2)
|
146
160
|
options = { range: 3..5 }.merge(fuzzy_options.slice(*NGRAMS_OPTIONS))
|
147
|
-
self.class.ngrams_score(
|
161
|
+
self.class.ngrams_score(str_1, str_2, **options).ratio
|
148
162
|
end
|
149
163
|
|
150
|
-
def words_ngram(
|
164
|
+
def words_ngram(str_1, str_2)
|
151
165
|
options = { range: 3..7 }.merge(fuzzy_options.slice(*NGRAMS_OPTIONS))
|
152
|
-
self.class.words_ngrams_score(
|
166
|
+
self.class.words_ngrams_score(str_1, str_2, **options).ratio
|
153
167
|
end
|
154
168
|
|
155
|
-
def position(
|
169
|
+
def position(str_1, str_2)
|
156
170
|
options = fuzzy_options.slice(*POSITION_OPTIONS)
|
157
|
-
self.class.chars_position_score(
|
171
|
+
self.class.chars_position_score(str_1, str_2, **options).ratio
|
158
172
|
end
|
159
173
|
|
160
174
|
# @note
|
@@ -162,12 +176,18 @@ module Eco
|
|
162
176
|
# @param data [Enumerable, nil]
|
163
177
|
# @return [Array<Object>] the non-repeated values of `data`
|
164
178
|
def haystack(data = nil)
|
165
|
-
data = self if
|
166
|
-
|
167
|
-
|
179
|
+
data = self if is_a?(Enumerable) && !data
|
180
|
+
|
181
|
+
msg = "'data' should be an Enumerable. Given: #{data.class}"
|
182
|
+
raise ArgumentError, msg unless data.is_a?(Enumerable)
|
183
|
+
|
184
|
+
data = is_a?(Hash) ? values.flatten : to_a.flatten
|
185
|
+
|
168
186
|
data.uniq.compact.tap do |items|
|
169
|
-
if !fuzzy_read_method && found = items.find {|item| !item.is_a?(String)}
|
170
|
-
|
187
|
+
if !fuzzy_read_method && (found = items.find {|item| !item.is_a?(String)})
|
188
|
+
msg = "To use non String objects as 'haystack' you should provide `read:` or `options[:read]`. "
|
189
|
+
msg << "Given element: #{found.class}"
|
190
|
+
raise ArgumentError, msg
|
171
191
|
end
|
172
192
|
end
|
173
193
|
end
|
@@ -175,12 +195,13 @@ module Eco
|
|
175
195
|
def item_string(item, attr = fuzzy_read_method)
|
176
196
|
return item if !item || item.is_a?(String) || !attr
|
177
197
|
return attr.call(item) if attr.is_a?(Proc)
|
198
|
+
|
178
199
|
attr = attr.to_sym
|
179
|
-
|
200
|
+
item.send(attr) if item.respond_to?(attr, true)
|
180
201
|
end
|
181
202
|
|
182
203
|
def fuzzy_match_options(options = nil)
|
183
|
-
options
|
204
|
+
options ||= fuzzy_options
|
184
205
|
options.slice(*FUZZY_MATCH_OPTIONS).merge({
|
185
206
|
stop_words: PREPOSITIONS + PRONOUNS + ARTICLES
|
186
207
|
})
|
@@ -189,13 +210,11 @@ module Eco
|
|
189
210
|
def fuzzy_read_method
|
190
211
|
fuzzy_match_options[:read]
|
191
212
|
end
|
192
|
-
|
193
213
|
end
|
194
214
|
|
195
215
|
class << self
|
196
216
|
include FuzzyMatch::ClassMethods
|
197
217
|
end
|
198
|
-
|
199
218
|
end
|
200
219
|
end
|
201
220
|
end
|
@@ -16,7 +16,7 @@ module Eco::Data::Locations::NodeBase
|
|
16
16
|
raise ArgumentError, msg unless node.is_a?(Eco::Data::Locations::NodeBase)
|
17
17
|
|
18
18
|
node.node_hash.tap do |json|
|
19
|
-
json.merge!({
|
19
|
+
json.merge!({'parent_id' => parent_id}) unless parent_id == :unused
|
20
20
|
json.merge!(yield(node, json)) if block_given?
|
21
21
|
end
|
22
22
|
end
|
@@ -90,7 +90,7 @@ module Eco::Data::Locations::NodeBase
|
|
90
90
|
|
91
91
|
node_hash = serialize_node(child, parent_id: node_id, &block)
|
92
92
|
results << node_hash
|
93
|
-
node_hash[
|
93
|
+
node_hash['nodes'] = get_children(
|
94
94
|
child.id, parents,
|
95
95
|
parent: child, done_ids: done_ids,
|
96
96
|
level: level + 1, skipped: skipped,
|
@@ -105,7 +105,7 @@ module Eco::Data::Locations::NodeBase
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def parent_msg(parent)
|
108
|
-
parent ? "child of '#{parent.id}'" :
|
108
|
+
parent ? "child of '#{parent.id}'" : 'top level'
|
109
109
|
end
|
110
110
|
|
111
111
|
def level_msg(level)
|
@@ -113,7 +113,7 @@ module Eco::Data::Locations::NodeBase
|
|
113
113
|
end
|
114
114
|
|
115
115
|
def indent(level)
|
116
|
-
|
116
|
+
' ' * level
|
117
117
|
end
|
118
118
|
|
119
119
|
# Method to ensure the results are consistent
|
@@ -122,7 +122,7 @@ module Eco::Data::Locations::NodeBase
|
|
122
122
|
# because otherwise would be part of `done_ids` anyway.
|
123
123
|
# @param unlinked_trees [Array<Hash>] by excluding those done and skipped,
|
124
124
|
# it will treeify the unlinked nodes (the exclusion applies to `parants_hash`)
|
125
|
-
def check_results( # rubocop:disable Metrics/AbcSize
|
125
|
+
def check_results( # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
126
126
|
_tree, nodes, parents,
|
127
127
|
done_ids: {}, skipped: [], unlinked_trees: [],
|
128
128
|
warns: [], &block
|
@@ -138,9 +138,9 @@ module Eco::Data::Locations::NodeBase
|
|
138
138
|
|
139
139
|
# The reason of missing nodes in the output tree is unknown!
|
140
140
|
if skipped.empty? && unlinked_parent_ids.empty?
|
141
|
-
msg
|
142
|
-
msg <<
|
143
|
-
msg <<
|
141
|
+
msg = []
|
142
|
+
msg << 'BUG in this library (open issue with maintainers).'
|
143
|
+
msg << 'There were no skipped nodes nor missin referred parents, and yet:'
|
144
144
|
msg << " * the tree nodes count: #{done_ids.count} ..."
|
145
145
|
msg << " * doesn't match the original nodes count: #{nodes.count}"
|
146
146
|
raise msg.join("\n")
|
@@ -181,7 +181,7 @@ module Eco::Data::Locations::NodeBase
|
|
181
181
|
str_skipped = (residual_skipped.count < 15 ? " => #{residual_skipped.map(&:id).join(', ')}" : '')
|
182
182
|
|
183
183
|
msg = []
|
184
|
-
msg <<
|
184
|
+
msg << 'After treeifying via the unlinked_parents:'
|
185
185
|
msg << " * total_nodes: #{nodes.count}"
|
186
186
|
msg << " * tracked_nodes: #{tracked_nodes.count}"
|
187
187
|
msg << " * untracked_nodes: #{untracked_nodes.count}"
|
@@ -230,14 +230,16 @@ module Eco::Data::Locations::NodeBase
|
|
230
230
|
node_hash = serialize_node(child, parent_id: node_id, &block) unless src_plain
|
231
231
|
descendants = get_tree_nodes_raw(child.id, parents, src_plain: src_plain, &block).tap do |desc|
|
232
232
|
next unless (nil_count = desc.count(nil)).positive?
|
233
|
+
|
233
234
|
log(:debug) {
|
234
235
|
"get_tree_nodes_raw gave #{nil_count} nil values for nodes of #{child.id}"
|
235
236
|
}
|
236
237
|
end
|
238
|
+
|
237
239
|
next results.concat(descendants) if src_plain
|
238
240
|
|
239
241
|
results << node_hash.merge({
|
240
|
-
|
242
|
+
'nodes' => descendants.compact
|
241
243
|
})
|
242
244
|
end
|
243
245
|
end
|
@@ -256,7 +258,7 @@ module Eco::Data::Locations::NodeBase
|
|
256
258
|
|
257
259
|
# With given a skipped `node` (repeated `id`), it gives different warnings,
|
258
260
|
# provided that the context in which the double-up `id` happened is identified.
|
259
|
-
def report_skipped_node( # rubocop:disable Metrics/AbcSize
|
261
|
+
def report_skipped_node( # rubocop:disable Metrics/AbcSize, Metrics/ParameterLists, Metrics/MethodLength
|
260
262
|
node, parent,
|
261
263
|
done_ids, level,
|
262
264
|
level_ids, parents,
|
data/lib/eco/data/mapper.rb
CHANGED
@@ -2,7 +2,7 @@ module Eco
|
|
2
2
|
module Data
|
3
3
|
class Mapper
|
4
4
|
# it expects [[v1a, v1b], [v2a, v2b] ...]
|
5
|
-
def initialize
|
5
|
+
def initialize(array_of_arrays = [], internal: :last, insensitive: false)
|
6
6
|
@internal_order = internal
|
7
7
|
@source = array_of_arrays
|
8
8
|
@insensitive = insensitive
|
@@ -23,7 +23,7 @@ module Eco
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
@by_internal = @source.reverse.
|
26
|
+
@by_internal = @source.reverse.to_h(&:reverse).tap do |h_data|
|
27
27
|
next unless insensitive?
|
28
28
|
|
29
29
|
h_data.dup.each do |key, value|
|
@@ -57,7 +57,7 @@ module Eco
|
|
57
57
|
src_dup.map(&:reverse)
|
58
58
|
end
|
59
59
|
|
60
|
-
def +(array_of_arrays)
|
60
|
+
def +(array_of_arrays) # rubocop:disable Naming/BinaryOperatorParameterName
|
61
61
|
self.class.new(array_of_arrays + to_a, internal: @internal_order)
|
62
62
|
end
|
63
63
|
|
@@ -70,7 +70,7 @@ module Eco
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def internal?(value)
|
73
|
-
return true
|
73
|
+
return true unless @source
|
74
74
|
|
75
75
|
value = value.downcase if insensitive?
|
76
76
|
@by_internal.key?(value)
|
@@ -9,8 +9,8 @@ module Eco
|
|
9
9
|
def logger
|
10
10
|
if instance_variable_defined?(:@session) && !@session.nil?
|
11
11
|
@session.logger
|
12
|
-
elsif respond_to?(:session)
|
13
|
-
session.logger
|
12
|
+
elsif respond_to?(:session, true)
|
13
|
+
send(:session).logger
|
14
14
|
elsif Object.const_defined?(:ASSETS)
|
15
15
|
ASSETS.session.logger
|
16
16
|
elsif defined?(super)
|
@@ -31,8 +31,8 @@ module Eco
|
|
31
31
|
levels = levels.compact.uniq.map(&:to_sym)
|
32
32
|
levels.unshift(:info) if levels.include?(:general) && levels.length == 1
|
33
33
|
|
34
|
-
levels.each do |level|
|
35
|
-
next unless logger.respond_to?(:level)
|
34
|
+
levels.uniq.each do |level|
|
35
|
+
next unless logger.respond_to?(:level, true)
|
36
36
|
|
37
37
|
logger.send(level, &block)
|
38
38
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Eco::Language::Delegation
|
2
|
+
class ChainableDelegator < SimpleDelegator
|
3
|
+
include ForDelegator::DelegatedClass
|
4
|
+
include ForDelegator::ConstDelegator
|
5
|
+
include ForDelegator::ConstLookupHooks
|
6
|
+
|
7
|
+
# It allows to chain delegators, when the first parameter is an
|
8
|
+
# instance of `delegated_class`.
|
9
|
+
# @note it also allows to create an instance of `delegated_class`
|
10
|
+
# on initialization.
|
11
|
+
def initialize(*args, **kargs, &block)
|
12
|
+
obj = args.first
|
13
|
+
obj = new(*args, **kargs, &block) unless of_kind?(obj)
|
14
|
+
|
15
|
+
super(obj)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# rubocop:disable Naming/MethodParameterName
|
2
|
+
|
3
|
+
module Eco::Language::Delegation
|
4
|
+
module DelegatingMissing
|
5
|
+
class << self
|
6
|
+
def included(base)
|
7
|
+
super
|
8
|
+
|
9
|
+
base.extend Eco::Language::Klass::HelpersBuilt
|
10
|
+
base.extend ClassMethods
|
11
|
+
base.inheritable_class_vars :_delegating_missing, :delegating_missing_to
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def delegating_missing(*these, to:)
|
17
|
+
msg = "Delegating to: should be String or Symbol. Given: #{to.class}"
|
18
|
+
raise ArgumentError, msg unless sym_or_string?(to)
|
19
|
+
|
20
|
+
these.map do |this|
|
21
|
+
msg = "Expecting String or Symbol. Given: #{this}."
|
22
|
+
raise ArgumentError, msg unless sym_or_string?(this)
|
23
|
+
|
24
|
+
this.to_sym
|
25
|
+
end.each do |this|
|
26
|
+
_delegating_missing[this] = to
|
27
|
+
end
|
28
|
+
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def delegating_missing_to(to = nil)
|
33
|
+
return @delegating_missing_to if to.nil?
|
34
|
+
|
35
|
+
msg = "Expecting String or Symbol. Given: #{to}."
|
36
|
+
raise ArgumentError, msg unless sym_or_string?(to)
|
37
|
+
|
38
|
+
|
39
|
+
@delegating_missing_to = to.to_sym
|
40
|
+
end
|
41
|
+
|
42
|
+
def delegating_missing?(sym)
|
43
|
+
return true if sym.nil? && delegating_missing_to
|
44
|
+
return false unless sym_or_string?(sym)
|
45
|
+
return true if _delegating_missing.key?(sym.to_sym)
|
46
|
+
return true if delegating_missing_to
|
47
|
+
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
def delegating_missing_target(instance, at: nil)
|
52
|
+
return unless delegating_missing?(at)
|
53
|
+
return unless (subject_ref = _delegating_missing[at] || delegating_missing_to)
|
54
|
+
|
55
|
+
instance_has_method =
|
56
|
+
instance.methods.include?(subject_ref) ||
|
57
|
+
instance.private_methods.include?(subject_ref)
|
58
|
+
|
59
|
+
return instance.method(subject_ref).call if instance_has_method
|
60
|
+
return unless at.to_s.start_with?('@')
|
61
|
+
return unless instance.instance_variable_defined?(at)
|
62
|
+
|
63
|
+
instance.instance_variable_get(at)
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def _delegating_missing
|
69
|
+
@_delegating_missing ||= {}
|
70
|
+
end
|
71
|
+
|
72
|
+
def sym_or_string?(value)
|
73
|
+
return false unless value.is_a?(Symbol) || value.is_a?(String)
|
74
|
+
return false if value.to_s.strip.empty?
|
75
|
+
|
76
|
+
true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# INSTANCE Methods
|
81
|
+
|
82
|
+
def respond_to_missing?(method_name, include_private = false)
|
83
|
+
super
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# @note if missing, redirect all parameters to `receiver`,
|
89
|
+
# as long as responds_to `method_name`
|
90
|
+
def method_missing(method_name, *args, **kargs, &block)
|
91
|
+
return super unless self.class.delegating_missing?(method_name)
|
92
|
+
|
93
|
+
target = self.class.delegating_missing_target(self, at: method_name)
|
94
|
+
|
95
|
+
if method_name.to_s.start_with?('@')
|
96
|
+
target.instance_variable_get(method_name)
|
97
|
+
else
|
98
|
+
target.send(method_name, *args, **kargs, &block)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# rubocop:enable Naming/MethodParameterName
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Eco::Language::Delegation
|
2
|
+
# Class to lookup constants through `delegated_class`.
|
3
|
+
# @note it uses `DelegatingMissing`.
|
4
|
+
# @note it tries to lookup on the `class` of the `delegating_missing_to`
|
5
|
+
# object. Which requires an instance of the delegator to exist, with
|
6
|
+
# the aim of scoping its class (so it can chain constant lookup), unless
|
7
|
+
# `delegated_class` is explicitly stated.
|
8
|
+
# @note that not setting `delegated_class` explicitly could fail
|
9
|
+
# to chain the looup.
|
10
|
+
module DelegatingMissingConst
|
11
|
+
class << self
|
12
|
+
def included(base)
|
13
|
+
super
|
14
|
+
|
15
|
+
base.send :include, DelegatingMissing
|
16
|
+
base.send :include, ForDelegator::ConstDelegator
|
17
|
+
base.extend ClassMethods
|
18
|
+
|
19
|
+
# because we inject `#initialize`
|
20
|
+
base.send :prepend, InstanceMethods
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
# Set always `delegated_class` when fetching the
|
26
|
+
# `delegating_missing_to` object.
|
27
|
+
def delegating_missing_target(instance, at: nil)
|
28
|
+
super.tap do |target|
|
29
|
+
next unless target
|
30
|
+
next unless at.nil?
|
31
|
+
|
32
|
+
delegated_class target.class
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module InstanceMethods
|
38
|
+
# Set the `delegated_class` to chain **constant lookup**
|
39
|
+
# via `delegating_missing_to.class`.
|
40
|
+
# @note this requires that the target can be fetched without passing
|
41
|
+
# parameters (as it is typically the case with `delegating_missing_to`).
|
42
|
+
def initialize(...)
|
43
|
+
super if defined?(super)
|
44
|
+
|
45
|
+
delegated_class.tap do |klass|
|
46
|
+
next unless (target = self.class.delegating_missing_target(self))
|
47
|
+
|
48
|
+
self.class.delegated_class target.class
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Eco::Language::Delegation
|
2
|
+
module DelegatingMissingOnClass
|
3
|
+
class << self
|
4
|
+
def included(base)
|
5
|
+
super
|
6
|
+
|
7
|
+
base.extend Eco::Language::Klass::HelpersBuilt
|
8
|
+
base.extend ClassMethods
|
9
|
+
base.inheritable_class_vars :delegating_missing_on_class_to
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def delegating_missing_on_class_to(to = nil)
|
15
|
+
return @delegating_missing_on_class_to if to.nil?
|
16
|
+
|
17
|
+
msg = "Expecting String or Symbol. Given: #{to}."
|
18
|
+
raise ArgumentError, msg unless sym_or_string?(to)
|
19
|
+
|
20
|
+
@delegating_missing_on_class_to = to
|
21
|
+
end
|
22
|
+
|
23
|
+
def respond_to_missing?(method_name, include_private = false)
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# @note if missing, redirect all parameters to `target`,
|
30
|
+
# as long as responds_to `method_name`
|
31
|
+
def method_missing(method_name, *args, **kargs, &block)
|
32
|
+
return super unless (target = delegating_missing_on_class_target)
|
33
|
+
|
34
|
+
target.send(method_name, *args, **kargs, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
# retrieves the delegating_missing_on_class_to object
|
38
|
+
def delegating_missing_on_class_target
|
39
|
+
return unless @delegating_missing_on_class_to
|
40
|
+
|
41
|
+
# fetch the object behind the method
|
42
|
+
method(@delegating_missing_on_class_to).call
|
43
|
+
end
|
44
|
+
|
45
|
+
def sym_or_string?(value)
|
46
|
+
return false unless value.is_a?(Symbol) || value.is_a?(String)
|
47
|
+
return false if value.to_s.strip.empty?
|
48
|
+
|
49
|
+
true
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|