ecoportal-api-v2 0.8.6 → 0.8.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +73 -28
  3. data/bin/console +1 -1
  4. data/ecoportal-api-v2.gemspec +5 -5
  5. data/lib/ecoportal/api-v2.rb +2 -2
  6. data/lib/ecoportal/api/common.v2.rb +8 -0
  7. data/lib/ecoportal/api/common/content.rb +1 -0
  8. data/lib/ecoportal/api/common/content/array_model.rb +8 -6
  9. data/lib/ecoportal/api/common/content/collection_model.rb +45 -20
  10. data/lib/ecoportal/api/common/content/double_model.rb +98 -9
  11. data/lib/ecoportal/api/common/content/hash_diff_patch.rb +44 -22
  12. data/lib/ecoportal/api/common/content/model_helpers.rb +36 -0
  13. data/lib/ecoportal/api/v2/page.rb +15 -2
  14. data/lib/ecoportal/api/v2/page/component.rb +44 -10
  15. data/lib/ecoportal/api/v2/page/component/action.rb +17 -8
  16. data/lib/ecoportal/api/v2/page/component/action_field.rb +37 -2
  17. data/lib/ecoportal/api/v2/page/component/chart_field.rb +43 -5
  18. data/lib/ecoportal/api/v2/page/component/chart_field/benchmark.rb +30 -0
  19. data/lib/ecoportal/api/v2/page/component/chart_field/config.rb +23 -0
  20. data/lib/ecoportal/api/v2/page/component/chart_field/frequency.rb +3 -4
  21. data/lib/ecoportal/api/v2/page/component/chart_field/heatmap.rb +1 -3
  22. data/lib/ecoportal/api/v2/page/component/chart_field/indicator.rb +4 -5
  23. data/lib/ecoportal/api/v2/page/component/chart_field/multiseries.rb +3 -5
  24. data/lib/ecoportal/api/v2/page/component/chart_field/sankey.rb +1 -3
  25. data/lib/ecoportal/api/v2/page/component/chart_field/serie.rb +3 -4
  26. data/lib/ecoportal/api/v2/page/component/chart_field/series_config.rb +5 -7
  27. data/lib/ecoportal/api/v2/page/component/chart_fr_field.rb +7 -5
  28. data/lib/ecoportal/api/v2/page/component/checklist_field.rb +1 -1
  29. data/lib/ecoportal/api/v2/page/component/checklist_item.rb +7 -5
  30. data/lib/ecoportal/api/v2/page/component/date_field.rb +71 -4
  31. data/lib/ecoportal/api/v2/page/component/file.rb +14 -3
  32. data/lib/ecoportal/api/v2/page/component/files_field.rb +37 -1
  33. data/lib/ecoportal/api/v2/page/component/gauge_field.rb +2 -2
  34. data/lib/ecoportal/api/v2/page/component/gauge_stop.rb +5 -5
  35. data/lib/ecoportal/api/v2/page/component/geo_coordinates.rb +13 -0
  36. data/lib/ecoportal/api/v2/page/component/geo_field.rb +4 -1
  37. data/lib/ecoportal/api/v2/page/component/image.rb +2 -1
  38. data/lib/ecoportal/api/v2/page/component/images_field.rb +57 -1
  39. data/lib/ecoportal/api/v2/page/component/number_field.rb +1 -0
  40. data/lib/ecoportal/api/v2/page/component/people_field.rb +117 -7
  41. data/lib/ecoportal/api/v2/page/component/people_viewable_field.rb +14 -0
  42. data/lib/ecoportal/api/v2/page/component/plain_text_field.rb +34 -2
  43. data/lib/ecoportal/api/v2/page/component/reference_field.rb +32 -3
  44. data/lib/ecoportal/api/v2/page/component/selection_field.rb +65 -7
  45. data/lib/ecoportal/api/v2/page/component/selection_option.rb +16 -5
  46. data/lib/ecoportal/api/v2/page/component/signature_field.rb +3 -2
  47. data/lib/ecoportal/api/v2/page/component/tag_field.rb +31 -1
  48. data/lib/ecoportal/api/v2/page/components.rb +8 -3
  49. data/lib/ecoportal/api/v2/page/permission_flags.rb +67 -0
  50. data/lib/ecoportal/api/v2/page/permit.rb +15 -0
  51. data/lib/ecoportal/api/v2/page/section.rb +70 -9
  52. data/lib/ecoportal/api/v2/page/sections.rb +64 -6
  53. data/lib/ecoportal/api/v2/page/stage.rb +12 -4
  54. data/lib/ecoportal/api/v2/page/stages.rb +7 -7
  55. data/lib/ecoportal/api/v2/pages/page_stage.rb +3 -3
  56. data/lib/ecoportal/api/v2_version.rb +5 -0
  57. metadata +17 -10
  58. data/lib/ecoportal/api/common.rb +0 -18
  59. data/lib/ecoportal/api/v2/version.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 484fc9b5ba81835c60c8577578726c548dea573b997f028ac2dcc4b5d2a55c77
