ecoportal-api-v2 1.1.6 → 1.1.8

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.
@@ -6,12 +6,8 @@ module Ecoportal
6
6
  # which differs of `attr_*` ruby native class methods because `pass*`
7
7
  # completelly **links** the methods **to a subjacent `Hash` model**
8
8
  class DoubleModel < Common::BaseModel
9
- NOT_USED = Common::Content::ClassHelpers::NOT_USED
10
- extend Common::Content::ClassHelpers
11
- include Common::Content::ModelHelpers
12
-
13
9
  class UnlinkedModel < StandardError
14
- def initialize (msg = "Something went wrong when linking the document.", from: nil, key: nil)
10
+ def initialize(msg = "Something went wrong when linking the document.", from: nil, key: nil)
15
11
  msg += " From: #{from}." if from
16
12
  msg += " key: #{key}." if key
17
13
  super(msg)
@@ -21,6 +17,10 @@ module Ecoportal
21
17
  class NoKeyMethod < StandardError
22
18
  end
23
19
 
20
+ NOT_USED = Common::Content::ClassHelpers::NOT_USED
21
+ extend Common::Content::ClassHelpers
22
+ include Common::Content::ModelHelpers
23
+
24
24
  class << self
25
25
  attr_reader :key
26
26
 
@@ -38,6 +38,16 @@ module Ecoportal
38
38
  uid(length)
39
39
  end
40
40
 
41
+ def read_only?
42
+ @read_only = false if @read_only.nil?
43
+ @read_only
44
+ end
45
+
46
+ # Be able to define if a class should be read-only
47
+ def read_only!
48
+ @read_only = true
49
+ end
50
+
41
51
  # Same as `attr_reader` but links to a subjacent `Hash` model property
42
52
  # @note it does **not** create an _instance variable_
43
53
  # @param methods [Array<Symbol>] the method that exposes the value
@@ -108,7 +118,7 @@ module Ecoportal
108
118
  # as well as its `key` in the underlying `Hash` model.
109
119
  # @param default [Value] the default value that
110
120
  # this `key` will be written in the model when it doesn't exixt
111
- def passforced(method, default: , read_only: false)
121
+ def passforced(method, default:, read_only: false)
112
122
  model_forced_keys[method.to_s.freeze] = default
113
123
  passthrough(method, read_only: read_only)
114
124
  end
@@ -116,8 +126,9 @@ module Ecoportal
116
126
  # Ensures `doc` has the `model_forced_keys`. If it doesn't, it adds those missing
117
127
  # with the defined `default` values
118
128
  def enforce!(doc)
119
- return unless doc && doc.is_a?(Hash)
120
- return if model_forced_keys.empty?
129
+ return unless doc.is_a?(Hash)
130
+ return if model_forced_keys.empty?
131
+
121
132
  model_forced_keys.each do |key, default|
122
133
  doc[key] = default unless doc.key?(key)
123
134
  end
@@ -129,8 +140,8 @@ module Ecoportal
129
140
  # as well as its `key` in the underlying `Hash` model.
130
141
  # @param read_only [Boolean] should it only define the reader?
131
142
  def passthrough(*methods, read_only: false)
132
- pass_reader *methods
133
- pass_writer *methods unless read_only
143
+ pass_reader(*methods)
144
+ pass_writer(*methods) unless read_only
134
145
  self
135
146
  end
136
147
 
@@ -141,9 +152,7 @@ module Ecoportal
141
152
  # @param read_only [Boolean] should it only define the reader?
142
153
  def passdate(*methods, read_only: false)
143
154
  pass_reader(*methods) {|value| to_time(value)}
144
- unless read_only
145
- pass_writer(*methods) {|value| to_time(value)&.iso8601}
146
- end
155
+ pass_writer(*methods) {|value| to_time(value)&.iso8601} unless read_only
147
156
  self
148
157
  end
149
158
 
@@ -153,9 +162,7 @@ module Ecoportal
153
162
  # @param read_only [Boolean] should it only define the reader?
154
163
  def passboolean(*methods, read_only: false)
155
164
  pass_reader(*methods) {|value| value}
156
- unless read_only
157
- pass_writer(*methods) {|value| !!value}
158
- end
165
+ pass_writer(*methods) {|value| !!value} unless read_only
159
166
  self
160
167
  end
161
168
 
@@ -176,7 +183,7 @@ module Ecoportal
176
183
 
177
184
  define_method method do
