ecoportal-api-v2 2.0.16 → 3.1.1
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 +24 -1
- data/ecoportal-api-v2.gemspec +1 -1
- data/lib/ecoportal/api/common/concerns.rb +2 -2
- data/lib/ecoportal/api/common/content/class_helpers.rb +42 -7
- data/lib/ecoportal/api/common/content/client.rb +2 -1
- data/lib/ecoportal/api/common/content/collection_model/doc/rooted_key.rb +8 -8
- data/lib/ecoportal/api/common/content/collection_model/doc.rb +2 -2
- data/lib/ecoportal/api/common/content/collection_model/doc_mutation.rb +3 -3
- data/lib/ecoportal/api/common/content/collection_model/model.rb +6 -6
- data/lib/ecoportal/api/common/content/collection_model/modifiers.rb +3 -3
- data/lib/ecoportal/api/common/content/collection_model/mutation.rb +3 -3
- data/lib/ecoportal/api/common/content/collection_model.rb +5 -5
- data/lib/ecoportal/api/common/content/double_model/attributable/nesting/cascaded_callback.rb +203 -98
- data/lib/ecoportal/api/common/content/double_model/attributable/nesting/embeddable.rb +49 -59
- data/lib/ecoportal/api/common/content/double_model/attributable/nesting/keyable.rb +102 -114
- data/lib/ecoportal/api/common/content/double_model/attributable/nesting.rb +5 -3
- data/lib/ecoportal/api/common/content/double_model/attributable.rb +5 -5
- data/lib/ecoportal/api/common/content/double_model/diffable/diff_service.rb +33 -0
- data/lib/ecoportal/api/common/content/double_model/{diffable_model.rb → diffable.rb} +12 -5
- data/lib/ecoportal/api/common/content/double_model/double_doc/linkable_doc.rb +9 -4
- data/lib/ecoportal/api/common/content/double_model/double_doc/replaceable_doc.rb +10 -2
- data/lib/ecoportal/api/common/content/double_model/double_doc/reset_consolidate.rb +1 -1
- data/lib/ecoportal/api/common/content/double_model/double_doc/rooted_key.rb +10 -3
- data/lib/ecoportal/api/common/content/double_model/double_doc.rb +5 -5
- data/lib/ecoportal/api/common/content/double_model/hash_helpers.rb +23 -4
- data/lib/ecoportal/api/common/content/double_model/modifiers.rb +2 -2
- data/lib/ecoportal/api/common/content/double_model.rb +9 -9
- data/lib/ecoportal/api/common/content/hash_diff_patch.rb +21 -7
- data/lib/ecoportal/api/common/content/model_helpers.rb +1 -1
- data/lib/ecoportal/api/common/content.rb +11 -11
- data/lib/ecoportal/api/common.v2.rb +2 -2
- data/lib/ecoportal/api/v2/page/component/action.rb +13 -11
- data/lib/ecoportal/api/v2/page/component/action_field.rb +14 -12
- data/lib/ecoportal/api/v2/page/component/actions_field.rb +2 -1
- data/lib/ecoportal/api/v2/page/component/chart_field/config.rb +1 -2
- data/lib/ecoportal/api/v2/page/component/chart_field.rb +48 -44
- data/lib/ecoportal/api/v2/page/component/chart_fr_field.rb +0 -1
- data/lib/ecoportal/api/v2/page/component/checklist_field.rb +9 -6
- data/lib/ecoportal/api/v2/page/component/checklist_item.rb +2 -3
- data/lib/ecoportal/api/v2/page/component/contractor_entities_field.rb +18 -17
- data/lib/ecoportal/api/v2/page/component/date_field.rb +19 -18
- data/lib/ecoportal/api/v2/page/component/file.rb +3 -3
- data/lib/ecoportal/api/v2/page/component/files_field.rb +9 -6
- data/lib/ecoportal/api/v2/page/component/gauge_field.rb +3 -2
- data/lib/ecoportal/api/v2/page/component/gauge_stop.rb +26 -26
- data/lib/ecoportal/api/v2/page/component/geo_field.rb +2 -2
- data/lib/ecoportal/api/v2/page/component/image.rb +6 -5
- data/lib/ecoportal/api/v2/page/component/images_field.rb +21 -20
- data/lib/ecoportal/api/v2/page/component/law.rb +3 -4
- data/lib/ecoportal/api/v2/page/component/law_field.rb +2 -2
- data/lib/ecoportal/api/v2/page/component/number_field.rb +1 -1
- data/lib/ecoportal/api/v2/page/component/people_field.rb +19 -19
- data/lib/ecoportal/api/v2/page/component/plain_text_field.rb +6 -7
- data/lib/ecoportal/api/v2/page/component/reference_field.rb +1 -1
- data/lib/ecoportal/api/v2/page/component/rich_text_field.rb +3 -3
- data/lib/ecoportal/api/v2/page/component/selection_field.rb +32 -35
- data/lib/ecoportal/api/v2/page/component/selection_options.rb +12 -7
- data/lib/ecoportal/api/v2/page/component/tag_field.rb +5 -4
- data/lib/ecoportal/api/v2/page/component.rb +21 -21
- data/lib/ecoportal/api/v2/page/force/bindings.rb +49 -39
- data/lib/ecoportal/api/v2/page/force.rb +9 -9
- data/lib/ecoportal/api/v2/page/forces.rb +1 -1
- data/lib/ecoportal/api/v2/page/permit.rb +3 -3
- data/lib/ecoportal/api/v2/page/sections.rb +19 -14
- data/lib/ecoportal/api/v2/page/stage.rb +27 -20
- data/lib/ecoportal/api/v2/page/stages.rb +1 -1
- data/lib/ecoportal/api/v2/page.rb +13 -12
- data/lib/ecoportal/api/v2/pages/page_stage.rb +2 -2
- data/lib/ecoportal/api/v2/pages.rb +2 -2
- data/lib/ecoportal/api/v2/registers/page_result.rb +3 -3
- data/lib/ecoportal/api/v2/registers/register.rb +4 -5
- data/lib/ecoportal/api/v2/registers/search_results.rb +1 -1
- data/lib/ecoportal/api/v2/registers/stages_result.rb +1 -1
- data/lib/ecoportal/api/v2/registers.rb +6 -6
- data/lib/ecoportal/api/v2/s3/files/batch_upload.rb +1 -0
- data/lib/ecoportal/api/v2/s3/files.rb +3 -3
- data/lib/ecoportal/api/v2.rb +4 -4
- data/lib/ecoportal/api/v2_version.rb +1 -1
- data/lib/ecoportal/api-v2.rb +4 -5
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9f6265c8e79e49dfb8c121860260f99abf957c9f1649764ee66fcab3e7f136fd
|
4
|
+
data.tar.gz: 4de91b16581dbe57f9a23b8eb48a9fe64f365b558844f663d7471bf84a6dff75
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e73d7760680b0a3966610195c674bd7aacc6a4b8e117140edc29d42de7cb47f69eda51a36900062bbe3043d9b6581a833994e34a32a738f979ae1a64497b5284
|
7
|
+
data.tar.gz: 584efdc89b150aad2ea3d0e214a11133fc56cc9b9335cb05bb0b994617dd2fc24187ccc5df46ea06bc1a450f3e212971aa8a30fc17b8ad6b025950f700a94c68
|
data/CHANGELOG.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
|
5
|
-
## [
|
5
|
+
## [3.1.2] - 2025-05-xx
|
6
6
|
|
7
7
|
### Added
|
8
8
|
|
@@ -10,6 +10,29 @@ All notable changes to this project will be documented in this file.
|
|
10
10
|
|
11
11
|
### Fixed
|
12
12
|
|
13
|
+
## [3.1.1] - 2025-05-xx
|
14
|
+
|
15
|
+
### Added
|
16
|
+
|
17
|
+
- `Ecoportal::API::Common::Content::DoubleModel::HashHelpers`
|
18
|
+
- `Added` `#dig_path?` to check if `path` exists.
|
19
|
+
|
20
|
+
### Changed
|
21
|
+
|
22
|
+
- upgraded `ecoportal-api` gem
|
23
|
+
- `Ecoportal::API::Common::Content::HashPatchDiff` as well as a **concern**.
|
24
|
+
- Renamed `Ecoportal::API::Common::Content::DoubleModel::DiffableModel` to
|
25
|
+
- `Ecoportal::API::Common::Content::DoubleModel::Diffable`
|
26
|
+
- **Move** `diff` to **service class**.
|
27
|
+
- `require` to `require_relative` where applicable.
|
28
|
+
- **Renamed** `#dig_set` and `#dig_delete` to `#dig_set!` and `#dig_delete!`
|
29
|
+
|
30
|
+
### Fixed
|
31
|
+
|
32
|
+
- `inheritable_class_vars`
|
33
|
+
- Some objects should be **dupped** or even **cloned**
|
34
|
+
- `inherited` should be private
|
35
|
+
|
13
36
|
## [2.0.16] - 2025-03-14
|
14
37
|
|
15
38
|
### Fixed
|
data/ecoportal-api-v2.gemspec
CHANGED
@@ -33,7 +33,7 @@ Gem::Specification.new do |spec|
|
|
33
33
|
spec.add_development_dependency 'rubocop-rake', '~> 0'
|
34
34
|
spec.add_development_dependency 'yard', '~> 0.9'
|
35
35
|
|
36
|
-
spec.add_dependency 'ecoportal-api', '~> 0.10', '>= 0.10.
|
36
|
+
spec.add_dependency 'ecoportal-api', '~> 0.10', '>= 0.10.10'
|
37
37
|
spec.add_dependency 'mime-types', '~> 3.5', '>= 3.5.2'
|
38
38
|
end
|
39
39
|
|
@@ -128,7 +128,7 @@ module Ecoportal
|
|
128
128
|
# Think if would be possible to join them somehow.
|
129
129
|
def inheritable_class_vars(*vars)
|
130
130
|
@inheritable_class_vars ||= [:inheritable_class_vars]
|
131
|
-
@inheritable_class_vars
|
131
|
+
@inheritable_class_vars |= vars
|
132
132
|
end
|
133
133
|
|
134
134
|
# Builds the attr_reader and attr_writer of `attrs` and registers the associated instance variable as inheritable.
|
@@ -140,22 +140,57 @@ module Ecoportal
|
|
140
140
|
end # end
|
141
141
|
DEF_CLSS_ATTR
|
142
142
|
end
|
143
|
+
|
143
144
|
inheritable_class_vars(*attrs)
|
144
145
|
end
|
145
146
|
|
147
|
+
private
|
148
|
+
|
146
149
|
# This callback method is called whenever a subclass of the current class is created.
|
147
|
-
# @note
|
148
|
-
#
|
149
|
-
# -
|
150
|
-
# -
|
151
|
-
# -
|
150
|
+
# @note Mutating methods would reflect the changes on other classes as well, for this
|
151
|
+
# reason:
|
152
|
+
# - Immutable objects are copied as they are (i.e. `Symbol`)
|
153
|
+
# - Enumerables are deep dupped.
|
154
|
+
# - Mutable objects, such as `String` or `Date` are frozen (`freeze`). This
|
155
|
+
# might be changed later on and just dup them.
|
152
156
|
def inherited(subclass)
|
153
157
|
super
|
154
158
|
|
155
159
|
inheritable_class_vars.each do |var|
|
156
160
|
instance_var = instance_variable_name(var)
|
157
161
|
value = instance_variable_get(instance_var)
|
158
|
-
subclass.instance_variable_set(
|
162
|
+
subclass.instance_variable_set(
|
163
|
+
instance_var,
|
164
|
+
freeze_or_dup(value)
|
165
|
+
)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def freeze_or_dup(value)
|
170
|
+
case value
|
171
|
+
when FalseClass, TrueClass, Symbol, NilClass, Numeric
|
172
|
+
value
|
173
|
+
when Date, Time, String, Range
|
174
|
+
value.freeze
|
175
|
+
when Enumerable
|
176
|
+
case value
|
177
|
+
when Array
|
178
|
+
value.map { |elem| freeze_or_dup(elem) }
|
179
|
+
when Hash
|
180
|
+
value.each.with_object({}) do |(key, val), out|
|
181
|
+
out[key] = freeze_or_dup(val)
|
182
|
+
end
|
183
|
+
else
|
184
|
+
return value.dup if respond_to?(:dup)
|
185
|
+
return value.clone if respond_to?(:clone)
|
186
|
+
|
187
|
+
value
|
188
|
+
end
|
189
|
+
else
|
190
|
+
return value.dup if respond_to?(:dup)
|
191
|
+
return value.clone if respond_to?(:clone)
|
192
|
+
|
193
|
+
value
|
159
194
|
end
|
160
195
|
end
|
161
196
|
end
|
@@ -6,7 +6,8 @@ module Ecoportal
|
|
6
6
|
class Client < Ecoportal::API::Common::Client
|
7
7
|
attr_accessor :logger
|
8
8
|
|
9
|
-
# @note the `api_key` will be automatically added as parameter
|
9
|
+
# @note the `api_key` will be automatically added as parameter
|
10
|
+
# `X-ECOPORTAL-API-KEY` in the header of the http requests.
|
10
11
|
def initialize(
|
11
12
|
api_key:,
|
12
13
|
version: 'v2',
|
@@ -25,9 +25,8 @@ module Ecoportal
|
|
25
25
|
# - This method would have been better called `_doc_pos` :)
|
26
26
|
# @note this method shouldn't be protected nor private. See DoubleModel#_rooted_doc_key
|
27
27
|
def _rooted_doc_key(value)
|
28
|
-
fetchable_position = value.is_a?(Hash) || value.is_a?(Content::DoubleModel)
|
29
28
|
#print "*(#{value.class})"
|
30
|
-
return super unless fetchable_position
|
29
|
+
return super unless fetchable_position?(value)
|
31
30
|
|
32
31
|
if (id = get_key(value))
|
33
32
|
# fetch position
|
@@ -37,9 +36,16 @@ module Ecoportal
|
|
37
36
|
raise UnlinkedModel, "Can't find child: #{show_str}"
|
38
37
|
end
|
39
38
|
end
|
39
|
+
alias_method :_doc_pos, :_rooted_doc_key
|
40
40
|
|
41
41
|
private
|
42
42
|
|
43
|
+
def fetchable_position?(value)
|
44
|
+
return true if value.is_a?(Hash)
|
45
|
+
|
46
|
+
value.is_a?(Content::DoubleModel)
|
47
|
+
end
|
48
|
+
|
43
49
|
def cant_find_child_explanation(value)
|
44
50
|
case value
|
45
51
|
when Hash
|
@@ -53,12 +59,6 @@ module Ecoportal
|
|
53
59
|
end
|
54
60
|
end
|
55
61
|
end
|
56
|
-
|
57
|
-
# INSTANCE METHODS
|
58
|
-
|
59
|
-
def _doc_pos(value)
|
60
|
-
_rooted_doc_key(value)
|
61
|
-
end
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require_relative 'doc_mutation/delete'
|
2
|
+
require_relative 'doc_mutation/position'
|
3
|
+
require_relative 'doc_mutation/upsert'
|
4
4
|
|
5
5
|
module Ecoportal
|
6
6
|
module API
|
@@ -1,9 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
require_relative 'model/items'
|
2
|
+
require_relative 'model/iterable'
|
3
|
+
require_relative 'model/numeric_key'
|
4
|
+
require_relative 'model/cache'
|
5
|
+
require_relative 'model/var_tracking'
|
6
|
+
require_relative 'model/lookup'
|
7
7
|
|
8
8
|
module Ecoportal
|
9
9
|
module API
|
@@ -1,6 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require_relative 'modifiers/items_key'
|
2
|
+
require_relative 'modifiers/items_klass'
|
3
|
+
require_relative 'modifiers/items_order'
|
4
4
|
|
5
5
|
module Ecoportal
|
6
6
|
module API
|
@@ -1,6 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require_relative 'mutation/delete'
|
2
|
+
require_relative 'mutation/upsert'
|
3
|
+
require_relative 'mutation/clear'
|
4
4
|
|
5
5
|
module Ecoportal
|
6
6
|
module API
|
@@ -6,11 +6,11 @@ module Ecoportal
|
|
6
6
|
# @note to be able to refer to the correct element of the Collection,
|
7
7
|
# it is required that those elements have a unique `key` that allows to identify them
|
8
8
|
class CollectionModel < Content::DoubleModel
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
require_relative 'collection_model/modifiers'
|
10
|
+
require_relative 'collection_model/doc'
|
11
|
+
require_relative 'collection_model/model'
|
12
|
+
require_relative 'collection_model/doc_mutation'
|
13
|
+
require_relative 'collection_model/mutation'
|
14
14
|
|
15
15
|
include Modifiers
|
16
16
|
include Doc
|
data/lib/ecoportal/api/common/content/double_model/attributable/nesting/cascaded_callback.rb
CHANGED
@@ -1,104 +1,209 @@
|
|
1
|
-
module Ecoportal
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
1
|
+
module Ecoportal::API::Common::Content::DoubleModel::Attributable::Nesting
|
2
|
+
module CascadedCallback
|
3
|
+
class << self
|
4
|
+
def included(base)
|
5
|
+
super
|
6
|
+
|
7
|
+
base.extend Ecoportal::API::Common::Content::ClassHelpers
|
8
|
+
|
9
|
+
base.extend ClassMethods
|
10
|
+
base.inheritable_class_vars :_cascaded_attributes
|
11
|
+
base.send :include, InstanceMethods
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
# @note it also tracks `doc_key` as cascaded attribute on
|
17
|
+
# child classes.
|
18
|
+
def _cascaded_attribute!(meth, doc_key = meth, inherited: false)
|
19
|
+
meth = meth.to_sym
|
20
|
+
doc_key = doc_key.to_s
|
21
|
+
|
22
|
+
dont_override = _cascaded_attributes.key?(meth) && inherited
|
23
|
+
return _cascaded_attributes[meth] if dont_override
|
24
|
+
|
25
|
+
_cascaded_attributes[meth] = doc_key
|
26
|
+
|
27
|
+
subclasses.each do |subclass|
|
28
|
+
subclass._cascaded_attribute!(meth, doc_key, inherited: true)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def _cascaded_attributes
|
33
|
+
@_cascaded_attributes ||={}
|
34
|
+
end
|
35
|
+
|
36
|
+
def _cascaded_methods
|
37
|
+
_cascaded_attributes.keys
|
38
|
+
end
|
39
|
+
|
40
|
+
def _cascaded_doc_keys
|
41
|
+
_cascaded_attributes.values.uniq
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# INSTANCE METHODS
|
46
|
+
|
47
|
+
# We offer helpers to implement cascaded callbacks to nested objects
|
48
|
+
# i.e. `#as_update` or `#dirty?`
|
49
|
+
# @note this happens at instance level (not tracked at class level)
|
50
|
+
module InstanceMethods
|
51
|
+
# Method to go through all the embedded properties recursively.
|
52
|
+
# @note **Be aware** that
|
53
|
+
# 1. It does NOT natively discard `root?` objects. You will need to
|
54
|
+
# explicitly do this in the block callback.
|
55
|
+
# 2. If `method` calls in turn to `cascaded_callback`, to prevent
|
56
|
+
# **double-recursion** you MUST use `recurs: false`.
|
57
|
+
# The **problem** with this approach is that **`key_path`**
|
58
|
+
# from the original object that called `cascaded_callback`
|
59
|
+
# **is lost**.
|
60
|
+
# For which you should probably rather use `cascaded_reduce`.
|
61
|
+
# 3. It already does a first call on `self.method`, might it respond to.
|
62
|
+
# And it will not `yield` in this first call.
|
63
|
+
# @note the `cascaded_callback` will end were:
|
64
|
+
# 1. The current object does NOT respond to `method`.
|
65
|
+
# 2. The current object does NOT have nested properties. So where
|
66
|
+
# the object does not have any `_cascaded_attributes`.
|
67
|
+
# @yield [result, value, key_path, object] block to accumulate result.
|
68
|
+
# The block is yielded for the main (root) object, as well as
|
69
|
+
# per each one of its `_cascaded_attributes` (so nested properties).
|
70
|
+
# @yieldparam result [Hash, Variant] the accumulated value of calling `method`
|
71
|
+
# across all nested models from root to this point (`object`).
|
72
|
+
# @yieldparam value [Variant] the value of calling `method` on `object`.
|
73
|
+
# @yieldparam key_path [Array<String>] the `Hash` model `path` of **keys** to get
|
74
|
+
# from root to `objecct`. It is important to **note** that an
|
75
|
+
# **empty path** means we are on the top object from where this method
|
76
|
+
# was callled.
|
77
|
+
# @yieldparam object [DoubleModel] the current object.
|
78
|
+
# @yieldreturn [Variant] the accumulated result or the current iteration.
|
79
|
+
# @param value [Variant] the intial value of the cascaded callback.
|
80
|
+
# - It can also be the accumulated value of cascaded callbacks from
|
81
|
+
# up to the model hierarchy to the current instance.
|
82
|
+
# @param method [Symbol] to be called on `self` and all nested models.
|
83
|
+
# Private methods are in scope.
|
84
|
+
# @param args [Array<>] arguments for `method`.
|
85
|
+
# @param kargs [Hash<Symbol,Variant>] named arguments for `method`.
|
86
|
+
# @param path [Array<String>] the `Hash` model `path` of **keys** to get
|
87
|
+
# from root to `self`.
|
88
|
+
# @param recurs [Boolean] whether it should go beyound the first level.
|
89
|
+
# This is specially useful to set to `false` when `method` will,
|
90
|
+
# in turn, call `cascaded_callback`, as that would already have
|
91
|
+
# a recursion. Noo need to decrease performance with a double recursion,
|
92
|
+
# in such a case.
|
93
|
+
# @return [Variant] the result of cascaded calling `method` through all the
|
94
|
+
# the nested models.
|
95
|
+
def cascaded_callback(
|
96
|
+
value = nil,
|
97
|
+
method:,
|
98
|
+
args: [],
|
99
|
+
kargs: {},
|
100
|
+
path: [],
|
101
|
+
recurs: true,
|
102
|
+
&block
|
103
|
+
)
|
104
|
+
method = method.to_sym
|
105
|
+
return value unless respond_to?(method, true)
|
106
|
+
|
107
|
+
value =
|
108
|
+
if path.empty?
|
109
|
+
# Don't yield on the first call
|
110
|
+
send(method, *args, **kargs)
|
111
|
+
else
|
112
|
+
yield(
|
113
|
+
value,
|
114
|
+
send(method, *args, **kargs),
|
115
|
+
path,
|
116
|
+
self
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
return value unless respond_to?(:_cascaded_attributes)
|
121
|
+
|
122
|
+
_cascaded_attributes.reduce(value) do |val, (attribute, obj_k)|
|
123
|
+
next val unless (obj = send(attribute))
|
124
|
+
next val unless obj.respond_to(method, true)
|
125
|
+
|
126
|
+
obj_path = path.dup.push(obj_k)
|
127
|
+
# next val if obj_path.empty?
|
128
|
+
|
129
|
+
unless obj.respond_to?(:cascaded_callback)
|
130
|
+
next yield(
|
131
|
+
val,
|
132
|
+
obj.send(method, *args, **kargs),
|
133
|
+
obj_path,
|
134
|
+
obj
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
138
|
+
next val unless recurs
|
139
|
+
|
140
|
+
obj.cascaded_callback(
|
141
|
+
val,
|
142
|
+
method: method,
|
143
|
+
args: args,
|
144
|
+
kargs: kargs,
|
145
|
+
path: obj_path,
|
146
|
+
recurs: recurs,
|
147
|
+
&block
|
148
|
+
)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Trace = Struct.new(:subject, :nested_attrs, :obj_key_path)
|
153
|
+
def cascaded_reduce(init = nil, recurs: false, trace: nil, &block)
|
154
|
+
trace ||= {}
|
155
|
+
trace = _cascaded_attributes_trace(recurs: recurs) if trace.empty?
|
156
|
+
|
157
|
+
return init if trace.empty?
|
158
|
+
|
159
|
+
params = %i[subject key key_path attributes]
|
160
|
+
subject, key, key_path, attributes = trace.values_at(*params)
|
161
|
+
|
162
|
+
value = yield(init, subject, key, key_path, trace)
|
163
|
+
return value if attributes.nil? || attributes.empty?
|
164
|
+
|
165
|
+
attributes.reduce(value) do |mem, (_attr, subtrace)|
|
166
|
+
cascaded_reduce(mem, recurs: recurs, trace: subtrace, &block)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
def _cascaded_attributes_trace(trace = nil, recurs: false, key_path: [])
|
173
|
+
{
|
174
|
+
subject: self,
|
175
|
+
attribute: nil,
|
176
|
+
key: nil,
|
177
|
+
key_path: key_path,
|
178
|
+
nested_attrs: _cascaded_attributes.keys,
|
179
|
+
attributes: {}
|
180
|
+
}.merge(trace || {}).tap do |out_trace|
|
181
|
+
_cascaded_attributes.each.with_object(out_trace) do |out, (attribute, obj_k)|
|
182
|
+
next unless (obj = send(attribute))
|
183
|
+
|
184
|
+
obj_k_path = key_path.dup.push(obj_k)
|
185
|
+
|
186
|
+
sub_trace = out[:attributes][attribute] = {
|
187
|
+
subject: obj,
|
188
|
+
attribute: attribute,
|
189
|
+
key: obj_k,
|
190
|
+
key_path: obj_k_path
|
191
|
+
}
|
192
|
+
|
193
|
+
next unless recurs
|
194
|
+
|
195
|
+
_cascaded_attributes_trace(sub_trace, recurs: true, key_path: obj_k_path)
|
99
196
|
end
|
100
197
|
end
|
101
198
|
end
|
199
|
+
|
200
|
+
def _cascaded_attribute!(...)
|
201
|
+
self.class._cascaded_attribute!(...)
|
202
|
+
end
|
203
|
+
|
204
|
+
def _cascaded_attributes
|
205
|
+
self.class._cascaded_attributes
|
206
|
+
end
|
102
207
|
end
|
103
208
|
end
|
104
209
|
end
|