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.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +76 -5
  3. data/eco-helpers.gemspec +2 -1
  4. data/lib/eco/api/common/class_helpers.rb +1 -136
  5. data/lib/eco/api/common/loaders/base.rb +1 -1
  6. data/lib/eco/api/common/loaders/case_base.rb +1 -1
  7. data/lib/eco/api/common/loaders/config/cli.rb +1 -1
  8. data/lib/eco/api/common/loaders/config/session.rb +1 -1
  9. data/lib/eco/api/common/loaders/config/workflow.rb +1 -1
  10. data/lib/eco/api/common/loaders/config.rb +2 -5
  11. data/lib/eco/api/common/loaders/error_handler.rb +1 -1
  12. data/lib/eco/api/common/loaders/parser.rb +2 -2
  13. data/lib/eco/api/common/loaders/policy.rb +1 -1
  14. data/lib/eco/api/common/loaders/use_case/target_model.rb +1 -1
  15. data/lib/eco/api/common/loaders/use_case/type.rb +1 -1
  16. data/lib/eco/api/common/loaders/use_case.rb +1 -1
  17. data/lib/eco/api/common/people/default_parsers/archived_parser.rb +19 -0
  18. data/lib/eco/api/common/people/default_parsers/boolean_parser.rb +4 -4
  19. data/lib/eco/api/common/people/default_parsers/date_parser.rb +3 -3
  20. data/lib/eco/api/common/people/default_parsers/freemium_parser.rb +6 -6
  21. data/lib/eco/api/common/people/default_parsers/login_providers_parser.rb +3 -3
  22. data/lib/eco/api/common/people/default_parsers/multi_parser.rb +4 -4
  23. data/lib/eco/api/common/people/default_parsers/policy_groups_parser.rb +9 -6
  24. data/lib/eco/api/common/people/default_parsers/send_invites_parser.rb +6 -5
  25. data/lib/eco/api/common/people/default_parsers/xls_parser.rb +2 -2
  26. data/lib/eco/api/common/people/default_parsers.rb +1 -0
  27. data/lib/eco/api/common/people/entries.rb +16 -15
  28. data/lib/eco/api/common/people/person_entry.rb +53 -37
  29. data/lib/eco/api/common/people/person_parser.rb +8 -6
  30. data/lib/eco/api/common/people/supervisor_helpers.rb +3 -1
  31. data/lib/eco/api/common/session/logger/channels.rb +2 -1
  32. data/lib/eco/api/common/session/logger.rb +2 -2
  33. data/lib/eco/api/common/session/mailer/aws_provider.rb +3 -2
  34. data/lib/eco/api/common/session/mailer/provider_base.rb +2 -1
  35. data/lib/eco/api/common/session/mailer/sendgrid_provider.rb +9 -9
  36. data/lib/eco/api/common/session/mailer.rb +5 -3
  37. data/lib/eco/api/common/session/sftp.rb +11 -4
  38. data/lib/eco/api/common/version_patches/object.rb +2 -1
  39. data/lib/eco/api/custom/mailer.rb +1 -1
  40. data/lib/eco/api/error/handlers.rb +3 -3
  41. data/lib/eco/api/error.rb +17 -17
  42. data/lib/eco/api/microcases/people/apply_changes/set_account/account_excluded.rb +3 -11
  43. data/lib/eco/api/microcases/people/apply_changes/set_core/core_excluded.rb +4 -1
  44. data/lib/eco/api/microcases/people/manage/search.rb +3 -1
  45. data/lib/eco/api/organization/people.rb +1 -0
  46. data/lib/eco/api/policies.rb +2 -2
  47. data/lib/eco/api/session/batch/job/sets.rb +1 -0
  48. data/lib/eco/api/session/batch/job/type.rb +1 -0
  49. data/lib/eco/api/session/batch/job.rb +2 -2
  50. data/lib/eco/api/session/batch/launcher/valid_methods.rb +3 -2
  51. data/lib/eco/api/session/batch/launcher.rb +4 -5
  52. data/lib/eco/api/session/batch/searcher.rb +4 -4
  53. data/lib/eco/api/session/config/api.rb +2 -2
  54. data/lib/eco/api/session/config/apis/enviro_spaces.rb +2 -2
  55. data/lib/eco/api/session/config/post_launch.rb +7 -4
  56. data/lib/eco/api/session/config/sftp.rb +1 -1
  57. data/lib/eco/api/session/config/tagtree.rb +1 -1
  58. data/lib/eco/api/session/config/workflow.rb +4 -4
  59. data/lib/eco/api/session/config.rb +25 -24
  60. data/lib/eco/api/session.rb +4 -4
  61. data/lib/eco/api/usecases/base_case/model.rb +2 -1
  62. data/lib/eco/api/usecases/base_case/type.rb +2 -1
  63. data/lib/eco/api/usecases/base_io/validations.rb +6 -4
  64. data/lib/eco/api/usecases/cli/option.rb +5 -2
  65. data/lib/eco/api/usecases/default/people/amend/clear_abilities_case.rb +2 -2
  66. data/lib/eco/api/usecases/default/people/amend/restore_db_case.rb +16 -9
  67. data/lib/eco/api/usecases/default/people/treat/analyse_people_case.rb +20 -20
  68. data/lib/eco/api/usecases/default.rb +5 -5
  69. data/lib/eco/api/usecases/default_cases/to_csv_case.rb +8 -8
  70. data/lib/eco/api/usecases/default_cases/upsert_case.rb +4 -4
  71. data/lib/eco/api/usecases/graphql/helpers/base.rb +1 -1
  72. data/lib/eco/api/usecases/graphql/helpers/location/base/tree_tracking.rb +5 -1
  73. data/lib/eco/api/usecases/graphql/helpers/location/command/diffs/stages/commandable.rb +5 -3
  74. data/lib/eco/api/usecases/graphql/helpers/location/command/result.rb +3 -3
  75. data/lib/eco/api/usecases/graphql/helpers/location/command.rb +3 -0
  76. data/lib/eco/api/usecases/graphql/samples/location/command/dsl.rb +2 -2
  77. data/lib/eco/api/usecases/graphql/samples/location/command/service/tree_update.rb +9 -3
  78. data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/inputable.rb +5 -4
  79. data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff/convertible/parsing.rb +5 -2
  80. data/lib/eco/api/usecases/graphql/samples/location/service/tree_diff.rb +3 -3
  81. data/lib/eco/api/usecases/graphql/utils/sftp.rb +1 -1
  82. data/lib/eco/api/usecases/lib/{file_pattern.rb → files/file_pattern.rb} +1 -1
  83. data/lib/eco/api/usecases/lib/{sftp.rb → files/sftp.rb} +19 -7
  84. data/lib/eco/api/usecases/lib/files.rb +7 -0
  85. data/lib/eco/api/usecases/lib.rb +1 -2
  86. data/lib/eco/api/usecases/ooze_cases/export_register_case.rb +5 -5
  87. data/lib/eco/api/usecases/ooze_samples/helpers/exportable_ooze.rb +14 -11
  88. data/lib/eco/api/usecases/ooze_samples/helpers_migration/copying.rb +14 -23
  89. data/lib/eco/api/usecases/ooze_samples/helpers_migration/typed_fields_pairing.rb +49 -27
  90. data/lib/eco/api/usecases/ooze_samples/ooze_base_case.rb +9 -9
  91. data/lib/eco/api/usecases/ooze_samples/ooze_run_base_case.rb +1 -1
  92. data/lib/eco/api/usecases/ooze_samples/register_export_case.rb +25 -17
  93. data/lib/eco/api/usecases/ooze_samples/register_migration_case.rb +41 -24
  94. data/lib/eco/api/usecases/ooze_samples/register_update_case.rb +16 -15
  95. data/lib/eco/api/usecases/samples/drivers/cli/sftp_cli.rb +15 -15
  96. data/lib/eco/api/usecases/samples/drivers/cli/url_pull_cli.rb +5 -5
  97. data/lib/eco/api/usecases/samples/drivers/sftp_sample.rb +5 -3
  98. data/lib/eco/api/usecases/use_case.rb +6 -6
  99. data/lib/eco/api/usecases/use_case_chain/chaining.rb +6 -6
  100. data/lib/eco/api/usecases/use_case_chain.rb +4 -4
  101. data/lib/eco/api/usecases/use_case_io.rb +2 -1
  102. data/lib/eco/api/usecases.rb +9 -9
  103. data/lib/eco/cli/config/options_set.rb +4 -4
  104. data/lib/eco/cli/config/use_cases.rb +3 -3
  105. data/lib/eco/cli/scripting/argument.rb +1 -1
  106. data/lib/eco/cli_default/input.rb +9 -9
  107. data/lib/eco/cli_default/options.rb +125 -100
  108. data/lib/eco/cli_default/people.rb +3 -3
  109. data/lib/eco/cli_default/usecases.rb +83 -83
  110. data/lib/eco/cli_default/workflow.rb +7 -7
  111. data/lib/eco/data/files/helpers.rb +7 -5
  112. data/lib/eco/data/fuzzy_match/result.rb +69 -26
  113. data/lib/eco/data/fuzzy_match/results.rb +10 -10
  114. data/lib/eco/data/fuzzy_match/score.rb +13 -8
  115. data/lib/eco/data/fuzzy_match.rb +69 -50
  116. data/lib/eco/data/hashes/diff_result/meta.rb +2 -1
  117. data/lib/eco/data/locations/node_base/treeify.rb +13 -11
  118. data/lib/eco/data/locations/node_diff/accessors.rb +2 -1
  119. data/lib/eco/data/mapper.rb +4 -4
  120. data/lib/eco/language/auxiliar_logger.rb +4 -4
  121. data/lib/eco/language/delegation/chainable_delegator.rb +18 -0
  122. data/lib/eco/language/delegation/delegating_missing.rb +104 -0
  123. data/lib/eco/language/delegation/delegating_missing_const.rb +53 -0
  124. data/lib/eco/language/delegation/delegating_missing_on_class.rb +53 -0
  125. data/lib/eco/language/delegation/for_delegator/const_delegator.rb +66 -0
  126. data/lib/eco/language/delegation/for_delegator/const_lookup_hooks.rb +99 -0
  127. data/lib/eco/language/delegation/for_delegator/delegated_class.rb +71 -0
  128. data/lib/eco/language/delegation/for_delegator.rb +11 -0
  129. data/lib/eco/language/delegation.rb +10 -0
  130. data/lib/eco/language/klass/builder.rb +29 -0
  131. data/lib/eco/language/klass/helpers_built.rb +9 -0
  132. data/lib/eco/language/klass/hierarchy.rb +34 -0
  133. data/lib/eco/language/klass/inheritable_class_vars.rb +45 -0
  134. data/lib/eco/language/klass/naming.rb +21 -0
  135. data/lib/eco/language/klass/resolver.rb +30 -0
  136. data/lib/eco/language/klass/when_inherited.rb +11 -13
  137. data/lib/eco/language/klass.rb +6 -0
  138. data/lib/eco/language/methods.rb +0 -1
  139. data/lib/eco/language/models/class_helpers.rb +25 -23
  140. data/lib/eco/language/models/collection.rb +12 -2
  141. data/lib/eco/language/strings/underscore.rb +17 -0
  142. data/lib/eco/language/strings.rb +8 -0
  143. data/lib/eco/language.rb +2 -0
  144. data/lib/eco/version.rb +1 -1
  145. metadata +39 -7
  146. data/lib/eco/language/methods/delegate_missing.rb +0 -29
