ecoportal-api-v2 2.0.12 → 2.0.14

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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/CHANGELOG.md +29 -3
  4. data/ecoportal-api-v2.gemspec +1 -1
  5. data/lib/ecoportal/api/common/content/array_model.rb +20 -3
  6. data/lib/ecoportal/api/common/content/class_helpers.rb +4 -2
  7. data/lib/ecoportal/api/common/content/client.rb +12 -6
  8. data/lib/ecoportal/api/common/content/collection_model/doc/items.rb +33 -0
  9. data/lib/ecoportal/api/common/content/collection_model/doc/rooted_key.rb +68 -0
  10. data/lib/ecoportal/api/common/content/collection_model/doc.rb +25 -0
  11. data/lib/ecoportal/api/common/content/collection_model/doc_mutation/delete.rb +33 -0
  12. data/lib/ecoportal/api/common/content/collection_model/doc_mutation/position.rb +42 -0
  13. data/lib/ecoportal/api/common/content/collection_model/doc_mutation/upsert.rb +45 -0
  14. data/lib/ecoportal/api/common/content/collection_model/doc_mutation.rb +27 -0
  15. data/lib/ecoportal/api/common/content/collection_model/model/cache.rb +44 -0
  16. data/lib/ecoportal/api/common/content/collection_model/model/items.rb +43 -0
  17. data/lib/ecoportal/api/common/content/collection_model/model/iterable.rb +44 -0
  18. data/lib/ecoportal/api/common/content/collection_model/model/lookup.rb +45 -0
  19. data/lib/ecoportal/api/common/content/collection_model/model/numeric_key.rb +40 -0
  20. data/lib/ecoportal/api/common/content/collection_model/model/var_tracking.rb +50 -0
  21. data/lib/ecoportal/api/common/content/collection_model/model.rb +33 -0
  22. data/lib/ecoportal/api/common/content/collection_model/modifiers/items_key.rb +57 -0
  23. data/lib/ecoportal/api/common/content/collection_model/modifiers/items_klass.rb +144 -0
  24. data/lib/ecoportal/api/common/content/collection_model/modifiers/items_order.rb +38 -0
  25. data/lib/ecoportal/api/common/content/collection_model/modifiers.rb +27 -0
  26. data/lib/ecoportal/api/common/content/collection_model/mutation/clear.rb +30 -0
  27. data/lib/ecoportal/api/common/content/collection_model/mutation/delete.rb +42 -0
  28. data/lib/ecoportal/api/common/content/collection_model/mutation/upsert.rb +56 -0
  29. data/lib/ecoportal/api/common/content/collection_model/mutation.rb +27 -0
  30. data/lib/ecoportal/api/common/content/collection_model.rb +19 -351
  31. data/lib/ecoportal/api/common/content/doc_helpers.rb +18 -16
  32. data/lib/ecoportal/api/common/content/double_model/attributable/base.rb +23 -0
  33. data/lib/ecoportal/api/common/content/double_model/attributable/enforce.rb +62 -0
  34. data/lib/ecoportal/api/common/content/double_model/attributable/nesting/cascaded_callback.rb +104 -0
  35. data/lib/ecoportal/api/common/content/double_model/attributable/nesting/embeddable.rb +76 -0
  36. data/lib/ecoportal/api/common/content/double_model/attributable/nesting/keyable.rb +119 -0
  37. data/lib/ecoportal/api/common/content/double_model/attributable/nesting.rb +136 -0
  38. data/lib/ecoportal/api/common/content/double_model/attributable/passthrough.rb +70 -0
  39. data/lib/ecoportal/api/common/content/double_model/attributable/simple.rb +48 -0
  40. data/lib/ecoportal/api/common/content/double_model/attributable.rb +30 -0
  41. data/lib/ecoportal/api/common/content/double_model/base.rb +29 -0
  42. data/lib/ecoportal/api/common/content/double_model/diffable_model.rb +43 -0
  43. data/lib/ecoportal/api/common/content/double_model/double_doc/base.rb +23 -0
  44. data/lib/ecoportal/api/common/content/double_model/double_doc/linkable_doc.rb +87 -0
  45. data/lib/ecoportal/api/common/content/double_model/double_doc/replaceable_doc.rb +61 -0
  46. data/lib/ecoportal/api/common/content/double_model/double_doc/reset_consolidate.rb +54 -0
  47. data/lib/ecoportal/api/common/content/double_model/double_doc/rooted_key.rb +49 -0
  48. data/lib/ecoportal/api/common/content/double_model/double_doc.rb +31 -0
  49. data/lib/ecoportal/api/common/content/double_model/hash_helpers.rb +40 -0
  50. data/lib/ecoportal/api/common/content/double_model/modifiers/read_only_able.rb +73 -0
  51. data/lib/ecoportal/api/common/content/double_model/modifiers/rootable.rb +64 -0
  52. data/lib/ecoportal/api/common/content/double_model/modifiers.rb +24 -0
  53. data/lib/ecoportal/api/common/content/double_model/parented.rb +22 -0
  54. data/lib/ecoportal/api/common/content/double_model/var_tracking.rb +45 -0
  55. data/lib/ecoportal/api/common/content/double_model.rb +28 -486
  56. data/lib/ecoportal/api/common/content/hash_diff_patch.rb +2 -1
  57. data/lib/ecoportal/api/common/content/includer.rb +16 -0
  58. data/lib/ecoportal/api/common/content/model_helpers.rb +14 -16
  59. data/lib/ecoportal/api/common/content.rb +1 -0
  60. data/lib/ecoportal/api/v2/page/component.rb +46 -46
  61. data/lib/ecoportal/api/v2/page/components.rb +2 -2
  62. data/lib/ecoportal/api/v2/page.rb +14 -14
  63. data/lib/ecoportal/api/v2/pages/page_stage/task.rb +2 -2
  64. data/lib/ecoportal/api/v2/pages/page_stage/tasks.rb +3 -3
  65. data/lib/ecoportal/api/v2/pages/page_stage.rb +8 -8
  66. data/lib/ecoportal/api/v2/pages/stages.rb +2 -2
  67. data/lib/ecoportal/api/v2/pages.rb +15 -15
  68. data/lib/ecoportal/api/v2/registers.rb +20 -19
  69. data/lib/ecoportal/api/v2/s3/files/batch_upload.rb +1 -0
  70. data/lib/ecoportal/api/v2/s3/files/poll.rb +5 -5
  71. data/lib/ecoportal/api/v2/s3/files/poll_status.rb +3 -3
  72. data/lib/ecoportal/api/v2/s3/files.rb +6 -6
  73. data/lib/ecoportal/api/v2/s3.rb +5 -5
  74. data/lib/ecoportal/api/v2.rb +18 -8
  75. data/lib/ecoportal/api/v2_version.rb +1 -1
  76. metadata +50 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 933cb180c2a1d901d3ec065c20527d8d9ee30db24634c20ae3fa2867042311da