178
185
  return instance_variable_get(var) if instance_variable_defined?(var)
179
- new_obj = dim_class.new(parent: self, key: method, read_only: self._read_only)
186
+ new_obj = dim_class.new(parent: self, key: method, read_only: read_only?)
180
187
  variable_set(var, new_obj)
181
188
  end
182
189
  end
@@ -187,7 +194,7 @@ module Ecoportal
187
194
  # @param key [Symbol] the `key` that embeds it to the underlying `Hash` model
188
195
  # @nullable [Boolean] to specify if this object can be `nil`
189
196
  # @param klass [Class, String] the class of the embedded object
190
- def embeds_one(method, key: method, nullable: false, klass:)
197
+ def embeds_one(method, klass:, key: method, nullable: false)
191
198
  embed(method, key: key, nullable: nullable, multiple: false, klass: klass)
192
199
  end
193
200
 
@@ -202,73 +209,83 @@ module Ecoportal
202
209
  # @param read_only [Boolean] whether or not should try to **work around** items `klass` missing a `key`
203
210
  # - If set to `true` this is meant only for read purposes (won't be able to successufully insert)
204
211
  def embeds_many(method, key: method, klass: nil, enum_class: nil,
205
- order_matters: false, order_key: nil, read_only: false)
212
+ order_matters: false, order_key: nil, read_only: read_only?)
206
213
  if enum_class
207
214
  eclass = enum_class
208
215
  elsif klass
209
216
  eclass = new_class("#{method}::#{klass}", inherits: Common::Content::CollectionModel) do |dim_class|
210
- dim_class.klass = klass
217
+ # NOTE: new_class may resolve the namespace of the class to an already existing class
218
+ dim_class.klass ||= klass
211
219
  dim_class.order_matters = order_matters
212
220
  dim_class.order_key = order_key
221
+ dim_class.read_only! if read_only
213
222
  end
214
223
  else
215
224
  raise "You should either specify the 'klass' of the elements or the 'enum_class'"
216
225
  end
217
- embed(method, key: key, multiple: true, klass: eclass, read_only: read_only) do |instance_with_called_method|
226
+
227
+ embed(
228
+ method, key: key,
229
+ multiple: true, klass: eclass,
230
+ read_only: read_only
231
+ ) do |instance_with_called_method|
218
232
  # keep reference to the original class to resolve the `klass` dependency
219
233
  # See stackoverflow: https://stackoverflow.com/a/73709529/4352306
220
234
  referrer_class = instance_with_called_method.class
221
- eclass.klass = {referrer_class => klass} if klass
235
+ eclass.klass = {referrer_class => klass} if klass
236
+ # This helps `resolve_class` to correctly resolve a symbol
237
+ # by using referrer_class as a base module to resolve it
222
238
  end
223
239
  end
224
240
 
225
241
  private
226
242
 
227
- def embed(method, key: method, nullable: false, multiple: false, klass:, read_only: false, &block)
243
+ def embed(
244
+ method, klass:, key: method,
245
+ nullable: false, multiple: false, read_only: read_only?,
246
+ &embed_block
247
+ )
228
248
  method = method.to_s.freeze
229
249
  var = instance_variable_name(method).freeze
230
- k = key.to_s.freeze
250
+ obj_k = key.to_s.freeze
231
251
 
232
252
  # retrieving method (getter)
233
253
  define_method(method) do
234
- yield(self) if block_given?
254
+ # set item klass as referrer to klass (to allow resolve symbol)
255
+ embed_block&.call(self)
235
256
  return instance_variable_get(var) if instance_variable_defined?(var)
236
- unless nullable
237
- doc[k] ||= multiple ? [] : {}
238
- end
239
- return variable_set(var, nil) unless doc[k]
240
257
 
241
- embedded_class = self.class.resolve_class(klass)
258
+ doc[obj_k] ||= (multiple ? [] : {}) unless nullable
259
+ return variable_set(var, nil) unless doc[obj_k]
242
260
 