@@ -11,8 +11,10 @@ module Eco
11
11
 
12
12
  class << self
13
13
  def included(base)
14
- base.send(:include, InstanceMethods)
15
- base.extend(ClassMethods)
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(str1, str2, **options)
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(str1, str2, **options)
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
- :identities, :groupings, :stop_words, :read,
42
- :must_match_grouping, :must_match_at_least_one_word,
43
- :gather_last_result, :threshold
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 = [:ignore_case, :weight]
47
- NGRAMS_OPTIONS = [:range]
48
- POSITION_OPTIONS = [:max_distance]
49
- RESULTS_OPTIONS = [:order, :threshold]
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
- attr_accessor :fuzzy_options
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
- # TODO: integration for options[:unique_words] => to ensure repeated words do not bring down the score are cut by threshold
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
- unless item == needle
86
- item_str = item_string(item)
90
+ next if item == needle
87
91
 
88
- if item_str.to_s.strip.empty? || needle_str.to_s.strip.empty?
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
- jaro_res ||= jaro(needle_str, item_str)
93
- ngram_res ||= ngram(needle_str, item_str)
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
- raise "You should provide a block |needle_str, item_str, needle, item|" unless block_given?
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(needle_str || results.value, result.value, results.needle, result.match)
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(str1, str2)
154
+ def jaro(str_1, str_2)
141
155
  options = fuzzy_options.slice(*JARO_OPTIONS)