4
- data.tar.gz: 5c7bf8198ff1ac64b776538c83f80abde8fba0cf6aa6a9f729444548f6b72936
3
+ metadata.gz: 426bf1825b51e8170e8c9cad831c19777758f195c62b07d8ba1dde395936ad61
4
+ data.tar.gz: 3141541feb1e5f108890de72a5bd6d6eddcb427149f009ba3de773ff68bc622e
5
5
  SHA512:
6
- metadata.gz: c47162752062ca85c5a215ce249c3dee0b702d5b11cf095d0f9d9f68bd178af1e9edb4a3bc5c42792133761c6b036cbe2b8a509b4306327a0c72ce0d77a647bc
7
- data.tar.gz: 0b2b8d9ac691e3ba75d599adb23012d01600be0d2888bb6a4f1548c3686d8ccac0a95d1aff5e586b241a185b917cd0f2bff05f82b907670148cf18e372d0e81a
6
+ metadata.gz: ea725f7615e8f4efb85ed66a8fb15b0b8af0665a9926272390a191cc95e0e021dbec57a203ce22be09fbad56ab756d05500dda24252c0b43889ef54158161808
7
+ data.tar.gz: 5dacfb6320f60555064f60ef144effb8a3b3ded3586a319344a65893b32a5cf1c2138739927fbe00ebfb92eeedb3416a1ce16723492de4bdb24a592c59ab7e46
data/.gitignore CHANGED
@@ -9,6 +9,9 @@ Gemfile.lock
9
9
  /tmp/
10
10
  /pkg/
11
11
 
12
+ /.vscode
13
+ .solargraph.yml
14
+
12
15
  # docs
13
16
  /.yardoc
14
17
  /_yardoc/
data/CHANGELOG.md CHANGED
@@ -2,16 +2,42 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
- ## [2.0.14] - 2024-11-xx
5
+ ## [2.0.15] - 2024-12-xx
6
6
 