4
- data.tar.gz: 02d65b9252633b691ee87076566a429f3763e47dcbba28d04ce439dfbfa78609
3
+ metadata.gz: e8961e37170e3ffe06d26c17daa6672a15d595ff91c5e8fb38253549b166057a
4
+ data.tar.gz: c9b25eb42cfa9cb45cee3d830067eddc7d4191fa87f0fd4e35620e346ca27922
5
5
  SHA512:
6
- metadata.gz: 258ba907986e16b304f69ca903a7aba2b3daf3ea8d44b1af819e08bd63dfbce5ee2d904cc94bab14f84ecaa0f9d980f498378b53f8bbc35a237e62621f3ea7fd
7
- data.tar.gz: 7340b168c888be83c2c2798614b55bb7893bc1fb3819914f99e207805ef4b709f5f34a0b743e31f0345ce2f0d59ebdf3d3154c6a5e6c30b12e8910b2403486e5
6
+ metadata.gz: a68c58f62600b78745caff84d7e0dbda83e2f79cba8d41ca08ffbcf361060bd614fc6957f38878bb09d41dc6db1fcff3e307dd0072d21d960073683e6881fdbc
7
+ data.tar.gz: 998e1409fd0674bc409ab2ff1dcfb68f42a0dd37bca8eab040750cc8cc10ca2651fb98dc61adf3d44b0b0dbdc0bccfe384786cdd79ad1fd9ed96d12a00f3a4b4
data/CHANGELOG.md CHANGED
@@ -1,34 +1,99 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
- ## [0.8.6] - 2021-02-xx
4
+ ## [0.8.10] - 2021-08-xx
5
5
 
6
6
  ### Added
7
- - `Ecoportal::API::V2::Page::Component::SelectionField` added methods `#numeric!` `#text!`
7
+ - `Ecoportal::API::Common::Content::CollectionModel#[]` now supports position as well
8
+ - `Ecoportal::API::V2::Page::Component::FilesField#add_file`: support for adding files
9
+ - `Ecoportal::API::V2::Page::Component::PeopleField#viewable_fields`: support for managing `viewable_fields`
8
10
 
9
11
  ### Changed
12
+
10
13
  ### Fixed
14
+ - `Ecoportal::API::V2::Page::Component::FilesField`: was not requiring `File`
15
+ - `Ecoportal::API::V2::Page::Component::NumberField#value`: it was missing :/
16
+ - `Ecoportal::API::Common::Content::HashDiffPatch` did not support nested objects in Arrays, where the nested object wouldn't have a `patch_ver`. This **fix** allows for it
17
+ - `Ecoportal::API::Common::Content::DoubleModel.passforced` to define `methods` that should always be present. This allows to define `patch_ver` as a forced `key` in models that have it
18
+ - The enforcement (`self.class.enforce!`) happens on `initialize`
19
+ - `passenforced` subjacent model `forced_model_keys` is inheritable
20
+ - `Ecoportal::API::Common::Content::CollectionModel`:
21
+ - Method `upsert!` was not working fine the parameters `pos`, `before` and `after`
22
+ - Method `delete!` did not support position
23
+
24
+ ## [0.8.9] - 2021-08-16
11
25
 
26
+ ### Added
27
+ - `Ecoportal::API::Common::Content::ModelHelpers`
28
+ - Starting with `#same_string?`, this lib aims to offer a full set of helper comparers.
29
+ - `Ecoportal::API::V2::Page::Components#get_by_id`
30
+ - In future changes, method `[]` might be overriding the method of the parent class `CollectionModel`.
31
+ - `Ecoportal::API::V2::Page::PermissionFlags` to offer support to `can_permission`, `subscribed`, etc.
32
+ - `Ecoportal::API::V2::Page::Section#add_component` super handy helper to add fields to sections.
33
+ - `Ecoportal::API::V2::Page::Component::PeopleField#delete` to remove people using their ids.
34
+ - `Ecoportal::API::V2::Page::Component::GeoField` **added** suport for `#coordinates`
35
+ - With embedded object `Ecoportal::API::V2::Page::Component::GeoCoordinates`
36
+ - `#configure` method, to all the `Component` types (but `ChartField` s)
37
+ - This method allows to quickly set field properties.
38
+ - `Ecoportal::API::V2::Page::Sections#between`, aiming to obtain sections between two other ones
12
39
 