243
- if multiple && read_only
244
- if doc[k].is_a?(Array) && embedded_class < Common::Content::CollectionModel
245
- if (item_class = embedded_class.klass) && !item_class.key?
246
- item_class.passkey :id
247
- doc[k].each_with_index do |item_doc, i|
248
- item_doc["id"] = "#{i}" unless item_doc.key?("id")
249
- end
250
- end
251
- end
252
- end
253
-
254
- embedded_class.new(doc[k], parent: self, key: k, read_only: self._read_only || read_only).tap do |obj|
255
- variable_set(var, obj)
261
+ embedded_class = self.class.resolve_class(klass)
262
+ setup_items_key(embedded_class, doc[obj_k]) if multiple && read_only
263
+
264
+ embedded_class.new(
265
+ doc[obj_k],
266
+ parent: self,
267
+ key: obj_k,
268
+ read_only: read_only? || read_only
269
+ ).tap do |collection|
270
+ variable_set(var, collection)
256
271
  end
257
272
  end
258
273
  end
259
274
 
260
275
  # The list of keys that will be forced in the model
261
276
  def model_forced_keys
262
- @forced_model_keys ||= {}
277
+ @model_forced_keys ||= {}
263
278
  end
264
279
  end
265
280
 
266
- inheritable_class_vars :forced_model_keys, :key
281
+ inheritable_class_vars :model_forced_keys, :key, :read_only
267
282
 
268
- # `_key` refers to the parent's property that links to this model
283
+ # `_key` refers to the `_parent`'s property that links to this model
284
+ # @note while `key` refers to the value of theproperty of this model
285
+ # that is key (identifies an item in a set of elements)
269
286
  attr_reader :_parent, :_key, :_read_only
270
287
 
271
- def initialize(doc = {}, parent: self, key: nil, read_only: false)
288
+ def initialize(doc = {}, parent: self, key: nil, read_only: self.class.read_only?) # rubocop:disable Lint/MissingSuper
272
289
  @_dim_vars = []
273
290
  @_parent = parent || self
274
291
  @_key = key || self
@@ -281,10 +298,16 @@ module Ecoportal
281
298
  @original_doc = JSON.parse(@doc.to_json)
282
299
  end
283
300
 
284
- if key_method? && doc && doc.is_a?(Hash)
285
- self.key = doc[key_method]
286
- #puts "\n$(#{self.key}<=>#{self.class})"
287
- end
301
+ return unless key_method? && doc && doc.is_a?(Hash)
302
+
303
+ self.key = doc[key_method]
304
+ #puts "\n$(#{self.key}<=>#{self.class})"
305
+ end
306
+
307
+ # @note `read_only` allows for some optimizations, such as storing values
308
+ # in instance variables, for optimization purposes
309
+ def read_only?
310
+ @_read_only
288
311
  end
289
312
 
290
313
  def root
@@ -294,15 +317,20 @@ module Ecoportal
294
317
 
295
318
  # @return [String] the `value` of the `key` method (i.e. `id` value)
296
319
  def key
297
- raise NoKeyMethod.new "No key_method defined for #{self.class}" unless key_method?
298
- self.method(key_method).call
320
+ raise NoKeyMethod, "No key_method defined for #{self.class}" unless key_method?
321
+
322
+ method(key_method).call
299
323
  end
300
324
 
301
325
  # @param [String] the `value` of the `key` method (i.e. `id` value)
302
326
  def key=(value)
303
- raise NoKeyMethod.new "No key_method defined for #{self.class}" unless key_method?
304
- method = "#{key_method}="
305
- self.method(method).call(value)
327
+ raise NoKeyMethod, "No key_method defined for #{self.class}" unless key_method?
328
+
329
+ method("#{key_method}=").call(value)
330
+ end
331
+
332
+ def resolved_doc_key
333
+ [_doc_key(_key)]
306
334
  end
307
335
 
308
336
  # Offers a method for child classes to transform the key,
@@ -320,25 +348,22 @@ module Ecoportal
320
348
  # @return [nil, Hash] the underlying `Hash` model as is (carrying current changes)
321
349
  def doc
322
350
  return @doc if doc_var?
351
+
323
352
  raise UnlinkedModel.new(from: "#{self.class}#doc", key: _key) unless linked?
324
- if is_root?
325
- @doc
326
- else
327
- # transform parent's `_key` to this object into a
328
- # path key that can rerieve from the parents's doc
329
- _parent.doc.dig(*[_doc_key(_key)].flatten)
330
- end
353
+ return @doc if is_root?
354
+
355
+ # transform parent's `_key` to this object into a
356
+ # path key that can rerieve from the parents's doc
357
+ _parent.doc.dig(*resolved_doc_key.flatten)
331
358
  end
332
359
 
333
360
  # The `original_doc` holds the model as is now on server-side.
334
361
  # @return [nil, Hash] the underlying `Hash` model as after last `consolidate!` changes