7
7
  ### Added
8
8
 
9
9
  ### Changed
10
10
 
11
- - upgrade `ecoportal-api` core gem
12
-
13
11
  ### Fixed
14
12
 
13
+ ## [2.0.14] - 2025-02-23
14
+
15
+ ### Added
16
+
17
+ - `Ecoportal::API::Common::DoubleModel::root!` method
18
+ - To stop the propagation of `read_only`
19
+ - To define this model as top/root in the hiearchy that hangs from it
20
+ - `Ecoportal::API::Common::ArrayModel`
21
+ - **Added**
22
+ - `#added_items` (alias `#added`) to know which elements where added.
23
+ - `#deleted_items` (alias `#deleted`) to know which elements where removed.
24
+ - **Changed**
25
+ - `#push!` (alias `#push`) to accept variadic arguments.
26
+ - `read_only` name arg to `Ecoportal::API::Common::DoubleModel::embeds_one`
27
+ - `Ecoportal:API::Common::DoubleModel::Attributable::Nesting::CascadedCallback`
28
+ - A helper to track all the nested method/doc_key pairs througout parent and descendant classes thereof.
29
+ - This allows for cascaded callbacks to implement certain methods.
30
+
31
+ ### Changed
32
+
33
+ - Upgrade `ecoportal-api` core gem.
34
+ - Code tidy up.
35
+ - **MAJOR REFACTOR**:
36
+ - Decoupled the code of `DoubleModel` into modular concerns.
37
+ - Decoupled the code of `CollectionModel` into modular concerns.
38
+ - Renamed some internal names to better reflect their function.
39
+ - This major refactor aims to be able to cascade `as_update`, provided that it calls `as_update` on each nested DoubleModel, ensuring that `as_update` can be redefined or fine tunned (rather than generating the diff out of the top model's doc).
40
+
15
41
  ## [2.0.12] - 2024-11-21
16
42
 
17
43
  ### 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.7'
36
+ spec.add_dependency 'ecoportal-api', '~> 0.10', '>= 0.10.8'
37
37
  spec.add_dependency 'mime-types', '~> 3.5', '>= 3.5.2'
38
38
  end
39
39
 
@@ -25,6 +25,7 @@ module Ecoportal
25
25
  def same_type?(a, b) # rubocop:disable Naming/MethodParameterName
26
26
  msg = "To use this comparison both objects should be `ArrayModel`"
27
27
  raise msg unless a.is_a?(ArrayModel) && b.is_a?(ArrayModel)
28
+
28
29
  (a.order_matters? == b.order_matters?) && (a.uniq? == b.uniq?)
29
30
  end
30
31
  end
@@ -32,7 +33,7 @@ module Ecoportal
32
33
  inheritable_class_vars :order_matteres, :uniq
33
34
 
34
35
  def initialize(doc = [], parent: self, key: nil, read_only: self.class.read_only?)
35
- super(doc, parent: parent, key: key, read_only: read_only)
36
+ super
36
37
  end
37
38
 
38
39
  def order_matters?
@@ -143,20 +144,36 @@ module Ecoportal
143
144
  value.all? {|v| _items.include?(v)}
144
145
  end
145
146
 
147
+ # @return [Array<Date>, Array<String>, Array<Number] the elements that have
148
+ # been added
149
+ def added_items
150
+ (doc || []) - (original_doc || [])
151
+ end
152
+ alias_method :added, :added_items
153
+
154
+ # @return [Array<Date>, Array<String>, Array<Number] the elements that have
155
+ # been deleted
156
+ def deleted_items
157
+ (original_doc || []) - (doc || [])
158
+ end
159
+ alias_method :deleted, :deleted_items
160
+
146
161
  # Adds an element to the subjacent `Array`
147
162
  # @note if the class variable `uniq` is `true`, it skips duplicates
148
163
  def <<(value)
149
164
  _items.concat(into_a(value)).tap do |doc|
150
165
  doc.uniq! if uniq?
151
166
  end
167
+
152
168
  on_change
153
169
  self
154
170
  end
155
171
 
156
172
  # @see #<<
157
- def push!(value)
158
- self << value
173
+ def push!(*values)
174
+ self << values
159
175
  end
176
+ alias_method :push, :push!
160
177
 
161
178
  # @see #<<
162
179
  # @note same as #push! but for multiple elements
@@ -5,7 +5,7 @@ module Ecoportal
5
5
  module Content
6
6
  module ClassHelpers
7
7
  include Ecoportal::API::Common::BaseClass
8
- NOT_USED = "no_used!".freeze
8
+ NOT_USED = 'no_used!'.freeze
9
9
 
10
10
  # Class resolver
11
11
  # @note it caches the resolved `klass`es
@@ -124,7 +124,8 @@ module Ecoportal
124
124
  # - subclasses will inherit the value as is at that moment
125
125
  # - any change afterwards will be only on the specific class (in line with class instance variables)
126
126
  # - adapted from https://stackoverflow.com/a/10729812/4352306
127
- # TODO: this separates the logic of the method to the instance var. Think if would be possible to join them somehow.
127
+ # @todo this separates the logic of the method to the instance var.
128
+ # Think if would be possible to join them somehow.
128
129
  def inheritable_class_vars(*vars)
129
130
  @inheritable_class_vars ||= [:inheritable_class_vars]
130
131
  @inheritable_class_vars += vars
@@ -150,6 +151,7 @@ module Ecoportal
150
151
  # - therefore, `freeze` will be called on the values that are inherited.
151
152
  def inherited(subclass)
152
153
  super
154
+
153
155
  inheritable_class_vars.each do |var|
154
156
  instance_var = instance_variable_name(var)
155
157
  value = instance_variable_get(instance_var)
@@ -7,11 +7,16 @@ module Ecoportal
7
7
  attr_accessor :logger
8
8
 
9
9
  # @note the `api_key` will be automatically added as parameter `X-ECOPORTAL-API-KEY` in the header of the http requests.
10
- def initialize(api_key:, version: "v2", host: "live.ecoportal.com", logger: nil)
11
- super(api_key: api_key, version: "v2", host: host, logger: logger)
10
+ def initialize(
11
+ api_key:,
12
+ version: 'v2',
13
+ host: 'live.ecoportal.com',
14
+ logger: nil
15
+ )
16
+ super
12
17
  end
13
18
 
14
- def delete(path)
19
+ def delete(_path)
15
20
  raise "DELETE operation does not have integration for api #{@version}"
16
21
  end
17
22
 
@@ -19,7 +24,7 @@ module Ecoportal
19
24
  # @param params [Hash] the header paramters of the http request (not including the api key).
20
25
  # @option params [String] :template_id original template.
21
26
  def post(path, data:, params: {})
22
- instrument("POST", path, params) do
27
+ instrument('POST', path, params) do
23
28
  request do |http|
24
29
  http.post(url_for(path), json: data, params: params)
25
30
  end
@@ -30,9 +35,10 @@ module Ecoportal
30
35
  # @note It configures HTTP so it only allows body data in json format.
31
36
  # @return [HTTP] HTTP object.
32
37
  def base_request
33
- @base_request ||= HTTP.headers("X-ECOPORTAL-API-KEY" => @api_key).accept(:json)
38
+ @base_request ||= HTTP.headers(
39
+ 'X-ECOPORTAL-API-KEY' => @api_key
40
+ ).accept(:json)
34
41
  end
35
-
36
42
  end
37
43
  end
38
44
  end
@@ -0,0 +1,33 @@
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ module Content
5
+ class CollectionModel
6
+ module Doc
7
+ module Items
8
+ protected
9
+
10
+ def _doc_items
11
+ replace_doc([]) unless doc.is_a?(Array)
12
+ doc
13
+ end
14
+
15
+ private
16
+
17
+ def to_ini_doc(value)
18
+ case value
19
+ when Array
20
+ value
21
+ when Enumerable
22
+ value.to_a
23
+ else
24
+ []
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,68 @@
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ module Content
5
+ class CollectionModel
6
+ module Doc
7
+ module RootedKey
8
+ class << self
9
+ include Content::Includer
10
+
11
+ def included(base)
12
+ super
13
+ # to suport call to super:
14
+ include_missing(base, DoubleModel::DoubleDoc::RootedKey)
15
+ include_missing(base, Doc::Items)
16
+ include_missing(base, CollectionModel::Modifiers::ItemsKey)
17
+ base.send(:include, InstanceMethods)
18
+ end
19
+ end
20
+
21
+ module InstanceMethods
22
+ # Transforms `value` into the actual `key` to access the object in the doc `Array`
23
+ # @note
24
+ # - The name of the method is after the paren't class method
25
+ # - This method would have been better called `_doc_pos` :)
26
+ # @note this method shouldn't be protected nor private. See DoubleModel#_rooted_doc_key
27
+ def _rooted_doc_key(value)
28
+ fetchable_position = value.is_a?(Hash) || value.is_a?(Content::DoubleModel)
29
+ #print "*(#{value.class})"
30
+ return super unless fetchable_position
31
+
32
+ if (id = get_key(value))
33
+ # fetch position
34
+ _doc_items.index {|item| get_key(item) == id}
35
+ else
36
+ show_str = cant_find_child_explanation(value)
37
+ raise UnlinkedModel, "Can't find child: #{show_str}"
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def cant_find_child_explanation(value)
44
+ case value
45
+ when Hash
46
+ value.pretty_inspect
47
+ when Content::DoubleModel
48
+ msg = "#{value} with key: #{value.class.key} "
49
+ msg << "(items_key: #{items_key})"
50
+ msg
51
+ else
52
+ value
53
+ end
54
+ end
55
+ end
56
+
57
+ # INSTANCE METHODS
58
+
59
+ def _doc_pos(value)
60
+ _rooted_doc_key(value)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,25 @@
1
+ require 'ecoportal/api/common/content/collection_model/doc/items'
2
+ require 'ecoportal/api/common/content/collection_model/doc/rooted_key'
3
+
4
+ module Ecoportal
5
+ module API
6
+ module Common
7
+ module Content
8
+ class CollectionModel
9
+ module Doc
10
+ class << self
11
+ include Content::Includer
12
+
13
+ def included(base)
14
+ super
15
+
16
+ include_missing(base, Items)
17
+ include_missing(base, RootedKey)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,33 @@
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ module Content
5
+ class CollectionModel
6
+ module DocMutation
7
+ module Delete
8
+ class << self
9
+ def included(base)
10
+ super
11
+ base.send(:include, CollectionModel::Doc::Items)
12
+ base.send(:include, CollectionModel::Doc::RootedKey)
13
+ end
14
+ end
15
+
16
+ # INSTANCE METHODS
17
+
18
+ private
19
+
20
+ # Deletes `value` from `doc` (here referred as `_doc_items`)
21
+ # @return [Object] the element deleted from `doc`
22
+ def _doc_delete(value)
23
+ return unless (current_pos = _rooted_doc_key(value))
24
+
25
+ _doc_items.delete_at(current_pos)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,42 @@
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ module Content
5
+ class CollectionModel
6
+ module DocMutation
7
+ module Position
8
+ class << self
9
+ def included(base)
10
+ super
11
+ base.extend Content::ClassHelpers
12
+ base.send(:include, CollectionModel::Doc::RootedKey)
13
+ base.send(:include, CollectionModel::Model::Lookup)
14
+ end
15
+ end
16
+
17
+ # INSTANCE METHODS
18
+
19
+ private
20
+
21
+ def scope_position(pos: NOT_USED, before: NOT_USED, after: NOT_USED)
22
+ if used_param?(pos)
23
+ return unless (elem = self[pos])
24
+
25
+ _rooted_doc_key(elem) - 1
26
+ elsif used_param?(before)
27
+ return unless (elem = self[before])
28
+
29
+ _rooted_doc_key(elem) - 1
30
+ elsif used_param?(after)
31
+ return unless (elem = self[after])
32
+
33
+ _rooted_doc_key(elem)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,45 @@
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ module Content
5
+ class CollectionModel
6
+ module DocMutation
7
+ module Upsert
8
+ class << self
9
+ def included(base)
10
+ super
11
+ base.send(:include, CollectionModel::Doc::RootedKey)
12
+ base.send(:include, DocMutation::Position)
13
+ end
14
+ end
15
+
16
+ # INSTANCE METHODS
17
+
18
+ private
19
+
20
+ def _doc_upsert(value, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
21
+ elem = self[value]
22
+ current_pos = nil
23
+ current_pos = _rooted_doc_key(elem) if elem
24
+
25
+ pos = scope_position(pos: pos, before: before, after: after)
26
+ pos ||= current_pos
27
+
28
+ if current_pos && pos
29
+ _doc_items.delete_at(current_pos)
30
+ pos -= 1 unless pos <= current_pos
31
+ end
32
+
33
+ pos = _doc_items.length unless pos && pos < _doc_items.length
34
+
35
+ pos.tap do |_i|
36
+ _doc_items.insert(pos, value)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,27 @@
1
+ require 'ecoportal/api/common/content/collection_model/doc_mutation/delete'
2
+ require 'ecoportal/api/common/content/collection_model/doc_mutation/position'
3
+ require 'ecoportal/api/common/content/collection_model/doc_mutation/upsert'
4
+
5
+ module Ecoportal
6
+ module API
7
+ module Common
8
+ module Content
9
+ class CollectionModel
10
+ module DocMutation
11
+ class << self
12
+ include Content::Includer
13
+
14
+ def included(base)
15
+ super
16
+
17
+ include_missing(base, Delete)
18
+ include_missing(base, Position)
19
+ include_missing(base, Upsert)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,44 @@
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ module Content
5
+ class CollectionModel
6
+ module Model
7
+ module Cache
8
+ class << self
9
+ include Content::Includer
10
+
11
+ def included(base)
12
+ super
13
+
14
+ include_missing(base, DoubleModel::VarTracking)
15
+ include_missing(base, Model::Items)
16
+ end
17
+ end
18
+
19
+ # INSTANCE METHODS
20
+
21
+ protected
22
+
23
+ def on_change
24
+ @indexed = false
25
+ #variables_remove! # if ever enabled, move on_change to VarTracking
26
+ end
27
+
28
+ # @note it does not support a change of `id` on an existing item
29
+ def items_by_key
30
+ return @items_by_key if @indexed
31
+
32
+ {}.tap do |hash|
33
+ variable_set(:@items_by_key, hash)
34
+ _items.each {|item| hash[item.key] = item}
35
+ @indexed = true
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,43 @@
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ module Content
5
+ class CollectionModel
6
+ module Model
7
+ module Items
8
+ class << self
9
+ include Content::Includer
10
+
11
+ def included(base)
12
+ super
13
+
14
+ include_missing(base, DoubleModel::VarTracking)
15
+ include_missing(base, CollectionModel::Modifiers::ItemsKlass)
16
+ include_missing(base, CollectionModel::Doc::Items)
17
+ end
18
+ end
19
+
20
+ # INSTANCE METHODS
21
+
22
+ def _items
23
+ return @_items if @_items
24
+
25
+ [].tap do |elements|
26
+ # necessary in most cases:
27
+ # @todo check if add condition `unless read_only?`
28
+ variable_set(:@_items, elements)
29
+
30
+ _doc_items.each do |item_doc|
31
+ elements << new_item(item_doc)
32
+ end
33
+
34
+ @_items = elements if read_only?
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,44 @@
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ module Content
5
+ class CollectionModel
6
+ module Model
7
+ module Iterable
8
+ class << self
9
+ include Content::Includer
10
+
11
+ def included(base)
12
+ super
13
+
14
+ include_missing(base, Model::Items)
15
+ include_missing(base, Enumerable)
16
+ end
17
+ end
18
+
19
+ # INSTANCE METHODS
20
+
21
+ def each(&block)
22
+ return to_enum(:each) unless block
23
+
24
+ _items.each(&block)
25
+ end
26
+
27
+ def length
28
+ count
29
+ end
30
+
31
+ def empty?
32
+ count&.zero?
33
+ end
34
+
35
+ def present?
36
+ count&.positive?
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,45 @@
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ module Content
5
+ class CollectionModel
6
+ module Model
7
+ module Lookup
8
+ class << self
9
+ include Content::Includer
10
+
11
+ def included(base)
12
+ super
13
+
14
+ include_missing(base, Model::NumericKey)
15
+ include_missing(base, Model::Cache)
16
+ end
17
+ end
18
+
19
+ # INSTANCE METHODS
20
+
21
+ # Get an element usign the `key`.
22
+ # @param value [String, Hash, Ecoportal::API::Common::Content::DoubleModel]
23
+ # @return [Object] the `items_class` element object
24
+ def [](value)
25
+ items_by_key[get_key(value)]
26
+ end
27
+
28
+ # Checks if an element exists in the collection
29
+ # @param value [String, Hash, Ecoportal::API::Common::Content::DoubleModel]
30
+ # @return [Boolean] whether or not it is included
31
+ def include?(value)
32
+ items_by_key.key?(get_key(value))
33
+ end
34
+
35
+ # @return [Array<Object>] the `items_class` element object
36
+ def values_at(*keys)
37
+ keys.map {|key| self[key]}
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end