13
- ## [0.8.5] - 2021-02-22
40
+
41
+ ### Changed
42
+ - `Ecoportal::API::V2::Page::Section` real support for `split` sections (right vs left)
43
+ - This is actually a **FIX**
44
+ - `Ecoportal::API::V2::Page::Component::DateField#create_event`
45
+ - Now it switches to _allow future dates_
46
+ - `Ecoportal::API::V2::Page::Component::SelectionField#add_option`, the `name` parameter is now optional
47
+ - This change aims to make it consistent with the back-end.
48
+ - To its actual `Boolean` type some properties
49
+ - All `Component` types
50
+
51
+ ### Fixed
52
+ - `Ecoportal::API::Common::Content::HashDiffPatch` did not support `Hash` values without `id` or `patch_ver`
53
+ - This fix should allow them to flow to the update
54
+ - `Ecoportal::API::V2::Page::Component::ChartField` did not have `doc` for `mode` based configuration
55
+ - `Ecoportal::API::Common::Content::ArrayModel#insert_one`
56
+ - When `pos`, `before` & `after` were `nil` it was failing to attach the element.
57
+ - `Ecoportal::API::V2::Page::Sections#add` was not adding in the correct order
58
+ - `Ecoportal::API::V2::Page::Section.new_doc` was unnecessarily giving `9999` as default weight
59
+
60
+ ## [0.8.8] - 2021-08-03
14
61
 
15
62
  ### Added
63
+ - `Ecoportal::API::V2::Page::Component::ChartField::Benchmark`
64
+ - Support to convert selection options between numeric and text type.
65
+ - Add `Permit` object to `Page` and `Stage`
66
+
16
67
  ### Changed
17
- - upgrade
68
+ - Removed `Stages.ordered_stages`: detected bug with Enumerable iteration
69
+
70
+
71
+ ## [0.8.7] - 2021-05-25
72
+
73
+ ### Changed
74
+ - Upgrade `ecoportal-api` gem
75
+
18
76
  ### Fixed
77
+ - Requiring `api/common` from 2 different ends
78
+
79
+ ## [0.8.6] - 2021-02-23
80
+
81
+ ### Added
82
+ - `Ecoportal::API::V2::Page::Component::SelectionField` added methods `#numeric!` `#text!`
83
+
84
+ ## [0.8.5] - 2021-02-22
85
+
86
+ ### Changed
87
+ - upgrade
19
88
 
20
89
 
21
90
  ## [0.8.4] - 2021-02-22
22
91
 
23
- ### Added
24
92
  ### Changed
25
93
  - roll back `ecoportal-api` dependency
26
94
 
27
- ### Fixed
28
-
29
95
  ## [0.8.3] - 2021-02-22
30
96
 
31
- ### Added
32
97
  ### Changed
33
98
  - updated `rspec` for expected patch data on `delete` operation.
34
99
 
@@ -37,23 +102,16 @@ All notable changes to this project will be documented in this file.
37
102
 
38
103
  ## [0.8.2] - 2021-02-21
39
104
 
40
- ### Added
41
105
  ### Changed
42
106
  - some necessary changes for the new gem to be active
43
107
 
44
- ### Fixed
45
-
46
108
  ## [0.8.1] - 2021-02-21
47
109
 
48
- ### Added
49
110
  ### Changed
50
111
  - renamed parameters (backwards incompatible change):
51
112
  - `Ecoportal::API::V2::Pages::Stages` methods `#get` and `#update`
52
113
  - updated `Ecoportal::API::V2::Pages#` accordingly
53
114
 
54
- ### Fixed
55
-
56
-
57
115
  ## MOVED TO GEM `ecoportal-api-v2` ##
58
116
 
59
117
  ## [0.7.5] - 2021-02-21
@@ -147,42 +205,29 @@ All notable changes to this project will be documented in this file.
147
205
  - automatic key builder
148
206
  - helper: `Ecoportal::API::V2::v2key` method