335
362
  def original_doc
336
363
  raise UnlinkedModel.new(from: "#{self.class}#original_doc", key: _key) unless linked?
337
- if is_root?
338
- @original_doc
339
- else
340
- _parent.original_doc.dig(*[_doc_key(_key)].flatten)
341
- end
364
+ return @original_doc if is_root?
365
+
366
+ _parent.original_doc.dig(*resolved_doc_key.flatten)
342
367
  end
343
368
 
344
369
  def as_json
@@ -359,7 +384,7 @@ module Ecoportal
359
384
  # @return [Boolean] stating if there are changes
360
385
  def dirty?
361
386
  au = as_update
362
- !((au == {}) || (au == nil))
387
+ !((au == {}) || au.nil?)
363
388
  end
364
389
 
365
390
  # It makes `original_doc` to be like `doc`
@@ -379,7 +404,7 @@ module Ecoportal
379
404
  if key
380
405
  keys = [key].flatten.compact
381
406
  odoc = original_doc.dig(*keys)
382
- odoc = odoc && JSON.parse(odoc.to_json)
407
+ odoc &&= JSON.parse(odoc.to_json)
383
408
  dig_set(doc, keys, odoc)
384
409
  else
385
410
  replace_doc(JSON.parse(original_doc.to_json))
@@ -393,13 +418,11 @@ module Ecoportal
393
418
 
394
419
  def replace_doc(new_doc)
395
420
  raise UnlinkedModel.new(from: "#{self.class}#replace_doc", key: _key) unless linked?
396
- if is_root?
397
- @doc = new_doc
398
- else
399
- dig_set(_parent.doc, [_doc_key(_key)].flatten, new_doc)
400
- _parent.variable_remove!(_key) unless new_doc
401
- #variables_remove!
402
- end
421
+ return (@doc = new_doc) if is_root?
422
+
423
+ dig_set(_parent.doc, resolved_doc_key.flatten, new_doc)
424
+ _parent.variable_remove!(_key) unless new_doc
425
+ #variables_remove!
403
426
  end
404
427
 
405
428
  protected
@@ -408,6 +431,9 @@ module Ecoportal
408
431
  !!defined?(@doc)
409
432
  end
410
433
 
434
+ # Both requisites
435
+ # @note that for optimization purposes, `@doc` var may be used when
436
+ # the object is `read_only?`
411
437
  def is_root?
412
438
  _parent == self && doc_var?
413
439
  end
@@ -418,11 +444,9 @@ module Ecoportal
418
444
 
419
445
  def replace_original_doc(new_doc)
420
446
  raise UnlinkedModel.new(from: "#{self.class}#replace_original_doc", key: _key) unless linked?
421
- if is_root?
422
- @original_doc = new_doc
423
- else
424
- dig_set(_parent.original_doc, [_doc_key(_key)].flatten, new_doc)
425
- end
447
+ return (@original_doc = new_doc) if is_root?
448
+
449
+ dig_set(_parent.original_doc, resolved_doc_key.flatten, new_doc)
426
450
  end
427
451
 
428
452
  # Helper to track down persistent variables
@@ -435,16 +459,16 @@ module Ecoportal
435
459
  # Helper to remove tracked down instance variables
436
460
  def variable_remove!(key)
437
461
  var = instance_variable_name(key)
438
- unless !@_dim_vars.include?(var)
439
- @_dim_vars.delete(var)
440
- remove_instance_variable(var)
441
- end
462
+ return unless @_dim_vars.include?(var)
463
+
464
+ @_dim_vars.delete(var)
465
+ remove_instance_variable(var)
442
466
  end
443
467
 
444
468
  # Removes all the persistent variables
445
469
  def variables_remove!
446
470
  #puts "going to remove vars: #{@_dim_vars} on #{self.class} (parent: #{identify_parent(self._parent)})"
447
- @_dim_vars.dup.map {|k| variable_remove!(k)}
471
+ @_dim_vars.dup.map {|var| variable_remove!(var)}
448
472
  end
449
473
 
450
474
  private
@@ -482,6 +506,20 @@ module Ecoportal
482
506
  self.class.key
483
507
  end
484
508
 