142
- self.class.jaro_winkler(str1, str2, **options)
156
+ self.class.jaro_winkler(str_1, str_2, **options)
143
157
  end
144
158
 
145
- def ngram(str1, str2)
159
+ def ngram(str_1, str_2)
146
160
  options = { range: 3..5 }.merge(fuzzy_options.slice(*NGRAMS_OPTIONS))
147
- self.class.ngrams_score(str1, str2, **options).ratio
161
+ self.class.ngrams_score(str_1, str_2, **options).ratio
148
162
  end
149
163
 
150
- def words_ngram(str1, str2)
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(str1, str2, **options).ratio
166
+ self.class.words_ngrams_score(str_1, str_2, **options).ratio
153
167
  end
154
168
 
155
- def position(str1, str2)
169
+ def position(str_1, str_2)
156
170
  options = fuzzy_options.slice(*POSITION_OPTIONS)
157
- self.class.chars_position_score(str1, str2, **options).ratio
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 self.is_a?(Enumerable) && !data
166
- raise "'data' should be an Enumerable. Given: #{data.class}" unless data.is_a?(Enumerable)
167
- data = self.is_a?(Hash) ? self.values.flatten : to_a.flatten
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
- raise "To use non String objects as 'haystack' you should provide `read:` or `options[:read]`. Given element: #{found.class}"
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
- return item.send(attr) if item.respond_to?(attr)
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 = fuzzy_options unless 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
@@ -5,7 +5,8 @@ module Eco
5
5
  module Meta
6
6
  class << self
7
7
  def included(base)
8
- super(base)
8
+ super
9
+
9
10
  base.extend Eco::Language::Models::ClassHelpers
10
11
  base.extend ClassMethods
11
12
  base.inheritable_class_vars :key, :compared_attrs, :case_sensitive
@@ -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!({"parent_id" => parent_id}) unless parent_id == :unused
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["nodes"] = get_children(
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}'" : "top level"
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
- " " * level
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 << "BUG in this library (open issue with maintainers)."
143
- msg << "There were no skipped nodes nor missin referred parents, and yet:"
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 << "After treeifying via the unlinked_parents:"
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
- "nodes" => descendants.compact
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,
@@ -2,7 +2,8 @@ class Eco::Data::Locations::NodeDiff
2
2
  module Accessors
3
3
  class << self
4
4
  def included(base)
5
- super(base)
5
+ super
6
+
6
7
  base.extend Eco::Language::Models::ClassHelpers
7
8
  base.extend ClassMethods
8
9
  base.inheritable_class_vars :exposed_attrs
@@ -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 (array_of_arrays = [], internal: :last, insensitive: false)
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.map(&:reverse).to_h.tap do |h_data|
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 unless @source
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