149
207
  - `user_key:` and `org_key:` as constructor methods for `Ecoportal::API::V2`
150
- ### Changed
151
- ### Fixed
152
208
 
153
209
  ## [0.7.1] - 2020-10-07
154
210
 
155
- ### Added
156
211
  ### Changed
157
212
  - updated dependencies
158
- ### Fixed
159
-
160
213
 
161
214
  ## [0.7.0] - 2020-09-10
162
215
 
163
- ### Added
164
216
  ### Changed
165
217
  - updated dependencies
166
- ### Fixed
167
218
 
168
219
  ## [0.6.1] - 2020-07-11
169
220
 
170
221
  ### Added
171
222
  - `Ecoportal::API::Common::Content::DoubleModel#pretty_print`
172
- ### Changed
173
- ### Fixed
174
223
 
175
224
  ## [0.6.0] - 2020-07-11
176
225
 
177
- ### Added
178
226
  ### Changed
179
227
  - upgraded `ecoportal-api` gem
180
- ### Fixed
181
228
 
182
229
  ## [0.5.9] - 2020-07-02
183
230
 
184
231
  ### Added
185
232
  - helper `Ecoportal::API::Common::Content::StringDigest#indexable_label`: to see the part of a label that gets indexed
186
233
  - this `CHANGELOG.md` file
187
- ### Changed
188
- ### Fixed
data/bin/console CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "bundler/setup"
4
- require "ecoportal/api"
4
+ require "ecoportal/api-v2"
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
@@ -1,11 +1,11 @@
1
1
 