509
+ # It allows to work-around missing item_key
510
+ def setup_items_key(embedded_class, obj_doc)
511
+ # only if is going to be a collection
512
+ return unless obj_doc.is_a?(Array) && embedded_class < Common::Content::CollectionModel
513
+ return unless (item_class = embedded_class.klass)
514
+ # if already has key don't need to work around
515
+ return if item_class&.key
516
+
517
+ # apply work around
518
+ item_class.passkey :id
519
+ obj_doc.each_with_index do |item_doc, idx|
520
+ item_doc["id"] = idx.to_s unless item_doc.key?("id")
521
+ end
522
+ end
485
523
  end
486
524
  end
487
525
  end
@@ -5,4 +5,5 @@ module Ecoportal
5
5
  end
6
6
  end
7
7
 
8
+ require 'ecoportal/api/common/concerns'
8
9
  require 'ecoportal/api/common/content'
@@ -30,65 +30,64 @@ module Ecoportal
30
30
  class << self
31
31
  def new_doc(type: nil)
32
32
  {
33
- "id" => new_uuid
33
+ "id" => new_uuid
34
34
  }.tap do |base_doc|
35
35
  if type
36
36
  base_doc.merge!({"type" => type})
37
- if klass = get_class(base_doc)
37
+ if (klass = get_class(base_doc))
38
38
  base_doc.merge!(klass.new_doc || {})
39
39
  end
40
40
  end
41
41
  end
42
42
  end
43
43
 
44
- def get_class(doc)
45
- if doc.is_a?(Hash)
46
- case doc["type"]
47
- when "tag_field"
48
- tag_field_class
49
- when "geo"
50
- geo_field_class
51
- when "select"
52
- selection_field_class
53
- when "date"
54
- date_field_class
55
- when "number"
56
- number_field_class
57
- when "gauge"
58
- gauge_field_class
59
- when "plain_text"
60
- plain_text_field_class
61
- when "rich_text"
62
- rich_text_field_class
63
- when "people"
64
- people_field_class
65
- when "contractor_entities"
66
- contractor_entities_field_class
67
- when "checklist"
68
- checklist_field_class
69
- when "page_action","checklist_task"
70
- action_field_class
71
- when "actions_list"
72
- actions_field_class
73
- when "file"
74
- files_field_class
75
- when "image_gallery"
76
- images_field_class
77
- when "signature"
78
- signature_field_class
79
- when "cross_reference"
80
- reference_field_class
81
- when "law"
82
- law_field_class
83
- when "mailbox"
84
- mailbox_field_class
85
- when "chart"
86
- chart_field_class
87
- when "frequency_rate_chart"
88
- chart_fr_field_class
89
- else
90
- self
91
- end
44
+ def get_class(doc) # rubocop:disable Metrics/AbcSize
45
+ return nil unless doc.is_a?(Hash)
46
+ case doc["type"]
47
+ when "tag_field"
48
+ tag_field_class
49
+ when "geo"
50
+ geo_field_class
51
+ when "select"
52
+ selection_field_class
53
+ when "date"
54
+ date_field_class
55
+ when "number"
56
+ number_field_class
57
+ when "gauge"
58
+ gauge_field_class
59
+ when "plain_text"
60
+ plain_text_field_class
61
+ when "rich_text"
62
+ rich_text_field_class
63
+ when "people"
64
+ people_field_class
65
+ when "contractor_entities"
66
+ contractor_entities_field_class
67
+ when "checklist"
68
+ checklist_field_class
69
+ when "page_action", "checklist_task"
70
+ action_field_class
71
+ when "actions_list"
72
+ actions_field_class
73
+ when "file"
74
+ files_field_class
75
+ when "image_gallery"
76
+ images_field_class
77
+ when "signature"
78
+ signature_field_class
79
+ when "cross_reference"
80
+ reference_field_class
81
+ when "law"
82
+ law_field_class
83
+ when "mailbox"
84
+ mailbox_field_class
85
+ when "chart"
86
+ chart_field_class
87
+ when "frequency_rate_chart"
88
+ chart_fr_field_class
89
+ else
90
+ self
92
91
  end
93
92
  end
94
93
  end
@@ -103,7 +102,7 @@ module Ecoportal
103
102
  passarray :refs
104
103
 
105
104
  def ooze
106
- self._parent.ooze
105
+ _parent.ooze
107
106
  end
108
107
 
109
108
  def ref_backend
@@ -111,9 +110,9 @@ module Ecoportal
111
110
  end
112
111
 
113
112
  def ref(any_length: false)
