lib/ecoportal/api/common/content/collection_model.rb in ecoportal-api-v2-1.1.7 vs lib/ecoportal/api/common/content/collection_model.rb in ecoportal-api-v2-1.1.8
- old
+ new
@@ -30,19 +30,22 @@
# This is an optimization to cut class lookups
# @param value [Hash] base `doc` (raw object) to create the object with
# @yield [doc] identifies the target `class` of the raw object
# @yieldparam doc [Hash]
# @yieldreturn [Klass] the target `class`
- # @return [Klass] the target `class`
+ # @return [Class, Proc, Hash] the target `class`
+ # - `Hash` tracks a symbol pending to be resovle from its referrer
+ # - `Class` an already resolve class
+ # - `Proc` a forker that pivots between multiple classes
def klass(value = NOT_USED, &block)
@klass = block if block_given?
- if @klass && !@class.is_a?(Proc)
- @klass = resolve_class(@klass, exception: false) unless @klass.is_a?(Class)
- @klass
- elsif @klass.is_a?(Proc) && used_param?(value)
+ if @klass.is_a?(Proc) && used_param?(value)
@klass.call(value)
+ elsif @klass && !@klass.is_a?(Proc) && !@klass.is_a?(Class)
+ @klass = resolve_class(@klass, exception: false)
+ @klass
else
@klass
end.tap do |result|
next unless result.is_a?(Class)
next unless result < Ecoportal::API::Common::Content::DoubleModel
@@ -56,11 +59,11 @@
end
# Optimization
def new_item_class_based?
return false if @new_item.is_a?(Proc)
- return false if @klass.is_a?(Proc)
+ return false if klass.is_a?(Proc)
return true if klass.is_a?(Class)
false
end
# Generates a new object of the target class
@@ -76,49 +79,45 @@
# @key [Symbol, String] the key value to access the item within collection
# Please observe that items in a CollectionModel are identified via their key attr.
# Meaning that there is actually no need to define this argument.
# @return [Klass] instance object of the target `klass`
def new_item(doc = NOT_USED, parent: nil, key: nil, read_only: false, &block)
- return (@new_item = block; nil) if block_given
+ if block_given?
+ @new_item = block
+ return
+ end
msg = "To define the 'new_item' callback (factory), you need to use a block"
raise msg unless used_param?(doc)
msg = "You should define either a 'klass' or a 'new_item' callback first"
raise msg unless klass?
return @new_item.call(doc, parent, key) if @new_item.is_a?(Proc)
- raise "Could not find a class for: #{doc}" unless target_class = klass(doc)
+ raise "Could not find a class for: #{doc}" unless (target_class = klass(doc))
return doc if doc.is_a?(target_class)
target_class.new(doc, parent: parent, key: key, read_only: read_only)
end
-
- def doc_class(name)
- dim_class = new_class(name, inherits: Common::Content::ArrayModel) do |klass|
- klass.order_matters = order_matters
- klass.uniq = uniq
- end
- end
end
include Enumerable
inheritable_class_vars :klass, :order_matters, :order_key, :items_key, :new_item
def initialize(ini_doc = [], parent: self, key: nil, read_only: false)
- unless self.class.klass?
- raise "Undefined base 'klass' or 'new_item' callback for #{self.class}"
- end
+ msg = "Undefined base 'klass' or 'new_item' callback for #{self.class}"
+ raise msg unless self.class.klass?
- ini_doc = case ini_doc
- when Array
- ini_doc
- when Enumerable
- ini_doc.to_a
- else
- []
- end
+ ini_doc =
+ case ini_doc
+ when Array
+ ini_doc
+ when Enumerable
+ ini_doc.to_a
+ else
+ []
+ end
super(ini_doc, parent: parent, key: key, read_only: read_only)
end
# @return [Class] the class of the elements of the Collection
@@ -135,11 +134,11 @@
# - The name of the method is after the paren't class method
# - This method would have been better called `_doc_pos` :)
def _doc_key(value)
#print "*(#{value.class})"
return super(value) unless value.is_a?(Hash) || value.is_a?(Content::DoubleModel)
- if id = get_key(value)
+ if (id = get_key(value))
#print "^"
_doc_items.index {|item| get_key(item) == id}.tap do |p|
#print "{{#{p}}}"
end
else
@@ -155,14 +154,22 @@
raise UnlinkedModel, "Can't find child: #{show_str}"
end
end
- def length; count; end
- def empty?; count == 0; end
- def present?; count > 0; end
+ def length
+ count
+ end
+ def empty?
+ count&.zero?
+ end
+
+ def present?
+ count&.positive?
+ end
+
def each(&block)
return to_enum(:each) unless block
_items.each(&block)
end
@@ -204,26 +211,26 @@
unless value.is_a?(Hash) || value.is_a?(Content::DoubleModel)
raise "'Content::DoubleModel' or 'Hash' doc required. Given #{value.class}"
end
item_doc = value.is_a?(Content::DoubleModel)? value.doc : value
item_doc = JSON.parse(item_doc.to_json)
- if item = self[value]
+ if (item = self[value])
item.replace_doc(item_doc)
else
_doc_upsert(item_doc, pos: pos, before: before, after: after).tap do |pos_idx|
_items.insert(pos_idx, new_item(item_doc))
@indexed = false
end
end
- (item || self[item_doc]).tap do |item|
- yield(item) if block_given?
+ (item || self[item_doc]).tap do |itm|
+ yield(itm) if block_given?
end
end
# Deletes all the elements of this `CollectionModel` instance
def clear
- self.to_a.each {|item| delete!(item)}
+ to_a.each {|item| delete!(item)}
end
# Deletes `value` from this `CollectionModel` instance
# @param value [String, Hash, Ecoportal::API::Common::Content::DoubleModel]
# - When used as `String`, the `key` value (i.e. `id` value) is expected
@@ -231,23 +238,30 @@
# - When used as `DoubleModel`, it should be the specific object to be deleted
def delete!(value)
unless value.is_a?(Hash) || value.is_a?(Content::DoubleModel) || value.is_a?(String)
raise "'Content::DoubleModel' or 'Hash' doc required"
end
- if item = self[value]
- _doc_delete(item.doc)
- @indexed = false
- _items.delete(item)
- end
+ return unless (item = self[value])
+ _doc_delete(item.doc)
+ @indexed = false
+ _items.delete(item)
end
protected
- def order_matters?; self.class.order_matters; end
- def uniq?; self.class.uniq; end
- def items_key; self.class.items_key; end
+ def order_matters?
+ self.class.order_matters
+ end
+ def uniq?
+ self.class.uniq
+ end
+
+ def items_key
+ self.class.items_key
+ end
+
def on_change
@indexed = false
#variables_remove!
end
@@ -259,11 +273,11 @@
when Hash
value[items_key]
when String
value
when Numeric
- get_key(self.to_a[value])
+ get_key(to_a[value])
end
end
def _doc_items
replace_doc([]) unless doc.is_a?(Array)
@@ -282,13 +296,13 @@
private
def new_item(value)
if self.class.new_item_class_based?
- self.class.klass.new(value, parent: self, read_only: self._read_only)
+ self.class.klass.new(value, parent: self, read_only: _read_only)
else
- self.class.new_item(value, parent: self, read_only: self._read_only)
+ self.class.new_item(value, parent: self, read_only: _read_only)
end
end
# Helper to remove tracked down instance variables
def variable_remove!(key)
@@ -307,51 +321,49 @@
end
# Deletes `value` from `doc` (here referred as `_doc_items`)
# @return [Object] the element deleted from `doc`
def _doc_delete(value)
- if current_pos = _doc_key(value)
- _doc_items.delete_at(current_pos)
- end
+ return unless (current_pos = _doc_key(value))
+
+ _doc_items.delete_at(current_pos)
end
def _doc_upsert(value, pos: NOT_USED, before: NOT_USED, after: NOT_USED)
- current_pos = if elem = self[value]
- _doc_key(elem)
- end
+ current_pos =
+ if (elem = self[value])
+ _doc_key(elem)
+ end
pos = scope_position(pos: pos, before: before, after: after)
pos ||= current_pos
if current_pos && pos
_doc_items.delete_at(current_pos)
- pos = (pos <= current_pos)? pos : pos - 1
+ pos = pos <= current_pos ? pos : pos - 1
end
- pos = (pos && pos < _doc_items.length)? pos : _doc_items.length
- pos.tap do |i|
+ pos = (pos && pos < _doc_items.length)? pos : _doc_items.length # rubocop:disable Style/TernaryParentheses
+ pos.tap do |_i|
_doc_items.insert(pos, value)
end
-
end
def scope_position(pos: NOT_USED, before: NOT_USED, after: NOT_USED)
- case
- when used_param?(pos)
- if elem = self[pos]
+ if used_param?(pos)
+ if (elem = self[pos])
_doc_key(elem) - 1
end
- when used_param?(before)
- if elem = self[before]
+ elsif used_param?(before)
+ if (elem = self[before])
_doc_key(elem) - 1
end
- when used_param?(after)
- if elem = self[after]
+ elsif used_param?(after)
+ if (elem = self[after])
_doc_key(elem)
end
end
end
-
end
end
end
end
end