2
2
  lib = File.expand_path("../lib", __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "ecoportal/api/v2/version"
4
+ require "ecoportal/api/v2_version"
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "ecoportal-api-v2"
8
- spec.version = Ecoportal::API::V2::GEM_VERSION
8
+ spec.version = Ecoportal::API::GEM2_VERSION
9
9
  spec.authors = ["Oscar Segura"]
10
10
  spec.email = ["rien@ecoportal.co.nz", "oscar@ecoportal.co.nz", "bozydar@ecoportal.co.nz"]
11
11
 
@@ -22,12 +22,12 @@ Gem::Specification.new do |spec|
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ["lib"]
24
24
 
25
- spec.add_development_dependency "bundler", ">= 2.2.11", "< 2.3"
25
+ spec.add_development_dependency "bundler", ">= 2.2.17", "< 2.3"
26
26
  spec.add_development_dependency "rspec", ">= 3.10.0", "< 3.11"
27
27
  spec.add_development_dependency "rake", ">= 13.0.3", "< 13.1"
28
28
  spec.add_development_dependency "yard", ">= 0.9.26", "< 0.10"
29
29
  spec.add_development_dependency "redcarpet", ">= 3.5.1", "< 3.6"
30
- spec.add_development_dependency "pry" , "~> 0.14"
30
+ spec.add_development_dependency "pry" , ">= 0.14"
31
31
 
32
- spec.add_dependency 'ecoportal-api', '>= 0.8.1', '< 0.9'
32
+ spec.add_dependency 'ecoportal-api', '>= 0.8.3', '< 0.9'
33
33
  end
@@ -1,10 +1,10 @@
1
1
  require "ecoportal/api"
2
- require "ecoportal/api/v2/version"
2
+ require "ecoportal/api/v2_version"
3
3
 
4
4
  module Ecoportal
5
5
  module API
6
6
  end
7
7
  end
8
8
 
9
- require_relative "api/common"
9
+ require_relative "api/common.v2"
10
10
  require_relative "api/v2"
@@ -0,0 +1,8 @@
1
+ module Ecoportal
2
+ module API
3
+ module Common
4
+ end
5
+ end
6
+ end
7
+
8
+ require 'ecoportal/api/common/content'
@@ -9,6 +9,7 @@ end
9
9
 
10
10
  require 'ecoportal/api/common/content/class_helpers'
11
11
  require 'ecoportal/api/common/content/string_digest'
12
+ require 'ecoportal/api/common/content/model_helpers'
12
13
  require 'ecoportal/api/common/content/double_model'
13
14
  require 'ecoportal/api/common/content/array_model'
14
15
  require 'ecoportal/api/common/content/collection_model'
@@ -3,7 +3,8 @@ module Ecoportal
3
3
  module Common
4
4
  module Content
5
5
  # Class to handle a plain Array embedded in a Hashed model.
6
- # @note its purpose is to handle an Array of basic objects (i.e. `Date`, `String`, `Number`)
6
+ # @note
7
+ # - Its purpose is to handle an Array of basic objects (i.e. `Date`, `String`, `Number`)
7
8
  class ArrayModel < Content::DoubleModel
8
9
  class TypeMismatchedComparison < Exception
9
10
  def initialize (this: nil, that: msg = "Trying to compare objects with different behavior.")
@@ -222,15 +223,16 @@ module Ecoportal
222
223
  def insert_one(value, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
223
224
  i = index(value)
224
225
  return i if (i && uniq?)
225
-
226
226
  pos = case
227
227
  when used_param?(pos)
228
- pos
228
+ pos || length
229
229
  when used_param?(before)
230
- index(before)
230
+ before ? index(before) : length
231
231
  when used_param?(after)
232
- if i = index(after)
233
- i + 1
232
+ if after
233
+ if i = index(after) then i + 1 end
234
+ else
235
+ length
234
236
  end
235
237
  else
236
238
  length
@@ -2,6 +2,9 @@ module Ecoportal
2
2
  module API
3
3
  module Common
4
4
  module Content
5
+ # CollectionModel aims to deal with Arrays of actual objects.
6
+ # @note to be able to refer to the correct element of the Collection,
7
+ # it is required that those elements have a unique `key` that allows to identify them
5
8
  class CollectionModel < Content::DoubleModel
6
9
 
7
10
  class << self
@@ -140,17 +143,21 @@ module Ecoportal
140
143
  end
141
144
 
142
145
  # Get an element usign the `key`.
146
+ # @param value [String, Hash, Ecoportal::API::Common::Content::DoubleModel]
147
+ # @return [Object] the `items_class` element object
143
148
  def [](value)
144
149
  items_by_key[get_key(value)]
145
150
  end
146
151
 
152
+ # @return [Array<Object>] the `items_class` element object
147
153
  def values_at(*keys)
148
154
  keys.map {|key| self[key]}
149
155
  end
150
156
 
151
157
  # Tries to find the element `value`, if it exists, it updates it
152
- # Otherwise it pushes it to the end
153
- # @return the element
158
+ # Otherwise it pushes it to the end
159
+ # @value [Hash, Ecoportal::API::Common::Content::DoubleModel] the eleement to be added
160
+ # @return [Object] the `items_class` element object
154
161
  def upsert!(value, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
155
162
  unless value.is_a?(Hash) || value.is_a?(Content::DoubleModel)
156
163
  raise "'Content::DoubleModel' or 'Hash' doc required"
@@ -160,15 +167,20 @@ module Ecoportal
160
167
  if item = self[value]
161
168
  item.replace_doc(item_doc)
162
169
  else
163
- _doc_upsert(item_doc, pos: pos, before: before, after: after)
170
+ pos_idx = _doc_upsert(item_doc, pos: pos, before: before, after: after)
164
171
  end
165
172
  (item || self[item_doc]).tap do |item|
166
173
  yield(item) if block_given?
167
174
  end
168
175
  end
169
176
 
177
+ # Deletes `value` from this `CollectionModel` instance
178
+ # @param value [String, Hash, Ecoportal::API::Common::Content::DoubleModel]
179
+ # - When used as `String`, the `key` value (i.e. `id` value) is expected
180
+ # - When used as `Hash`, it should be the `doc` of the target element
181
+ # - When used as `DoubleModel`, it should be the specific object to be deleted
170
182
  def delete!(value)
171
- unless value.is_a?(Hash) || value.is_a?(Content::DoubleModel)
183
+ unless value.is_a?(Hash) || value.is_a?(Content::DoubleModel) || value.is_a?(String)
172
184
  raise "'Content::DoubleModel' or 'Hash' doc required"
173
185
  end
174
186
  if item = self[value]
@@ -186,7 +198,7 @@ module Ecoportal
186
198
  variables_remove!
187
199
  end
188
200
 
189
- # Gets the `key` of the object
201
+ # Gets the `key` of the object `value`
190
202
  def get_key(value)
191
203
  case value
192
204
  when Content::DoubleModel
@@ -195,6 +207,8 @@ module Ecoportal
195
207
  value[items_key]
196
208
  when String
197
209
  value
210
+ when Numeric
211
+ get_key(self.to_a[value])
198
212
  end
199
213
  end
200
214
 
@@ -235,27 +249,22 @@ module Ecoportal
235
249
  super
236
250
  end
237
251
 
252
+ # Deletes `value` from `doc` (here referred as `_doc_items`)
253
+ # @return [Object] the element deleted from `doc`
238
254
  def _doc_delete(value)
239
255
  if current_pos = _doc_key(value)
240
- _doc_items.delete_at(current_pos)
241
- on_change
256
+ _doc_items.delete_at(current_pos).tap do |deleted|
257
+ on_change
258
+ end
242
259
  end
243
260
  end
244
261
 
245
262
  def _doc_upsert(value, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
246
- current_pos = _doc_key(value)
247
- pos = case
248
- when used_param?(pos)
249
- pos
250
- when used_param?(before)
251
- _doc_key(before)
252
- when used_param?(after)
253
- #puts "to add after #{after.id}"
254
- if i = _doc_key(after)
255
- i + 1
256
- end
257
- end
263
+ current_pos = if elem = self[value]
264
+ _doc_key(elem)
265
+ end
258
266
 
267
+ pos = scope_position(pos: pos, before: before, after: after)
259
268
  pos ||= current_pos
260
269
 
261
270
  if current_pos && pos
@@ -264,7 +273,6 @@ module Ecoportal
264
273
  end
265
274
 
266
275
  pos = (pos && pos < _doc_items.length)? pos : _doc_items.length
267
-
268
276
  pos.tap do |i|
269
277
  _doc_items.insert(pos, value)
270
278
  on_change
@@ -272,6 +280,23 @@ module Ecoportal
272
280
 
273
281
  end
274
282
 
283
+ def scope_position(pos: NOT_USED, before: NOT_USED, after: NOT_USED)
284
+ case
285
+ when used_param?(pos)
286
+ if elem = self[pos]
287
+ _doc_key(elem) - 1
288
+ end
289
+ when used_param?(before)
290
+ if elem = self[before]
291
+ _doc_key(elem) - 1
292
+ end
293
+ when used_param?(after)
294
+ if elem = self[after]
295
+ _doc_key(elem)
296
+ end
297
+ end
298
+ end
299
+
275
300
  end
276
301
  end
277
302
  end
@@ -10,6 +10,7 @@ module Ecoportal
10
10
  class DoubleModel < Common::BaseModel
11
11
  NOT_USED = Common::Content::ClassHelpers::NOT_USED
12
12
  extend Common::Content::ClassHelpers
13
+ include Common::Content::ModelHelpers
13
14
 
14
15
  class UnlinkedModel < Exception
15
16
  def initialize (msg = "Something went wrong when linking the document.", from: nil, key: nil)
@@ -36,6 +37,8 @@ module Ecoportal
36
37
 
37
38
  # Same as `attr_reader` but links to a subjacent `Hash` model property
38
39
  # @note it does **not** create an _instance variable_
40
+ # @param methods [Array<Symbol>] the method that exposes the value
41
+ # as well as its `key` in the underlying `Hash` model.
39
42
  def pass_reader(*methods)
40
43
  methods.each do |method|
41
44
  method = method.to_s.freeze
@@ -51,6 +54,8 @@ module Ecoportal
51
54
 
52
55
  # Same as `attr_writer` but links to a subjacent `Hash` model property
53
56
  # @note it does **not** create an _instance variable_
57
+ # @param methods [Array<Symbol>] the method that exposes the value
58
+ # as well as its `key` in the underlying `Hash` model.
54
59
  def pass_writer(*methods)
55
60
  methods.each do |method|
56
61
  method = method.to_s.freeze
@@ -69,6 +74,8 @@ module Ecoportal
69
74
  # no chance you can avoid invinite loop for `get_key` without setting an
70
75
  # instance variable key at the moment of the object creation, when the
71
76
  # `doc` is firstly received
77
+ # @param method [Symbol] the method that exposes the value
78
+ # as well as its `key` in the underlying `Hash` model.
72
79
  def passkey(method)
73
80
  method = method.to_s.freeze
74
81
  var = instance_variable_name(method)
@@ -90,7 +97,33 @@ module Ecoportal
90
97
  self
91
98
  end
92
99
 
100
+ # These are methods that should always be present in patch update
101
+ # @note
102
+ # - `DoubleModel` can be used with objects that do not use `patch_ver`
103
+ # - This ensures that does that do, will get the correct patch update model
104
+ # @param method [Symbol] the method that exposes the value
105
+ # as well as its `key` in the underlying `Hash` model.
106
+ # @param default [Value] the default value that
107
+ # this `key` will be written in the model when it doesn't exixt
108
+ def passforced(method, default: , read_only: false)
109
+ model_forced_keys[method.to_s.freeze] = default
110
+ passthrough(method, read_only: read_only)
111
+ end
112
+
113
+ # Ensures `doc` has the `model_forced_keys`. If it doesn't, it adds those missing
114
+ # with the defined `default` values
115
+ def enforce!(doc)
116
+ return unless doc && doc.is_a?(Hash)
117
+ return if model_forced_keys.empty?
118
+ model_forced_keys.each do |key, default|
119
+ doc[key] = default unless doc.key?(key)
120
+ end
121
+ doc
122
+ end
123
+
93
124
  # Same as `attr_accessor` but links to a subjacent `Hash` model property
125
+ # @param methods [Array<Symbol>] the method that exposes the value
126
+ # as well as its `key` in the underlying `Hash` model.
94
127
  # @param read_only [Boolean] should it only define the reader?
95
128
  def passthrough(*methods, read_only: false)
96
129
  pass_reader *methods
@@ -100,6 +133,8 @@ module Ecoportal
100
133
 
101
134
  # To link as a `Time` date to a subjacent `Hash` model property
102
135
  # @see Ecoportal::API::Common::Content::DoubleModel#passthrough
136
+ # @param methods [Array<Symbol>] the method that exposes the value
137
+ # as well as its `key` in the underlying `Hash` model.
103
138
  # @param read_only [Boolean] should it only define the reader?
104
139
  def passdate(*methods, read_only: false)
105
140
  pass_reader(*methods) {|value| to_time(value)}
@@ -109,7 +144,21 @@ module Ecoportal
109
144
  self
110
145
  end
111
146
 
147
+ # To link as a `Boolean` to a subjacent `Hash` model property
148
+ # @param methods [Array<Symbol>] the method that exposes the value
149
+ # as well as its `key` in the underlying `Hash` model.
150
+ # @param read_only [Boolean] should it only define the reader?
151
+ def passboolean(*methods, read_only: false)
152
+ pass_reader(*methods) {|value| value}
153
+ unless read_only
154
+ pass_writer(*methods) {|value| !!value}
155
+ end
156
+ self
157
+ end
158
+
112
159
  # To link as plain `Array` to a subjacent `Hash` model property
160
+ # @param methods [Array<Symbol>] the method that exposes the value
161
+ # as well as its `key` in the underlying `Hash` model.
113
162
  # @param order_matters [Boolean] does the order matter
114
163
  # @param uniq [Boolean] should it contain unique elements
115
164
  def passarray(*methods, order_matters: true, uniq: true)
@@ -131,6 +180,10 @@ module Ecoportal
131
180
  end
132
181
 
133
182
  # Helper to embed one nested object under one property
183
+ # @param method [Symbol] the method that exposes the embeded object
184
+ # @param key [Symbol] the `key` that embeds it to the underlying `Hash` model
185
+ # @nullable [Boolean] to specify if this object can be `nil`
186
+ # @param klass [Class, String] the class of the embedded object
134
187
  def embeds_one(method, key: method, nullable: false, klass:)
135
188
  embed(method, key: key, nullable: nullable, multiple: false, klass: klass)
136
189
  end
@@ -138,7 +191,11 @@ module Ecoportal
138
191
  # @note
139
192
  # - if you have a dedicated `Enumerable` class to manage `many`, you should use `:enum_class`
140
193
  # - otherwise, just indicate the child class in `:klass` and it will auto generate the class
141
- # @param
194
+ # @param method [Symbol] the method that exposes the embeded object
195
+ # @param key [Symbol] the `key` that embeds it to the underlying `Hash` model
196
+ # @param order_matters [Boolean] to state if the order will matter
197
+ # @param klass [Class, String] the class of the individual elements it embeds
198
+ # @param enum_class [Class, String] the class of the collection that will hold the individual elements
142
199
  def embeds_many(method, key: method, order_matters: false, order_key: nil, klass: nil, enum_class: nil)
143
200
  if enum_class
144
201
  eclass = enum_class
@@ -151,7 +208,7 @@ module Ecoportal
151
208
  else
152
209
  raise "You should either specify the 'klass' of the elements or the 'enum_class'"
153
210
  end
154
- embed(method, key: key, multiple: true, klass: eclass)
211
+ embed(method, key: key, multiple: true, klass: eclass)
155
212
  end
156
213
 
157
214
  private
@@ -175,8 +232,15 @@ module Ecoportal
175
232
  end
176
233
  end
177
234
 
235
+ # The list of keys that will be forced in the model
236
+ def model_forced_keys
237
+ @forced_model_keys ||= {}
238
+ end
239
+
178
240
  end
179
241
 
242
+ inheritable_class_vars :forced_model_keys
243
+
180
244
  attr_reader :_parent, :_key
181
245
 
182
246
  def initialize(doc = {}, parent: self, key: nil)
@@ -184,6 +248,8 @@ module Ecoportal
184
248
  @_parent = parent || self
185
249
  @_key = key || self
186
250
 
251
+ self.class.enforce!(doc)
252
+
187
253
  if _parent == self
188
254
  @doc = doc
189
255
  @original_doc = JSON.parse(@doc.to_json)
@@ -200,11 +266,13 @@ module Ecoportal
200
266
  _parent.root
201
267
  end
202
268
 
269
+ # @return [String] the `value` of the `key` method (i.e. `id` value)
203
270
  def key
204
271
  raise "No key_method defined for #{self.class}" unless key_method?
205
272
  self.method(key_method).call
206
273
  end
207
274
 
275
+ # @param [String] the `value` of the `key` method (i.e. `id` value)
208
276
  def key=(value)
209
277
  raise "No key_method defined for #{self.class}" unless key_method?
210
278
  method = "#{key_method}="
@@ -223,16 +291,25 @@ module Ecoportal
223
291
  end
224
292
  end
225
293
 
294
+ # @return [nil, Hash] the underlying `Hash` model as is (carrying current changes)
226
295
  def doc
227
296
  raise UnlinkedModel.new(from: "#{self.class}#doc", key: _key) unless linked?
228
- return @doc if is_root?
229
- _parent.doc.dig(*[_doc_key(_key)].flatten)
297
+ if is_root?
298
+ @doc
299
+ else
300
+ _parent.doc.dig(*[_doc_key(_key)].flatten)
301
+ end
230
302
  end
231
303
 
304
+ # The `original_doc` holds the model as is now on server-side.
305
+ # @return [nil, Hash] the underlying `Hash` model as after last `consolidate!` changes
232
306
  def original_doc
233
307
  raise UnlinkedModel.new(from: "#{self.class}#original_doc", key: _key) unless linked?
234
- return @original_doc if is_root?
235
- _parent.original_doc.dig(*[_doc_key(_key)].flatten)
308
+ if is_root?
309
+ @original_doc
310
+ else
311
+ _parent.original_doc.dig(*[_doc_key(_key)].flatten)
312
+ end
236
313
  end
237
314
 
238
315
  def as_json
@@ -243,25 +320,37 @@ module Ecoportal
243
320
  doc.to_json(*args)
244
321
  end
245
322
 
323
+ # @return [nil, Hash] the patch `Hash` model including only the changes between
324
+ # `original_doc` and `doc`
246
325
  def as_update
247
326
  new_doc = as_json
248
327
  Common::Content::HashDiffPatch.patch_diff(new_doc, original_doc)
249
328
  end
250
329
 
330
+ # @return [Boolean] stating if there are changes
251
331
  def dirty?
252
332
  as_update != {}
253
333
  end
254
334
 
335
+ # It makes `original_doc` to be like `doc`
336
+ # @note
337
+ # - after executing it, there will be no pending changes
338
+ # - you should technically run this command, after a successful update request to the server
255
339
  def consolidate!
256
340
  replace_original_doc(JSON.parse(doc.to_json))
257
341
  end
258
342
 
343
+ # It makes `doc` to be like `original`
344
+ # @note
345
+ # - after executing it, changes in `doc` will be lost
346
+ # - you should technically run this command only if you want to remove certain changes
347
+ # @key [Symbol] the specific part of the model you want to `reset`
259
348
  def reset!(key = nil)
260
349
  if key
261
- keys = [].push(key).compact
350
+ keys = [key].flatten.compact
262
351
  odoc = original_doc.dig(*keys)
263
- dig_set(doc, key, odoc && JSON.parse(odoc.to_json))
264
-
352
+ odoc = odoc && JSON.parse(odoc.to_json)
353
+ dig_set(doc, keys, odoc)
265
354
  else
266
355
  replace_doc(JSON.parse(original_doc.to_json))
267
356
  end