114
- if digest = self.class.hash_label(label, any_length: any_length)
115
- [type, digest].join(".")
116
- end
113
+ digest = self.class.hash_label(label, any_length: any_length)
114
+ return unless digest
115
+ [type, digest].join(".")
117
116
  end
118
117
 
119
118
  # Looks up the section that this component belongs to.
@@ -159,7 +158,7 @@ module Ecoportal
159
158
 
160
159
  # @return [Boolean] `true` if the component is bound to any force, `false` otherwise
161
160
  def bindings?
162
- forces.count > 0
161
+ forces.count&.positive?
163
162
  end
164
163
 
165
164
  # If the field has bindings they are replaced by this new field
@@ -168,10 +167,10 @@ module Ecoportal
168
167
  if fld.section
169
168
  fld.move(section: self.section, before: self)
170
169
  else
171
- self.section.add(fld, before: self)
170
+ section.add(fld, before: self)
172
171
  end
173
172
  replace_bindings(fld)
174
- self.delete!
173
+ delete!
175
174
  end
176
175
 
177
176
  def replace_bindings(fld)
@@ -180,12 +179,12 @@ module Ecoportal
180
179
 
181
180
  def delete!
182
181
  bindings.each {|b| b.delete!}
183
- self.unattach!
184
- self._parent.delete!(self)
182
+ unattach!
183
+ _parent.delete!(self)
185
184
  end
186
185
 
187
186
  def move(section:, before: nil, after: nil, side: nil)
188
- self.unattach!
187
+ unattach!
189
188
  section.add_component(self, before: before, after: after, side: side)
190
189
  end
191
190
 
@@ -212,9 +211,7 @@ module Ecoportal
212
211
  when :hide_reports
213
212
  self.hidden_on_reports = true
214
213
  when Hash
215
- if cnf.key?(:global)
216
- self.global_binding = cnf[:global]
217
- end
214
+ self.global_binding = cnf[:global] if cnf.key?(:global)
218
215
  else
219
216
  unused.push(cnf)
220
217
  end
@@ -222,7 +219,6 @@ module Ecoportal
222
219
  raise "Unsupported configuration options '#{unused}' for #{self.class}" unless unused.empty?
223
220
  end
224
221
  end
225
-
226
222
  end
227
223
  end
228
224
  end
@@ -5,28 +5,28 @@ module Ecoportal
5
5
  class Components < Common::Content::CollectionModel
6
6
  class_resolver :component_class, "Ecoportal::API::V2::Page::Component"
7
7
 
8
- self.klass do |doc|
8
+ klass do |doc|
9
9
  component_class.get_class(doc).tap do |klass|
10
10
  klass.key = :id
11
11
  end
12
12
  end
13
13
 
14
- order_matters = true
14
+ #self.order_matters = true
15
15
 
16
16
  def ooze
17
- self._parent.ooze
17
+ _parent.ooze
18
18
  end
19
19
 
20
20
  # @return [Ecoportal::API::V2::Page::Component] the field with `id`
21
21
  def get_by_id(id)
22
- self.find do |comp|
22
+ find do |comp|
23
23
  comp.id == id
24
24
  end
25
25
  end
26
26
 
27
27
  # @return [Array<Ecoportal::API::V2::Page::Component>] the fields of that `type`
28
28
  def get_by_type(type)
29
- self.select do |comp|
29
+ select do |comp|
30
30
  comp.type.downcase == type.to_s.strip.downcase
31
31
  end
32
32
  end
@@ -53,19 +53,19 @@ module Ecoportal
53
53
  def add(doc: nil, label: doc && doc["label"], type: doc && doc["type"])
54
54
  fld_doc = doc ? JSON.parse(doc.to_json) : component_class.new_doc(type: type)
55
55
  upsert!(fld_doc) do |fld|
56
- fld.label = label if !doc
57
- yield(fld) if block_given?
56
+ fld.label = label unless doc
57
+ yield(fld) if block_given?
58
58
  end
59
59
  end
60
60
 
61
61
  # @return [Array<Ecoportal::API::V2::Page::Component>] **orphaned** fields (with no section).
62
62
  def unattached
63
- select {|comp| !comp.attached?}
63
+ reject(&:attached?)
64
64
  end
65
65
 
66
66
  # @return [Array<Ecoportal::API::V2::Page::Component>] fields belonging to more than one section.
67
67
  def multi_section
68
- select {|comp| comp.multi_section?}
68
+ select(&:multi_section?)
69
69
  end
70
70
  end
71
71
  end